summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AconfigFlags.bp33
-rw-r--r--Android.bp24
-rw-r--r--TEST_MAPPING17
-rw-r--r--api/ApiDocs.bp2
-rw-r--r--api/StubLibraries.bp1
-rw-r--r--api/api.go19
-rw-r--r--core/api/current.txt471
-rw-r--r--core/api/lint-baseline.txt86
-rw-r--r--core/api/module-lib-current.txt5
-rw-r--r--core/api/module-lib-lint-baseline.txt90
-rw-r--r--core/api/removed.txt16
-rw-r--r--core/api/system-current.txt52
-rw-r--r--core/api/system-lint-baseline.txt94
-rw-r--r--core/api/system-removed.txt11
-rw-r--r--core/java/Android.bp10
-rw-r--r--core/java/android/animation/ObjectAnimator.java19
-rw-r--r--core/java/android/app/Activity.java15
-rw-r--r--core/java/android/app/BackgroundInstallControlManager.java101
-rw-r--r--core/java/android/app/SystemServiceRegistry.java14
-rw-r--r--core/java/android/app/background_install_control_manager.aconfig9
-rw-r--r--core/java/android/app/wearable/OWNERS2
-rw-r--r--core/java/android/content/ContentProvider.java31
-rw-r--r--core/java/android/content/pm/IBackgroundInstallControlService.aidl11
-rw-r--r--core/java/android/content/pm/ProviderInfo.java9
-rw-r--r--core/java/android/content/pm/ServiceInfo.java8
-rw-r--r--core/java/android/content/pm/multiuser.aconfig9
-rw-r--r--core/java/android/credentials/GetCandidateCredentialsException.java11
-rw-r--r--core/java/android/net/vcn/VcnManager.java20
-rw-r--r--core/java/android/net/vcn/flags.aconfig7
-rw-r--r--core/java/android/nfc/TEST_MAPPING10
-rw-r--r--core/java/android/nfc/tech/OWNERS2
-rw-r--r--core/java/android/os/PerformanceHintManager.java2
-rw-r--r--core/java/android/os/WorkDuration.java30
-rw-r--r--core/java/android/service/dreams/DreamService.java13
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java3
-rw-r--r--core/java/android/service/notification/ZenModeConfig.java149
-rw-r--r--core/java/android/service/notification/ZenModeDiff.java10
-rw-r--r--core/java/android/service/notification/flags.aconfig8
-rw-r--r--core/java/android/service/wearable/OWNERS4
-rw-r--r--core/java/android/speech/RecognizerIntent.java29
-rw-r--r--core/java/android/speech/flags/speech_flags.aconfig8
-rw-r--r--core/java/android/view/Choreographer.java7
-rw-r--r--core/java/android/view/SurfaceControlInputReceiver.java43
-rw-r--r--core/java/android/view/WindowManager.java91
-rw-r--r--core/java/android/view/WindowManagerGlobal.java76
-rw-r--r--core/java/android/view/WindowManagerImpl.java23
-rw-r--r--core/java/android/view/flags/view_flags.aconfig7
-rw-r--r--core/java/android/window/SplashScreenView.java10
-rw-r--r--core/java/android/window/flags/window_surfaces.aconfig8
-rw-r--r--core/java/android/window/flags/windowing_frontend.aconfig2
-rw-r--r--core/java/com/android/internal/display/RefreshRateSettingsUtils.java3
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java5
-rw-r--r--core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java6
-rw-r--r--core/proto/OWNERS3
-rw-r--r--core/res/res/values-watch/config.xml3
-rw-r--r--core/res/res/values/attrs_manifest.xml10
-rw-r--r--core/res/res/values/public-staging.xml2
-rw-r--r--core/res/res/values/strings.xml4
-rw-r--r--core/tests/coretests/src/android/os/PerformanceHintManagerTest.java41
-rw-r--r--core/tests/coretests/src/android/os/WorkDurationUnitTest.java77
-rw-r--r--core/tests/nfctests/OWNERS1
-rw-r--r--libs/WindowManager/Shell/Android.bp71
-rw-r--r--libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml13
-rw-r--r--libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml3
-rw-r--r--libs/WindowManager/Shell/multivalentTests/AndroidTest.xml31
-rw-r--r--libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt481
l---------libs/WindowManager/Shell/multivalentTestsForDevice1
l---------libs/WindowManager/Shell/multivalentTestsForDeviceless1
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java9
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java250
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java602
-rw-r--r--libs/hwui/Properties.cpp7
-rw-r--r--libs/hwui/Properties.h10
-rw-r--r--libs/hwui/pipeline/skia/ATraceMemoryDump.cpp26
-rw-r--r--libs/hwui/pipeline/skia/ATraceMemoryDump.h3
-rw-r--r--libs/hwui/renderthread/CacheManager.cpp5
-rw-r--r--lint-baseline.xml12
-rw-r--r--media/java/android/media/MediaRouter2.java77
-rw-r--r--media/java/android/media/projection/IMediaProjectionManager.aidl44
-rw-r--r--media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java27
-rw-r--r--nfc-extras/Android.bp4
-rw-r--r--nfc/Android.bp43
-rw-r--r--nfc/api/current.txt454
-rw-r--r--nfc/api/lint-baseline.txt95
-rw-r--r--nfc/api/module-lib-current.txt9
-rw-r--r--nfc/api/module-lib-lint-baseline.txt93
-rw-r--r--nfc/api/removed.txt16
-rw-r--r--nfc/api/system-current.txt52
-rw-r--r--nfc/api/system-lint-baseline.txt105
-rw-r--r--nfc/api/system-removed.txt11
-rw-r--r--nfc/jarjar-rules.txt38
-rw-r--r--nfc/java/android/nfc/ApduList.aidl (renamed from core/java/android/nfc/ApduList.aidl)0
-rw-r--r--nfc/java/android/nfc/ApduList.java (renamed from core/java/android/nfc/ApduList.java)0
-rw-r--r--nfc/java/android/nfc/AvailableNfcAntenna.aidl (renamed from core/java/android/nfc/AvailableNfcAntenna.aidl)0
-rw-r--r--nfc/java/android/nfc/AvailableNfcAntenna.java (renamed from core/java/android/nfc/AvailableNfcAntenna.java)0
-rw-r--r--nfc/java/android/nfc/Constants.java (renamed from core/java/android/nfc/Constants.java)0
-rw-r--r--nfc/java/android/nfc/ErrorCodes.java (renamed from core/java/android/nfc/ErrorCodes.java)0
-rw-r--r--nfc/java/android/nfc/FormatException.java (renamed from core/java/android/nfc/FormatException.java)0
-rw-r--r--nfc/java/android/nfc/IAppCallback.aidl (renamed from core/java/android/nfc/IAppCallback.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcAdapter.aidl (renamed from core/java/android/nfc/INfcAdapter.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcAdapterExtras.aidl (renamed from core/java/android/nfc/INfcAdapterExtras.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcCardEmulation.aidl (renamed from core/java/android/nfc/INfcCardEmulation.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl (renamed from core/java/android/nfc/INfcControllerAlwaysOnListener.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcDta.aidl (renamed from core/java/android/nfc/INfcDta.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcFCardEmulation.aidl (renamed from core/java/android/nfc/INfcFCardEmulation.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcTag.aidl (renamed from core/java/android/nfc/INfcTag.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcUnlockHandler.aidl (renamed from core/java/android/nfc/INfcUnlockHandler.aidl)0
-rw-r--r--nfc/java/android/nfc/INfcWlcStateListener.aidl (renamed from core/java/android/nfc/INfcWlcStateListener.aidl)0
-rw-r--r--nfc/java/android/nfc/ITagRemovedCallback.aidl (renamed from core/java/android/nfc/ITagRemovedCallback.aidl)0
-rw-r--r--nfc/java/android/nfc/NdefMessage.aidl (renamed from core/java/android/nfc/NdefMessage.aidl)0
-rw-r--r--nfc/java/android/nfc/NdefMessage.java (renamed from core/java/android/nfc/NdefMessage.java)0
-rw-r--r--nfc/java/android/nfc/NdefRecord.aidl (renamed from core/java/android/nfc/NdefRecord.aidl)0
-rw-r--r--nfc/java/android/nfc/NdefRecord.java (renamed from core/java/android/nfc/NdefRecord.java)0
-rw-r--r--nfc/java/android/nfc/NfcActivityManager.java (renamed from core/java/android/nfc/NfcActivityManager.java)0
-rw-r--r--nfc/java/android/nfc/NfcAdapter.java (renamed from core/java/android/nfc/NfcAdapter.java)0
-rw-r--r--nfc/java/android/nfc/NfcAntennaInfo.aidl (renamed from core/java/android/nfc/NfcAntennaInfo.aidl)0
-rw-r--r--nfc/java/android/nfc/NfcAntennaInfo.java (renamed from core/java/android/nfc/NfcAntennaInfo.java)0
-rw-r--r--nfc/java/android/nfc/NfcControllerAlwaysOnListener.java (renamed from core/java/android/nfc/NfcControllerAlwaysOnListener.java)0
-rw-r--r--nfc/java/android/nfc/NfcEvent.java (renamed from core/java/android/nfc/NfcEvent.java)0
-rw-r--r--nfc/java/android/nfc/NfcFrameworkInitializer.java (renamed from core/java/android/nfc/NfcFrameworkInitializer.java)0
-rw-r--r--nfc/java/android/nfc/NfcManager.java (renamed from core/java/android/nfc/NfcManager.java)0
-rw-r--r--nfc/java/android/nfc/NfcServiceManager.java (renamed from core/java/android/nfc/NfcServiceManager.java)0
-rw-r--r--nfc/java/android/nfc/NfcWlcStateListener.java (renamed from core/java/android/nfc/NfcWlcStateListener.java)0
-rw-r--r--nfc/java/android/nfc/Tag.aidl (renamed from core/java/android/nfc/Tag.aidl)0
-rw-r--r--nfc/java/android/nfc/Tag.java (renamed from core/java/android/nfc/Tag.java)0
-rw-r--r--nfc/java/android/nfc/TagLostException.java (renamed from core/java/android/nfc/TagLostException.java)0
-rw-r--r--nfc/java/android/nfc/TechListParcel.aidl (renamed from core/java/android/nfc/TechListParcel.aidl)0
-rw-r--r--nfc/java/android/nfc/TechListParcel.java (renamed from core/java/android/nfc/TechListParcel.java)0
-rw-r--r--nfc/java/android/nfc/TransceiveResult.aidl (renamed from core/java/android/nfc/TransceiveResult.aidl)0
-rw-r--r--nfc/java/android/nfc/TransceiveResult.java (renamed from core/java/android/nfc/TransceiveResult.java)0
-rw-r--r--nfc/java/android/nfc/WlcLDeviceInfo.aidl (renamed from core/java/android/nfc/WlcLDeviceInfo.aidl)0
-rw-r--r--nfc/java/android/nfc/WlcLDeviceInfo.java (renamed from core/java/android/nfc/WlcLDeviceInfo.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/AidGroup.aidl (renamed from core/java/android/nfc/cardemulation/AidGroup.aidl)0
-rw-r--r--nfc/java/android/nfc/cardemulation/AidGroup.java (renamed from core/java/android/nfc/cardemulation/AidGroup.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/ApduServiceInfo.aidl (renamed from core/java/android/nfc/cardemulation/ApduServiceInfo.aidl)0
-rw-r--r--nfc/java/android/nfc/cardemulation/ApduServiceInfo.java (renamed from core/java/android/nfc/cardemulation/ApduServiceInfo.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/CardEmulation.java (renamed from core/java/android/nfc/cardemulation/CardEmulation.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/HostApduService.java (renamed from core/java/android/nfc/cardemulation/HostApduService.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/HostNfcFService.java (renamed from core/java/android/nfc/cardemulation/HostNfcFService.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java (renamed from core/java/android/nfc/cardemulation/NfcFCardEmulation.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/NfcFServiceInfo.aidl (renamed from core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl)0
-rw-r--r--nfc/java/android/nfc/cardemulation/NfcFServiceInfo.java (renamed from core/java/android/nfc/cardemulation/NfcFServiceInfo.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/OWNERS (renamed from core/java/android/nfc/OWNERS)0
-rw-r--r--nfc/java/android/nfc/cardemulation/OffHostApduService.java (renamed from core/java/android/nfc/cardemulation/OffHostApduService.java)0
-rw-r--r--nfc/java/android/nfc/cardemulation/Utils.java (renamed from core/java/android/nfc/cardemulation/Utils.java)0
-rw-r--r--nfc/java/android/nfc/dta/NfcDta.java (renamed from core/java/android/nfc/dta/NfcDta.java)0
-rw-r--r--nfc/java/android/nfc/dta/OWNERS (renamed from core/java/android/nfc/cardemulation/OWNERS)0
-rw-r--r--nfc/java/android/nfc/flags.aconfig (renamed from core/java/android/nfc/flags.aconfig)0
-rw-r--r--nfc/java/android/nfc/package.html (renamed from core/java/android/nfc/package.html)0
-rw-r--r--nfc/java/android/nfc/tech/BasicTagTechnology.java (renamed from core/java/android/nfc/tech/BasicTagTechnology.java)0
-rw-r--r--nfc/java/android/nfc/tech/IsoDep.java (renamed from core/java/android/nfc/tech/IsoDep.java)0
-rw-r--r--nfc/java/android/nfc/tech/MifareClassic.java (renamed from core/java/android/nfc/tech/MifareClassic.java)0
-rw-r--r--nfc/java/android/nfc/tech/MifareUltralight.java (renamed from core/java/android/nfc/tech/MifareUltralight.java)0
-rw-r--r--nfc/java/android/nfc/tech/Ndef.java (renamed from core/java/android/nfc/tech/Ndef.java)0
-rw-r--r--nfc/java/android/nfc/tech/NdefFormatable.java (renamed from core/java/android/nfc/tech/NdefFormatable.java)0
-rw-r--r--nfc/java/android/nfc/tech/NfcA.java (renamed from core/java/android/nfc/tech/NfcA.java)0
-rw-r--r--nfc/java/android/nfc/tech/NfcB.java (renamed from core/java/android/nfc/tech/NfcB.java)0
-rw-r--r--nfc/java/android/nfc/tech/NfcBarcode.java (renamed from core/java/android/nfc/tech/NfcBarcode.java)0
-rw-r--r--nfc/java/android/nfc/tech/NfcF.java (renamed from core/java/android/nfc/tech/NfcF.java)0
-rw-r--r--nfc/java/android/nfc/tech/NfcV.java (renamed from core/java/android/nfc/tech/NfcV.java)0
-rw-r--r--nfc/java/android/nfc/tech/OWNERS (renamed from core/java/android/nfc/dta/OWNERS)0
-rw-r--r--nfc/java/android/nfc/tech/TagTechnology.java (renamed from core/java/android/nfc/tech/TagTechnology.java)0
-rw-r--r--nfc/java/android/nfc/tech/package.html (renamed from core/java/android/nfc/tech/package.html)0
-rw-r--r--nfc/tests/Android.bp (renamed from core/tests/nfctests/Android.bp)1
-rw-r--r--nfc/tests/AndroidManifest.xml (renamed from core/tests/nfctests/AndroidManifest.xml)0
-rw-r--r--nfc/tests/AndroidTest.xml (renamed from core/tests/nfctests/AndroidTest.xml)0
-rw-r--r--nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java (renamed from core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java)0
-rw-r--r--nfc/tests/src/android/nfc/TechListParcelTest.java (renamed from core/tests/nfctests/src/android/nfc/TechListParcelTest.java)0
-rw-r--r--packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml25
-rw-r--r--packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml6
-rw-r--r--packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml37
-rw-r--r--packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml45
-rw-r--r--packages/CredentialManager/res/values/colors.xml21
-rw-r--r--packages/CredentialManager/res/values/dimens.xml10
-rw-r--r--packages/CredentialManager/res/values/styles.xml21
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt22
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt84
-rw-r--r--packages/SettingsLib/AdaptiveIcon/lint-baseline.xml18
-rw-r--r--packages/SettingsLib/Android.bp1
-rw-r--r--packages/SettingsLib/EmergencyNumber/lint-baseline.xml22
-rw-r--r--packages/SettingsLib/MainSwitchPreference/Android.bp3
-rw-r--r--packages/SettingsLib/MainSwitchPreference/lint-baseline.xml15
-rw-r--r--packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml52
-rw-r--r--packages/SettingsLib/SchedulesProvider/lint-baseline.xml2
-rw-r--r--packages/SettingsLib/SearchProvider/lint-baseline.xml110
-rw-r--r--packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt4
-rw-r--r--packages/SettingsLib/Tile/lint-baseline.xml48
-rw-r--r--packages/SettingsLib/Utils/lint-baseline.xml98
-rw-r--r--packages/SettingsLib/lint-baseline.xml204
-rw-r--r--packages/SettingsLib/search/Android.bp3
-rw-r--r--packages/SettingsLib/search/lint-baseline.xml22
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java14
-rw-r--r--packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java7
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt77
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt38
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt76
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt1
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java14
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java34
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt7
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt118
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt39
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt74
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt64
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt87
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt58
-rw-r--r--packages/SystemUI/res/layout/power_notification_controls_settings.xml30
-rw-r--r--packages/SystemUI/res/values/strings.xml32
-rw-r--r--packages/SystemUI/res/xml/other_settings.xml27
-rw-r--r--packages/SystemUI/shared/Android.bp12
-rw-r--r--packages/SystemUI/shared/lint-baseline.xml708
-rw-r--r--packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt10
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt29
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt15
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt167
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt35
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt23
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt39
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt16
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt66
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt24
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt60
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt32
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java39
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepository.kt (renamed from packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt)14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt26
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java93
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt28
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt23
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt37
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt25
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java10
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java6
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt22
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt9
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java8
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt98
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java6
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt15
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt (renamed from packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt)0
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt23
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt22
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt1
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt)0
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt (renamed from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt)4
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeUserSetupRepository.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt)8
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryKosmos.kt (renamed from packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt)2
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt22
-rw-r--r--packages/SystemUI/unfold/Android.bp3
-rw-r--r--packages/SystemUI/unfold/lint-baseline.xml3
-rw-r--r--services/Android.bp3
-rw-r--r--services/accessibility/Android.bp4
-rw-r--r--services/accessibility/lint-baseline.xml4
-rw-r--r--services/backup/lint-baseline.xml4
-rw-r--r--services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java18
-rw-r--r--services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java9
-rw-r--r--services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java2
-rw-r--r--services/companion/java/com/android/server/companion/transport/Transport.java2
-rw-r--r--services/companion/lint-baseline.xml4
-rw-r--r--services/core/Android.bp3
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java8
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java5
-rw-r--r--services/core/java/com/android/server/am/AnrHelper.java8
-rw-r--r--services/core/java/com/android/server/am/ContentProviderHelper.java18
-rw-r--r--services/core/java/com/android/server/audio/AudioService.java13
-rw-r--r--services/core/java/com/android/server/audio/SoundDoseHelper.java37
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig4
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java71
-rw-r--r--services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java48
-rw-r--r--services/core/java/com/android/server/locksettings/LockSettingsService.java30
-rw-r--r--services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java26
-rw-r--r--services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java33
-rw-r--r--services/core/java/com/android/server/notification/NotificationHistoryManager.java4
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java6
-rw-r--r--services/core/java/com/android/server/notification/ZenModeHelper.java146
-rw-r--r--services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java97
-rw-r--r--services/core/java/com/android/server/pm/BackgroundInstallControlService.java181
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java112
-rw-r--r--services/core/java/com/android/server/pm/ShortcutService.java11
-rwxr-xr-xservices/core/java/com/android/server/tv/TvInputHardwareManager.java67
-rw-r--r--services/core/java/com/android/server/vcn/VcnContext.java10
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java387
-rw-r--r--services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java269
-rw-r--r--services/core/java/com/android/server/wearable/OWNERS4
-rw-r--r--services/core/java/com/android/server/wearable/WearableSensingManagerService.java2
-rw-r--r--services/core/java/com/android/server/wm/BackNavigationController.java6
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java1
-rw-r--r--services/core/lint-baseline.xml4
-rw-r--r--services/credentials/java/com/android/server/credentials/ClearRequestSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/CreateRequestSession.java3
-rw-r--r--services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java21
-rw-r--r--services/credentials/java/com/android/server/credentials/GetRequestSession.java2
-rw-r--r--services/credentials/java/com/android/server/credentials/RequestSession.java13
-rw-r--r--services/lint-baseline.xml4
-rw-r--r--services/print/lint-baseline.xml4
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/Android.bp1
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml11
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java37
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml3
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java222
-rw-r--r--services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp8
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java12
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java154
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java95
-rw-r--r--services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java3
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java541
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java11
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java16
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java7
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java14
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java358
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java6
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java5
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java13
-rw-r--r--services/usb/lint-baseline.xml4
-rw-r--r--telephony/common/com/android/internal/telephony/TelephonyPermissions.java6
-rw-r--r--telephony/java/android/telephony/SubscriptionManager.java22
-rw-r--r--tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java12
-rw-r--r--tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java6
-rw-r--r--tests/SurfaceControlViewHostTest/AndroidManifest.xml10
-rw-r--r--tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java49
-rw-r--r--tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl3
-rw-r--r--tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java217
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java419
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java31
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java2
-rw-r--r--tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java2
369 files changed, 7160 insertions, 5176 deletions
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 9e308435c9bc..edd9d3af5926 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -71,6 +71,8 @@ aconfig_srcjars = [
":android.appwidget.flags-aconfig-java{.generated_srcjars}",
":android.webkit.flags-aconfig-java{.generated_srcjars}",
":android.provider.flags-aconfig-java{.generated_srcjars}",
+ ":android.chre.flags-aconfig-java{.generated_srcjars}",
+ ":android.speech.flags-aconfig-java{.generated_srcjars}",
]
filegroup {
@@ -196,7 +198,7 @@ java_aconfig_library {
aconfig_declarations {
name: "android.nfc.flags-aconfig",
package: "android.nfc",
- srcs: ["core/java/android/nfc/*.aconfig"],
+ srcs: ["nfc/java/android/nfc/*.aconfig"],
}
cc_aconfig_library {
@@ -214,7 +216,7 @@ cc_aconfig_library {
java_aconfig_library {
name: "android.nfc.flags-aconfig-java",
aconfig_declarations: "android.nfc.flags-aconfig",
- min_sdk_version: "VanillaIceCream",
+ min_sdk_version: "34",
apex_available: [
"//apex_available:platform",
"com.android.nfcservices",
@@ -480,8 +482,8 @@ java_aconfig_library {
apex_available: [
"//apex_available:platform",
"com.android.permission",
+ "com.android.nfcservices",
],
-
}
// SQLite
@@ -743,6 +745,11 @@ aconfig_declarations {
java_aconfig_library {
name: "android.service.chooser.flags-aconfig-java",
aconfig_declarations: "android.service.chooser.flags-aconfig",
+ min_sdk_version: "34",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.nfcservices",
+ ],
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
@@ -905,3 +912,23 @@ java_aconfig_library {
aconfig_declarations: "android.provider.flags-aconfig",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+
+// ContextHub
+java_aconfig_library {
+ name: "android.chre.flags-aconfig-java",
+ aconfig_declarations: "chre_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+// Speech
+aconfig_declarations {
+ name: "android.speech.flags-aconfig",
+ package: "android.speech.flags",
+ srcs: ["core/java/android/speech/flags/*.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.speech.flags-aconfig-java",
+ aconfig_declarations: "android.speech.flags-aconfig",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/Android.bp b/Android.bp
index f3b2ebb4fc17..a3e39018e147 100644
--- a/Android.bp
+++ b/Android.bp
@@ -175,9 +175,6 @@ java_library {
// and remove this line.
"//frameworks/base/tools/hoststubgen:__subpackages__",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// AIDL files under these paths are mixture of public and private ones.
@@ -270,9 +267,6 @@ java_library {
],
sdk_version: "core_platform",
installable: false,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// NOTE: This filegroup is exposed for vendor libraries to depend on and is referenced in
@@ -437,13 +431,9 @@ java_library {
name: "framework-non-updatable-unbundled-impl-libs",
static_libs: [
"framework-location.impl",
- "framework-nfc.impl",
],
sdk_version: "core_platform",
installable: false,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// Separated so framework-minus-apex-defaults can be used without the libs dependency
@@ -487,9 +477,6 @@ java_library {
],
compile_dex: false,
headers_only: true,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -534,7 +521,7 @@ java_library {
},
lint: {
enabled: false,
- baseline_filename: "lint-baseline.xml",
+
},
}
@@ -559,9 +546,6 @@ java_library {
],
sdk_version: "core_platform",
apex_available: ["//apex_available:platform"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -577,9 +561,6 @@ java_library {
"calendar-provider-compat-config",
"contacts-provider-platform-compat-config",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
platform_compat_config {
@@ -634,9 +615,6 @@ java_library {
"rappor",
],
dxflags: ["--core-library"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// utility classes statically linked into framework-wifi and dynamically linked
diff --git a/TEST_MAPPING b/TEST_MAPPING
index d59775f4060b..ecfd86c584e0 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -138,15 +138,14 @@
}
],
"postsubmit-ravenwood": [
- // TODO(ravenwood) promote it to presubmit
- // TODO: Enable it once the infra knows how to run it.
-// {
-// "name": "CtsUtilTestCasesRavenwood",
-// "file_patterns": [
-// "*Ravenwood*",
-// "*ravenwood*"
-// ]
-// }
+ {
+ "name": "CtsUtilTestCasesRavenwood",
+ "host": true,
+ "file_patterns": [
+ "*Ravenwood*",
+ "*ravenwood*"
+ ]
+ }
],
"postsubmit-managedprofile-stress": [
{
diff --git a/api/ApiDocs.bp b/api/ApiDocs.bp
index bcfb68ffd04d..7ae3224e7500 100644
--- a/api/ApiDocs.bp
+++ b/api/ApiDocs.bp
@@ -63,6 +63,7 @@ stubs_defaults {
":framework-graphics-srcs",
":framework-mediaprovider-sources",
":framework-nearby-sources",
+ ":framework-nfc-updatable-sources",
":framework-ondevicepersonalization-sources",
":framework-permission-sources",
":framework-permission-s-sources",
@@ -183,6 +184,7 @@ doc_defaults {
"-federationapi AndroidX $(location :current-androidx-api)",
// doclava contains checks for a few issues that are have been migrated to metalava.
// disable them in doclava, to avoid mistriggering or double triggering.
+ "-hide 101", // TODO: turn Lint 101 back into an error again
"-hide 111", // HIDDEN_SUPERCLASS
"-hide 113", // DEPRECATION_MISMATCH
"-hide 125", // REQUIRES_PERMISSION
diff --git a/api/StubLibraries.bp b/api/StubLibraries.bp
index ef1fa6097056..74344cd4b5a5 100644
--- a/api/StubLibraries.bp
+++ b/api/StubLibraries.bp
@@ -635,7 +635,6 @@ java_defaults {
api_contributions: [
"framework-virtualization.stubs.source.test.api.contribution",
"framework-location.stubs.source.test.api.contribution",
- "framework-nfc.stubs.source.test.api.contribution",
],
}
diff --git a/api/api.go b/api/api.go
index 2668999c572e..b975c55c5af9 100644
--- a/api/api.go
+++ b/api/api.go
@@ -31,7 +31,6 @@ const conscrypt = "conscrypt.module.public.api"
const i18n = "i18n.module.public.api"
const virtualization = "framework-virtualization"
const location = "framework-location"
-const nfc = "framework-nfc"
var core_libraries_modules = []string{art, conscrypt, i18n}
@@ -43,7 +42,7 @@ var core_libraries_modules = []string{art, conscrypt, i18n}
// APIs.
// In addition, the modules in this list are allowed to contribute to test APIs
// stubs.
-var non_updatable_modules = []string{virtualization, location, nfc}
+var non_updatable_modules = []string{virtualization, location}
// The intention behind this soong plugin is to generate a number of "merged"
// API-related modules that would otherwise require a large amount of very
@@ -64,6 +63,7 @@ type CombinedApisProperties struct {
type CombinedApis struct {
android.ModuleBase
+ android.DefaultableModuleBase
properties CombinedApisProperties
}
@@ -74,6 +74,7 @@ func init() {
func registerBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("combined_apis", combinedApisModuleFactory)
+ ctx.RegisterModuleType("combined_apis_defaults", CombinedApisModuleDefaultsFactory)
}
var PrepareForCombinedApisTest = android.FixtureRegisterWithContext(registerBuildComponents)
@@ -409,6 +410,7 @@ func combinedApisModuleFactory() android.Module {
module := &CombinedApis{}
module.AddProperties(&module.properties)
android.InitAndroidModule(module)
+ android.InitDefaultableModule(module)
android.AddLoadHook(module, func(ctx android.LoadHookContext) { module.createInternalModules(ctx) })
return module
}
@@ -445,3 +447,16 @@ func remove(s []string, v string) []string {
}
return s2
}
+
+// Defaults
+type CombinedApisModuleDefaults struct {
+ android.ModuleBase
+ android.DefaultsModuleBase
+}
+
+func CombinedApisModuleDefaultsFactory() android.Module {
+ module := &CombinedApisModuleDefaults{}
+ module.AddProperties(&CombinedApisProperties{})
+ android.InitDefaultsModule(module)
+ return module
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index 7c34812464c0..902f0fc17a38 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1602,6 +1602,7 @@ package android {
field public static final int switchTextOff = 16843628; // 0x101036c
field public static final int switchTextOn = 16843627; // 0x101036b
field public static final int syncable = 16842777; // 0x1010019
+ field @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") public static final int systemUserOnly;
field public static final int tabStripEnabled = 16843453; // 0x10102bd
field public static final int tabStripLeft = 16843451; // 0x10102bb
field public static final int tabStripRight = 16843452; // 0x10102bc
@@ -4371,7 +4372,7 @@ package android.app {
method public final android.media.session.MediaController getMediaController();
method @NonNull public android.view.MenuInflater getMenuInflater();
method @NonNull public android.window.OnBackInvokedDispatcher getOnBackInvokedDispatcher();
- method @Deprecated public final android.app.Activity getParent();
+ method public final android.app.Activity getParent();
method @Nullable public android.content.Intent getParentActivityIntent();
method public android.content.SharedPreferences getPreferences(int);
method @Nullable public android.net.Uri getReferrer();
@@ -4389,7 +4390,7 @@ package android.app {
method public void invalidateOptionsMenu();
method public boolean isActivityTransitionRunning();
method public boolean isChangingConfigurations();
- method @Deprecated public final boolean isChild();
+ method public final boolean isChild();
method public boolean isDestroyed();
method public boolean isFinishing();
method public boolean isImmersive();
@@ -28748,460 +28749,6 @@ package android.net.vcn {
}
-package android.nfc {
-
- public final class AvailableNfcAntenna implements android.os.Parcelable {
- ctor public AvailableNfcAntenna(int, int);
- method public int describeContents();
- method public int getLocationX();
- method public int getLocationY();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.AvailableNfcAntenna> CREATOR;
- }
-
- public class FormatException extends java.lang.Exception {
- ctor public FormatException();
- ctor public FormatException(String);
- ctor public FormatException(String, Throwable);
- }
-
- public final class NdefMessage implements android.os.Parcelable {
- ctor public NdefMessage(byte[]) throws android.nfc.FormatException;
- ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...);
- ctor public NdefMessage(android.nfc.NdefRecord[]);
- method public int describeContents();
- method public int getByteArrayLength();
- method public android.nfc.NdefRecord[] getRecords();
- method public byte[] toByteArray();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefMessage> CREATOR;
- }
-
- public final class NdefRecord implements android.os.Parcelable {
- ctor public NdefRecord(short, byte[], byte[], byte[]);
- ctor @Deprecated public NdefRecord(byte[]) throws android.nfc.FormatException;
- method public static android.nfc.NdefRecord createApplicationRecord(String);
- method public static android.nfc.NdefRecord createExternal(String, String, byte[]);
- method public static android.nfc.NdefRecord createMime(String, byte[]);
- method public static android.nfc.NdefRecord createTextRecord(String, String);
- method public static android.nfc.NdefRecord createUri(android.net.Uri);
- method public static android.nfc.NdefRecord createUri(String);
- method public int describeContents();
- method public byte[] getId();
- method public byte[] getPayload();
- method public short getTnf();
- method public byte[] getType();
- method @Deprecated public byte[] toByteArray();
- method public String toMimeType();
- method public android.net.Uri toUri();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefRecord> CREATOR;
- field public static final byte[] RTD_ALTERNATIVE_CARRIER;
- field public static final byte[] RTD_HANDOVER_CARRIER;
- field public static final byte[] RTD_HANDOVER_REQUEST;
- field public static final byte[] RTD_HANDOVER_SELECT;
- field public static final byte[] RTD_SMART_POSTER;
- field public static final byte[] RTD_TEXT;
- field public static final byte[] RTD_URI;
- field public static final short TNF_ABSOLUTE_URI = 3; // 0x3
- field public static final short TNF_EMPTY = 0; // 0x0
- field public static final short TNF_EXTERNAL_TYPE = 4; // 0x4
- field public static final short TNF_MIME_MEDIA = 2; // 0x2
- field public static final short TNF_UNCHANGED = 6; // 0x6
- field public static final short TNF_UNKNOWN = 5; // 0x5
- field public static final short TNF_WELL_KNOWN = 1; // 0x1
- }
-
- public final class NfcAdapter {
- method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean allowTransaction();
- method public void disableForegroundDispatch(android.app.Activity);
- method public void disableReaderMode(android.app.Activity);
- method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean disallowTransaction();
- method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
- method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
- method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
- method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
- method @FlaggedApi("android.nfc.enable_nfc_charging") @Nullable public android.nfc.WlcLDeviceInfo getWlcLDeviceInfo();
- method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
- method public boolean isEnabled();
- method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean isObserveModeSupported();
- method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled();
- method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
- method public boolean isSecureNfcEnabled();
- method public boolean isSecureNfcSupported();
- method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled();
- method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void resetDiscoveryTechnology(@NonNull android.app.Activity);
- method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void setDiscoveryTechnology(@NonNull android.app.Activity, int, int);
- field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
- field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
- field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
- field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
- field public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
- field @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) public static final String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED";
- field public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
- field public static final String EXTRA_AID = "android.nfc.extra.AID";
- field public static final String EXTRA_DATA = "android.nfc.extra.DATA";
- field public static final String EXTRA_ID = "android.nfc.extra.ID";
- field public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
- field public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON";
- field public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
- field public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
- field public static final String EXTRA_TAG = "android.nfc.extra.TAG";
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_DISABLE = 0; // 0x0
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_KEEP = -1; // 0xffffffff
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_A = 1; // 0x1
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_B = 2; // 0x2
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_F = 4; // 0x4
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_DISABLE = 0; // 0x0
- field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_KEEP = -1; // 0xffffffff
- field public static final int FLAG_READER_NFC_A = 1; // 0x1
- field public static final int FLAG_READER_NFC_B = 2; // 0x2
- field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
- field public static final int FLAG_READER_NFC_F = 4; // 0x4
- field public static final int FLAG_READER_NFC_V = 8; // 0x8
- field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
- field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80
- field public static final int PREFERRED_PAYMENT_CHANGED = 2; // 0x2
- field public static final int PREFERRED_PAYMENT_LOADED = 1; // 0x1
- field public static final int PREFERRED_PAYMENT_UPDATED = 3; // 0x3
- field public static final int STATE_OFF = 1; // 0x1
- field public static final int STATE_ON = 3; // 0x3
- field public static final int STATE_TURNING_OFF = 4; // 0x4
- field public static final int STATE_TURNING_ON = 2; // 0x2
- }
-
- @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback {
- method @Deprecated public android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
- }
-
- @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback {
- method @Deprecated public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
- }
-
- @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback {
- method @Deprecated public void onNdefPushComplete(android.nfc.NfcEvent);
- }
-
- public static interface NfcAdapter.OnTagRemovedListener {
- method public void onTagRemoved();
- }
-
- public static interface NfcAdapter.ReaderCallback {
- method public void onTagDiscovered(android.nfc.Tag);
- }
-
- public final class NfcAntennaInfo implements android.os.Parcelable {
- ctor public NfcAntennaInfo(int, int, boolean, @NonNull java.util.List<android.nfc.AvailableNfcAntenna>);
- method public int describeContents();
- method @NonNull public java.util.List<android.nfc.AvailableNfcAntenna> getAvailableNfcAntennas();
- method public int getDeviceHeight();
- method public int getDeviceWidth();
- method public boolean isDeviceFoldable();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NfcAntennaInfo> CREATOR;
- }
-
- public final class NfcEvent {
- field public final android.nfc.NfcAdapter nfcAdapter;
- field public final int peerLlcpMajorVersion;
- field public final int peerLlcpMinorVersion;
- }
-
- public final class NfcManager {
- method public android.nfc.NfcAdapter getDefaultAdapter();
- }
-
- public final class Tag implements android.os.Parcelable {
- method public int describeContents();
- method public byte[] getId();
- method public String[] getTechList();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.Tag> CREATOR;
- }
-
- public class TagLostException extends java.io.IOException {
- ctor public TagLostException();
- ctor public TagLostException(String);
- }
-
- @FlaggedApi("android.nfc.enable_nfc_charging") public final class WlcLDeviceInfo implements android.os.Parcelable {
- ctor public WlcLDeviceInfo(double, double, double, int);
- method public int describeContents();
- method public double getBatteryLevel();
- method public double getProductId();
- method public int getState();
- method public double getTemperature();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field public static final int CONNECTED_CHARGING = 2; // 0x2
- field public static final int CONNECTED_DISCHARGING = 3; // 0x3
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.WlcLDeviceInfo> CREATOR;
- field public static final int DISCONNECTED = 1; // 0x1
- }
-
-}
-
-package android.nfc.cardemulation {
-
- public final class CardEmulation {
- method public boolean categoryAllowsForegroundPreference(String);
- method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService();
- method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String);
- method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService();
- method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
- method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService();
- method public int getSelectionModeForCategory(String);
- method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
- method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
- method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
- method public boolean removeAidsForService(android.content.ComponentName, String);
- method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
- method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
- method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setServiceObserveModeDefault(@NonNull android.content.ComponentName, boolean);
- method public boolean supportsAidPrefixRegistration();
- method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
- method public boolean unsetPreferredService(android.app.Activity);
- field @Deprecated public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
- field public static final String CATEGORY_OTHER = "other";
- field public static final String CATEGORY_PAYMENT = "payment";
- field public static final String EXTRA_CATEGORY = "category";
- field public static final String EXTRA_SERVICE_COMPONENT = "component";
- field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
- field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
- field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
- }
-
- public abstract class HostApduService extends android.app.Service {
- ctor public HostApduService();
- method public final void notifyUnhandled();
- method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onDeactivated(int);
- method public abstract byte[] processCommandApdu(byte[], android.os.Bundle);
- method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.os.Bundle>);
- method public final void sendResponseApdu(byte[]);
- field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
- field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_DATA_KEY = "android.nfc.cardemulation.DATA";
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_GAIN_KEY = "android.nfc.cardemulation.GAIN";
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TIMESTAMP_KEY = "android.nfc.cardemulation.TIMESTAMP";
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A'
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B'
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F'
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TYPE_KEY = "android.nfc.cardemulation.TYPE";
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X'
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O'
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U'
- field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
- field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
- }
-
- public abstract class HostNfcFService extends android.app.Service {
- ctor public HostNfcFService();
- method public final android.os.IBinder onBind(android.content.Intent);
- method public abstract void onDeactivated(int);
- method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
- method public final void sendResponsePacket(byte[]);
- field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
- field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
- field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
- }
-
- public final class NfcFCardEmulation {
- method public boolean disableService(android.app.Activity) throws java.lang.RuntimeException;
- method public boolean enableService(android.app.Activity, android.content.ComponentName) throws java.lang.RuntimeException;
- method public static android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
- method public String getNfcid2ForService(android.content.ComponentName) throws java.lang.RuntimeException;
- method public String getSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
- method public boolean registerSystemCodeForService(android.content.ComponentName, String) throws java.lang.RuntimeException;
- method public boolean setNfcid2ForService(android.content.ComponentName, String) throws java.lang.RuntimeException;
- method public boolean unregisterSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
- }
-
- public abstract class OffHostApduService extends android.app.Service {
- ctor public OffHostApduService();
- field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
- field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service";
- }
-
-}
-
-package android.nfc.tech {
-
- public final class IsoDep implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.IsoDep get(android.nfc.Tag);
- method public byte[] getHiLayerResponse();
- method public byte[] getHistoricalBytes();
- method public int getMaxTransceiveLength();
- method public android.nfc.Tag getTag();
- method public int getTimeout();
- method public boolean isConnected();
- method public boolean isExtendedLengthApduSupported();
- method public void setTimeout(int);
- method public byte[] transceive(byte[]) throws java.io.IOException;
- }
-
- public final class MifareClassic implements android.nfc.tech.TagTechnology {
- method public boolean authenticateSectorWithKeyA(int, byte[]) throws java.io.IOException;
- method public boolean authenticateSectorWithKeyB(int, byte[]) throws java.io.IOException;
- method public int blockToSector(int);
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public void decrement(int, int) throws java.io.IOException;
- method public static android.nfc.tech.MifareClassic get(android.nfc.Tag);
- method public int getBlockCount();
- method public int getBlockCountInSector(int);
- method public int getMaxTransceiveLength();
- method public int getSectorCount();
- method public int getSize();
- method public android.nfc.Tag getTag();
- method public int getTimeout();
- method public int getType();
- method public void increment(int, int) throws java.io.IOException;
- method public boolean isConnected();
- method public byte[] readBlock(int) throws java.io.IOException;
- method public void restore(int) throws java.io.IOException;
- method public int sectorToBlock(int);
- method public void setTimeout(int);
- method public byte[] transceive(byte[]) throws java.io.IOException;
- method public void transfer(int) throws java.io.IOException;
- method public void writeBlock(int, byte[]) throws java.io.IOException;
- field public static final int BLOCK_SIZE = 16; // 0x10
- field public static final byte[] KEY_DEFAULT;
- field public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY;
- field public static final byte[] KEY_NFC_FORUM;
- field public static final int SIZE_1K = 1024; // 0x400
- field public static final int SIZE_2K = 2048; // 0x800
- field public static final int SIZE_4K = 4096; // 0x1000
- field public static final int SIZE_MINI = 320; // 0x140
- field public static final int TYPE_CLASSIC = 0; // 0x0
- field public static final int TYPE_PLUS = 1; // 0x1
- field public static final int TYPE_PRO = 2; // 0x2
- field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
- }
-
- public final class MifareUltralight implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.MifareUltralight get(android.nfc.Tag);
- method public int getMaxTransceiveLength();
- method public android.nfc.Tag getTag();
- method public int getTimeout();
- method public int getType();
- method public boolean isConnected();
- method public byte[] readPages(int) throws java.io.IOException;
- method public void setTimeout(int);
- method public byte[] transceive(byte[]) throws java.io.IOException;
- method public void writePage(int, byte[]) throws java.io.IOException;
- field public static final int PAGE_SIZE = 4; // 0x4
- field public static final int TYPE_ULTRALIGHT = 1; // 0x1
- field public static final int TYPE_ULTRALIGHT_C = 2; // 0x2
- field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
- }
-
- public final class Ndef implements android.nfc.tech.TagTechnology {
- method public boolean canMakeReadOnly();
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.Ndef get(android.nfc.Tag);
- method public android.nfc.NdefMessage getCachedNdefMessage();
- method public int getMaxSize();
- method public android.nfc.NdefMessage getNdefMessage() throws android.nfc.FormatException, java.io.IOException;
- method public android.nfc.Tag getTag();
- method public String getType();
- method public boolean isConnected();
- method public boolean isWritable();
- method public boolean makeReadOnly() throws java.io.IOException;
- method public void writeNdefMessage(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
- field public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
- field public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
- field public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
- field public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
- field public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
- }
-
- public final class NdefFormatable implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public void format(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
- method public void formatReadOnly(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
- method public static android.nfc.tech.NdefFormatable get(android.nfc.Tag);
- method public android.nfc.Tag getTag();
- method public boolean isConnected();
- }
-
- public final class NfcA implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.NfcA get(android.nfc.Tag);
- method public byte[] getAtqa();
- method public int getMaxTransceiveLength();
- method public short getSak();
- method public android.nfc.Tag getTag();
- method public int getTimeout();
- method public boolean isConnected();
- method public void setTimeout(int);
- method public byte[] transceive(byte[]) throws java.io.IOException;
- }
-
- public final class NfcB implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.NfcB get(android.nfc.Tag);
- method public byte[] getApplicationData();
- method public int getMaxTransceiveLength();
- method public byte[] getProtocolInfo();
- method public android.nfc.Tag getTag();
- method public boolean isConnected();
- method public byte[] transceive(byte[]) throws java.io.IOException;
- }
-
- public final class NfcBarcode implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.NfcBarcode get(android.nfc.Tag);
- method public byte[] getBarcode();
- method public android.nfc.Tag getTag();
- method public int getType();
- method public boolean isConnected();
- field public static final int TYPE_KOVIO = 1; // 0x1
- field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
- }
-
- public final class NfcF implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.NfcF get(android.nfc.Tag);
- method public byte[] getManufacturer();
- method public int getMaxTransceiveLength();
- method public byte[] getSystemCode();
- method public android.nfc.Tag getTag();
- method public int getTimeout();
- method public boolean isConnected();
- method public void setTimeout(int);
- method public byte[] transceive(byte[]) throws java.io.IOException;
- }
-
- public final class NfcV implements android.nfc.tech.TagTechnology {
- method public void close() throws java.io.IOException;
- method public void connect() throws java.io.IOException;
- method public static android.nfc.tech.NfcV get(android.nfc.Tag);
- method public byte getDsfId();
- method public int getMaxTransceiveLength();
- method public byte getResponseFlags();
- method public android.nfc.Tag getTag();
- method public boolean isConnected();
- method public byte[] transceive(byte[]) throws java.io.IOException;
- }
-
- public interface TagTechnology extends java.io.Closeable {
- method public void connect() throws java.io.IOException;
- method public android.nfc.Tag getTag();
- method public boolean isConnected();
- }
-
-}
-
package android.opengl {
public class EGL14 {
@@ -33913,7 +33460,6 @@ package android.os {
@FlaggedApi("android.os.adpf_gpu_report_actual_work_duration") public final class WorkDuration implements android.os.Parcelable {
ctor public WorkDuration();
- ctor public WorkDuration(long, long, long, long);
method public int describeContents();
method public long getActualCpuDurationNanos();
method public long getActualGpuDurationNanos();
@@ -41552,6 +41098,8 @@ package android.speech {
field public static final String EXTRA_LANGUAGE_MODEL = "android.speech.extra.LANGUAGE_MODEL";
field public static final String EXTRA_LANGUAGE_PREFERENCE = "android.speech.extra.LANGUAGE_PREFERENCE";
field public static final String EXTRA_LANGUAGE_SWITCH_ALLOWED_LANGUAGES = "android.speech.extra.LANGUAGE_SWITCH_ALLOWED_LANGUAGES";
+ field @FlaggedApi("android.speech.flags.multilang_extra_launch") public static final String EXTRA_LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS = "android.speech.extra.LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS";
+ field @FlaggedApi("android.speech.flags.multilang_extra_launch") public static final String EXTRA_LANGUAGE_SWITCH_MAX_SWITCHES = "android.speech.extra.LANGUAGE_SWITCH_MAX_SWITCHES";
field public static final String EXTRA_MASK_OFFENSIVE_WORDS = "android.speech.extra.MASK_OFFENSIVE_WORDS";
field public static final String EXTRA_MAX_RESULTS = "android.speech.extra.MAX_RESULTS";
field public static final String EXTRA_ONLY_RETURN_LANGUAGE_PREFERENCE = "android.speech.extra.ONLY_RETURN_LANGUAGE_PREFERENCE";
@@ -45343,7 +44891,7 @@ package android.telephony {
method public void addOnSubscriptionsChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void addSubscriptionsIntoGroup(@NonNull java.util.List<java.lang.Integer>, @NonNull android.os.ParcelUuid);
method public boolean canManageSubscription(android.telephony.SubscriptionInfo);
- method @FlaggedApi("com.android.internal.telephony.flags.work_profile_api_split") @NonNull public android.telephony.SubscriptionManager createForAllUserProfiles();
+ method @FlaggedApi("com.android.internal.telephony.flags.enforce_subscription_user_filter") @NonNull public android.telephony.SubscriptionManager createForAllUserProfiles();
method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public android.os.ParcelUuid createSubscriptionGroup(@NonNull java.util.List<java.lang.Integer>);
method @Deprecated public static android.telephony.SubscriptionManager from(android.content.Context);
method public java.util.List<android.telephony.SubscriptionInfo> getAccessibleSubscriptionInfoList();
@@ -51848,6 +51396,10 @@ package android.view {
ctor public SurfaceControl.TrustedPresentationThresholds(@FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @FloatRange(from=0.0f, fromInclusive=false, to=1.0f) float, @IntRange(from=1) int);
}
+ @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public interface SurfaceControlInputReceiver {
+ method public boolean onInputEvent(@NonNull android.view.InputEvent);
+ }
+
public class SurfaceControlViewHost {
ctor public SurfaceControlViewHost(@NonNull android.content.Context, @NonNull android.view.Display, @Nullable android.os.IBinder);
method @Nullable public android.view.SurfaceControlViewHost.SurfacePackage getSurfacePackage();
@@ -53971,10 +53523,13 @@ package android.view {
method @Deprecated public android.view.Display getDefaultDisplay();
method @NonNull public default android.view.WindowMetrics getMaximumWindowMetrics();
method public default boolean isCrossWindowBlurEnabled();
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerBatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.view.Choreographer, @NonNull android.view.SurfaceControlInputReceiver);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void registerTrustedPresentationListener(@NonNull android.os.IBinder, @NonNull android.window.TrustedPresentationThresholds, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") @NonNull public default android.os.IBinder registerUnbatchedSurfaceControlInputReceiver(int, @NonNull android.os.IBinder, @NonNull android.view.SurfaceControl, @NonNull android.os.Looper, @NonNull android.view.SurfaceControlInputReceiver);
method public default void removeCrossWindowBlurEnabledListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
method public default void removeProposedRotationListener(@NonNull java.util.function.IntConsumer);
method public void removeViewImmediate(android.view.View);
+ method @FlaggedApi("com.android.window.flags.surface_control_input_receiver") public default void unregisterSurfaceControlInputReceiver(@NonNull android.os.IBinder);
method @FlaggedApi("com.android.window.flags.trusted_presentation_listener_for_window") public default void unregisterTrustedPresentationListener(@NonNull java.util.function.Consumer<java.lang.Boolean>);
field public static final String PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE = "android.window.PROPERTY_ACTIVITY_EMBEDDING_ALLOW_SYSTEM_OVERRIDE";
field public static final String PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED = "android.window.PROPERTY_ACTIVITY_EMBEDDING_SPLITS_ENABLED";
diff --git a/core/api/lint-baseline.txt b/core/api/lint-baseline.txt
index f331e7f5fa84..162f54cc6d5a 100644
--- a/core/api/lint-baseline.txt
+++ b/core/api/lint-baseline.txt
@@ -181,12 +181,6 @@ BroadcastBehavior: android.media.tv.TvContract#ACTION_WATCH_NEXT_PROGRAM_BROWSAB
Field 'ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED' is missing @BroadcastBehavior
BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION:
Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED:
- Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED:
- Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED:
- Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior
BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED:
Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior
BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER:
@@ -715,86 +709,6 @@ RequiresPermission: android.net.sip.SipAudioCall#setSpeakerMode(boolean):
Method 'setSpeakerMode' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.net.sip.SipAudioCall#startAudio():
Method 'startAudio' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity):
- Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]):
- Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String):
- Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String):
- Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String):
- Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]):
- Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]):
- Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int):
- Method 'decrement' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int):
- Method 'increment' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int):
- Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#restore(int):
- Method 'restore' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#transfer(int):
- Method 'transfer' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]):
- Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int):
- Method 'readPages' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]):
- Method 'writePage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#getNdefMessage():
- Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#isWritable():
- Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#makeReadOnly():
- Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage):
- Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage):
- Method 'format' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage):
- Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.TagTechnology#close():
- Method 'close' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.TagTechnology#connect():
- Method 'connect' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.os.BugreportManager#cancelBugreport():
Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.os.Build#getSerial():
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index c1b9f64b9e8a..24b923326baa 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -319,11 +319,6 @@ package android.net.wifi {
package android.nfc {
- public class NfcFrameworkInitializer {
- method public static void registerServiceWrappers();
- method public static void setNfcServiceManager(@NonNull android.nfc.NfcServiceManager);
- }
-
public class NfcServiceManager {
method @NonNull public android.nfc.NfcServiceManager.ServiceRegisterer getNfcManagerServiceRegisterer();
}
diff --git a/core/api/module-lib-lint-baseline.txt b/core/api/module-lib-lint-baseline.txt
index a6a948c7f64c..a2179bc59707 100644
--- a/core/api/module-lib-lint-baseline.txt
+++ b/core/api/module-lib-lint-baseline.txt
@@ -235,14 +235,6 @@ BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS:
Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior
BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION:
Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED:
- Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED:
- Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
- Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED:
- Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior
BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED:
Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior
BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER:
@@ -1009,86 +1001,6 @@ RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net
Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission
RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener):
Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission
-RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity):
- Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]):
- Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String):
- Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String):
- Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String):
- Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]):
- Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]):
- Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int):
- Method 'decrement' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int):
- Method 'increment' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int):
- Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#restore(int):
- Method 'restore' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#transfer(int):
- Method 'transfer' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]):
- Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int):
- Method 'readPages' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]):
- Method 'writePage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#getNdefMessage():
- Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#isWritable():
- Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#makeReadOnly():
- Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage):
- Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage):
- Method 'format' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage):
- Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.TagTechnology#close():
- Method 'close' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.TagTechnology#connect():
- Method 'connect' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.os.BugreportManager#cancelBugreport():
Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.os.BugreportManager#preDumpUiData():
@@ -1769,8 +1681,6 @@ SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED:
Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE:
Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
- Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED:
Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED:
diff --git a/core/api/removed.txt b/core/api/removed.txt
index b58c822e39bc..3c7c0d6e6ea1 100644
--- a/core/api/removed.txt
+++ b/core/api/removed.txt
@@ -190,22 +190,6 @@ package android.net {
}
-package android.nfc {
-
- public final class NfcAdapter {
- method @Deprecated public void disableForegroundNdefPush(android.app.Activity);
- method @Deprecated public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
- method @Deprecated public boolean invokeBeam(android.app.Activity);
- method @Deprecated public boolean isNdefPushEnabled();
- method @Deprecated public void setBeamPushUris(android.net.Uri[], android.app.Activity);
- method @Deprecated public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
- method @Deprecated public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
- method @Deprecated public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
- method @Deprecated public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
- }
-
-}
-
package android.os {
public class BatteryManager {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c9e12c0b5948..ebd05446e963 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -862,10 +862,6 @@ package android.app {
field @NonNull public static final android.os.Parcelable.Creator<android.app.AppOpsManager.PackageOps> CREATOR;
}
- @FlaggedApi("android.app.bic_client") public final class BackgroundInstallControlManager {
- method @FlaggedApi("android.app.bic_client") @NonNull @RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES) public java.util.List<android.content.pm.PackageInfo> getBackgroundInstalledPackages(long);
- }
-
public class BroadcastOptions {
method public void clearRequireCompatChange();
method public int getPendingIntentBackgroundActivityStartMode();
@@ -9883,49 +9879,6 @@ package android.net.wifi.sharedconnectivity.service {
}
-package android.nfc {
-
- public final class NfcAdapter {
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
- method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
- method @FlaggedApi("android.nfc.enable_nfc_charging") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableWlc(boolean);
- method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
- method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
- method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
- method @FlaggedApi("android.nfc.enable_nfc_charging") public void unregisterWlcStateListener(@NonNull android.nfc.NfcAdapter.WlcStateListener);
- field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
- field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
- field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
- field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
- }
-
- public static interface NfcAdapter.ControllerAlwaysOnListener {
- method public void onControllerAlwaysOnChanged(boolean);
- }
-
- public static interface NfcAdapter.NfcUnlockHandler {
- method public boolean onUnlockAttempted(android.nfc.Tag);
- }
-
- @FlaggedApi("android.nfc.enable_nfc_charging") public static interface NfcAdapter.WlcStateListener {
- method public void onWlcStateChanged(@NonNull android.nfc.WlcLDeviceInfo);
- }
-
-}
-
package android.nfc.cardemulation {
@FlaggedApi("android.nfc.enable_nfc_mainline") public final class AidGroup implements android.os.Parcelable {
@@ -9974,11 +9927,6 @@ package android.nfc.cardemulation {
field @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.ApduServiceInfo> CREATOR;
}
- public final class CardEmulation {
- method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public android.nfc.cardemulation.ApduServiceInfo getPreferredPaymentService();
- method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
- }
-
@FlaggedApi("android.nfc.enable_nfc_mainline") public final class NfcFServiceInfo implements android.os.Parcelable {
ctor @FlaggedApi("android.nfc.enable_nfc_mainline") public NfcFServiceInfo(@NonNull android.content.pm.PackageManager, @NonNull android.content.pm.ResolveInfo) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method @FlaggedApi("android.nfc.enable_nfc_mainline") public int describeContents();
diff --git a/core/api/system-lint-baseline.txt b/core/api/system-lint-baseline.txt
index 0505af4488ff..6c83fd04b76b 100644
--- a/core/api/system-lint-baseline.txt
+++ b/core/api/system-lint-baseline.txt
@@ -239,14 +239,6 @@ BroadcastBehavior: android.net.NetworkScoreManager#ACTION_SCORE_NETWORKS:
Field 'ACTION_SCORE_NETWORKS' is missing @BroadcastBehavior
BroadcastBehavior: android.net.Proxy#PROXY_CHANGE_ACTION:
Field 'PROXY_CHANGE_ACTION' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED:
- Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED:
- Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
- Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior
-BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED:
- Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior
BroadcastBehavior: android.os.DropBoxManager#ACTION_DROPBOX_ENTRY_ADDED:
Field 'ACTION_DROPBOX_ENTRY_ADDED' is missing @BroadcastBehavior
BroadcastBehavior: android.provider.CalendarContract#ACTION_EVENT_REMINDER:
@@ -1077,86 +1069,6 @@ RequiresPermission: android.net.vcn.VcnManager#applyVcnNetworkPolicy(android.net
Method 'applyVcnNetworkPolicy' documentation mentions permissions already declared by @RequiresPermission
RequiresPermission: android.net.vcn.VcnManager#removeVcnNetworkPolicyChangeListener(android.net.vcn.VcnManager.VcnNetworkPolicyChangeListener):
Method 'removeVcnNetworkPolicyChangeListener' documentation mentions permissions already declared by @RequiresPermission
-RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity):
- Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]):
- Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String):
- Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String):
- Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String):
- Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]):
- Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]):
- Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int):
- Method 'decrement' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int):
- Method 'increment' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int):
- Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#restore(int):
- Method 'restore' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#transfer(int):
- Method 'transfer' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]):
- Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int):
- Method 'readPages' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]):
- Method 'writePage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#getNdefMessage():
- Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#isWritable():
- Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#makeReadOnly():
- Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage):
- Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage):
- Method 'format' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage):
- Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#getTimeout():
- Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#setTimeout(int):
- Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]):
- Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.TagTechnology#close():
- Method 'close' documentation mentions permissions without declaring @RequiresPermission
-RequiresPermission: android.nfc.tech.TagTechnology#connect():
- Method 'connect' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.os.BugreportManager#cancelBugreport():
Method 'cancelBugreport' documentation mentions permissions without declaring @RequiresPermission
RequiresPermission: android.os.BugreportManager#preDumpUiData():
@@ -1863,10 +1775,6 @@ SamShouldBeLast: android.media.session.MediaSessionManager#addOnActiveSessionsCh
SAM-compatible parameters (such as parameter 1, "sessionListener", in android.media.session.MediaSessionManager.addOnActiveSessionsChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.media.session.MediaSessionManager#addOnSession2TokensChangedListener(android.media.session.MediaSessionManager.OnSession2TokensChangedListener, android.os.Handler):
SAM-compatible parameters (such as parameter 1, "listener", in android.media.session.MediaSessionManager.addOnSession2TokensChangedListener) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle):
- SAM-compatible parameters (such as parameter 2, "callback", in android.nfc.NfcAdapter.enableReaderMode) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
-SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler):
- SAM-compatible parameters (such as parameter 3, "tagRemovedListener", in android.nfc.NfcAdapter.ignore) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Binder#attachInterface(android.os.IInterface, String):
SAM-compatible parameters (such as parameter 1, "owner", in android.os.Binder.attachInterface) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
SamShouldBeLast: android.os.Binder#linkToDeath(android.os.IBinder.DeathRecipient, int):
@@ -1933,8 +1841,6 @@ SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_PORT_COMPLIANCE_CHANGED:
Field 'ACTION_USB_PORT_COMPLIANCE_CHANGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
SdkConstant: android.hardware.usb.UsbManager#ACTION_USB_STATE:
Field 'ACTION_USB_STATE' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
-SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
- Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
SdkConstant: android.service.euicc.EuiccService#ACTION_DELETE_SUBSCRIPTION_PRIVILEGED:
Field 'ACTION_DELETE_SUBSCRIPTION_PRIVILEGED' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
SdkConstant: android.service.euicc.EuiccService#ACTION_RENAME_SUBSCRIPTION_PRIVILEGED:
diff --git a/core/api/system-removed.txt b/core/api/system-removed.txt
index 51b8a11e1791..bbfa0ec3f3c2 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -142,17 +142,6 @@ package android.media.tv {
}
-package android.nfc {
-
- public final class NfcAdapter {
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
- method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
- field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
- }
-
-}
-
package android.os {
public class Build {
diff --git a/core/java/Android.bp b/core/java/Android.bp
index fb1e16a27d0b..eba500dd32b4 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -14,20 +14,12 @@ aidl_library {
hdrs: ["android/hardware/HardwareBuffer.aidl"],
}
-// TODO (b/303286040): Remove this once |ENABLE_NFC_MAINLINE_FLAG| is rolled out
-filegroup {
- name: "framework-core-nfc-infcadapter-sources",
- srcs: [
- "android/nfc/INfcAdapter.aidl",
- ],
- visibility: ["//frameworks/base/services/core"],
-}
-
filegroup {
name: "framework-core-sources",
srcs: [
"**/*.java",
"**/*.aidl",
+ ":framework-nfc-non-updatable-sources",
],
visibility: ["//frameworks/base"],
}
diff --git a/core/java/android/animation/ObjectAnimator.java b/core/java/android/animation/ObjectAnimator.java
index 1e1f1554d3a2..5840f02a8650 100644
--- a/core/java/android/animation/ObjectAnimator.java
+++ b/core/java/android/animation/ObjectAnimator.java
@@ -25,8 +25,6 @@ import android.util.Log;
import android.util.Property;
import android.view.animation.AccelerateDecelerateInterpolator;
-import java.lang.ref.WeakReference;
-
/**
* This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
* The constructors of this class take parameters to define the target object that will be animated
@@ -73,11 +71,7 @@ public final class ObjectAnimator extends ValueAnimator {
private static final boolean DBG = false;
- /**
- * A weak reference to the target object on which the property exists, set
- * in the constructor. We'll cancel the animation if this goes away.
- */
- private WeakReference<Object> mTarget;
+ private Object mTarget;
private String mPropertyName;
@@ -919,7 +913,7 @@ public final class ObjectAnimator extends ValueAnimator {
*/
@Nullable
public Object getTarget() {
- return mTarget == null ? null : mTarget.get();
+ return mTarget;
}
@Override
@@ -929,7 +923,7 @@ public final class ObjectAnimator extends ValueAnimator {
if (isStarted()) {
cancel();
}
- mTarget = target == null ? null : new WeakReference<Object>(target);
+ mTarget = target;
// New target should cause re-initialization prior to starting
mInitialized = false;
}
@@ -977,13 +971,6 @@ public final class ObjectAnimator extends ValueAnimator {
@Override
void animateValue(float fraction) {
final Object target = getTarget();
- if (mTarget != null && target == null) {
- // We lost the target reference, cancel and clean up. Note: we allow null target if the
- /// target has never been set.
- cancel();
- return;
- }
-
super.animateValue(fraction);
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index be2582f6175d..2103055afe50 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1177,23 +1177,12 @@ public class Activity extends ContextThemeWrapper
return mApplication;
}
- /**
- * Whether this is a child {@link Activity} of an {@link ActivityGroup}.
- *
- * @deprecated {@link ActivityGroup} is deprecated.
- */
- @Deprecated
+ /** Is this activity embedded inside of another activity? */
public final boolean isChild() {
return mParent != null;
}
- /**
- * Returns the parent {@link Activity} if this is a child {@link Activity} of an
- * {@link ActivityGroup}.
- *
- * @deprecated {@link ActivityGroup} is deprecated.
- */
- @Deprecated
+ /** Return the parent activity if this view is an embedded child. */
public final Activity getParent() {
return mParent;
}
diff --git a/core/java/android/app/BackgroundInstallControlManager.java b/core/java/android/app/BackgroundInstallControlManager.java
deleted file mode 100644
index f5b68788f0ea..000000000000
--- a/core/java/android/app/BackgroundInstallControlManager.java
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app;
-
-import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-import static android.annotation.SystemApi.Client.PRIVILEGED_APPS;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.SystemService;
-import android.content.Context;
-import android.content.pm.IBackgroundInstallControlService;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.os.ServiceManager;
-
-import java.util.List;
-
-/**
- * BackgroundInstallControlManager client allows apps to query apps installed in background.
- *
- * <p>Any applications that was installed without an accompanying installer UI activity paired
- * with recorded user interaction event is considered background installed. This is determined by
- * analysis of user-activity logs.
- *
- * <p>Warning: BackgroundInstallControl should not be considered a reliable or accurate
- * determination of background install application. Consumers can use this as a supplementary
- * signal, but must perform additional due diligence to confirm the install nature of the package.
- *
- * @hide
- */
-@FlaggedApi(Flags.FLAG_BIC_CLIENT)
-@SystemApi(client = PRIVILEGED_APPS)
-@SystemService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE)
-public final class BackgroundInstallControlManager {
-
- private static final String TAG = "BackgroundInstallControlManager";
- private static IBackgroundInstallControlService sService;
- private final Context mContext;
-
- BackgroundInstallControlManager(Context context) {
- mContext = context;
- }
-
- private static IBackgroundInstallControlService getService() {
- if (sService == null) {
- sService =
- IBackgroundInstallControlService.Stub.asInterface(
- ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
- }
- return sService;
- }
-
- /**
- * Returns a full list of {@link PackageInfo} of apps currently installed that are considered
- * installed in the background.
- *
- * <p>Refer to top level doc {@link BackgroundInstallControlManager} for more details on
- * background-installed applications.
- * <p>
- *
- * @param flags - Flags will be used to call
- * {@link PackageManager#getInstalledPackages(PackageInfoFlags)} to retrieve installed packages.
- * @return A list of packages retrieved from {@link PackageManager} with non-background
- * installed app filter applied.
- *
- * @hide
- */
- @FlaggedApi(Flags.FLAG_BIC_CLIENT)
- @SystemApi
- @RequiresPermission(QUERY_ALL_PACKAGES)
- public @NonNull List<PackageInfo> getBackgroundInstalledPackages(
- @PackageManager.PackageInfoFlagsBits long flags) {
- try {
- return getService()
- .getBackgroundInstalledPackages(flags, mContext.getUserId())
- .getList();
- } catch (SecurityException e) {
- throw e;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
-}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 390fa2212298..9cf732abb86a 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -1603,20 +1603,6 @@ public final class SystemServiceRegistry {
}
});
- // DO NOT do a flag check like this unless the flag is read-only.
- // (because this code is executed during preload in zygote.)
- // If the flag is mutable, the check should be inside CachedServiceFetcher.
- if (Flags.bicClient()) {
- registerService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE,
- BackgroundInstallControlManager.class,
- new CachedServiceFetcher<BackgroundInstallControlManager>() {
- @Override
- public BackgroundInstallControlManager createService(ContextImpl ctx) {
- return new BackgroundInstallControlManager(ctx);
- }
- });
- }
-
sInitializing = true;
try {
// Note: the following functions need to be @SystemApis, once they become mainline
diff --git a/core/java/android/app/background_install_control_manager.aconfig b/core/java/android/app/background_install_control_manager.aconfig
deleted file mode 100644
index 029b93ab4534..000000000000
--- a/core/java/android/app/background_install_control_manager.aconfig
+++ /dev/null
@@ -1,9 +0,0 @@
-package: "android.app"
-
-flag {
- namespace: "background_install_control"
- name: "bic_client"
- description: "System API for background install control."
- is_fixed_read_only: true
- bug: "287507984"
-}
diff --git a/core/java/android/app/wearable/OWNERS b/core/java/android/app/wearable/OWNERS
index 073e2d79850b..497eaf0e40f1 100644
--- a/core/java/android/app/wearable/OWNERS
+++ b/core/java/android/app/wearable/OWNERS
@@ -1,3 +1,5 @@
charliewang@google.com
+hackz@google.com
oni@google.com
+tomchan@google.com
volnov@google.com \ No newline at end of file
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index c7a75ed5ea9c..e9b94c9f5791 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -41,6 +41,7 @@ import android.content.res.Configuration;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.SQLException;
+import android.multiuser.Flags;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Binder;
@@ -146,6 +147,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
private boolean mExported;
private boolean mNoPerms;
private boolean mSingleUser;
+ private boolean mSystemUserOnly;
private SparseBooleanArray mUsersRedirectedToOwnerForMedia = new SparseBooleanArray();
private ThreadLocal<AttributionSource> mCallingAttributionSource;
@@ -377,7 +379,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
!= PermissionChecker.PERMISSION_GRANTED
&& getContext().checkUriPermission(userUri, Binder.getCallingPid(),
callingUid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
- != PackageManager.PERMISSION_GRANTED) {
+ != PackageManager.PERMISSION_GRANTED
+ && !deniedAccessSystemUserOnlyProvider(callingUserId,
+ mSystemUserOnly)) {
FrameworkStatsLog.write(GET_TYPE_ACCESSED_WITHOUT_PERMISSION,
enumCheckUriPermission,
callingUid, uri.getAuthority(), type);
@@ -865,6 +869,10 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
boolean checkUser(int pid, int uid, Context context) {
final int callingUserId = UserHandle.getUserId(uid);
+ if (deniedAccessSystemUserOnlyProvider(callingUserId, mSystemUserOnly)) {
+ return false;
+ }
+
if (callingUserId == context.getUserId() || mSingleUser) {
return true;
}
@@ -987,6 +995,9 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
// last chance, check against any uri grants
final int callingUserId = UserHandle.getUserId(uid);
+ if (deniedAccessSystemUserOnlyProvider(callingUserId, mSystemUserOnly)) {
+ return PermissionChecker.PERMISSION_HARD_DENIED;
+ }
final Uri userUri = (mSingleUser && !UserHandle.isSameUser(mMyUid, uid))
? maybeAddUserId(uri, callingUserId) : uri;
if (context.checkUriPermission(userUri, pid, uid, Intent.FLAG_GRANT_READ_URI_PERMISSION)
@@ -2623,6 +2634,7 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
setPathPermissions(info.pathPermissions);
mExported = info.exported;
mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
+ mSystemUserOnly = (info.flags & ProviderInfo.FLAG_SYSTEM_USER_ONLY) != 0;
setAuthorities(info.authority);
}
if (Build.IS_DEBUGGABLE) {
@@ -2756,6 +2768,11 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
String auth = uri.getAuthority();
if (!mSingleUser) {
int userId = getUserIdFromAuthority(auth, UserHandle.USER_CURRENT);
+ if (deniedAccessSystemUserOnlyProvider(mContext.getUserId(),
+ mSystemUserOnly)) {
+ throw new SecurityException("Trying to query a SYSTEM user only content"
+ + " provider from user:" + mContext.getUserId());
+ }
if (userId != UserHandle.USER_CURRENT
&& userId != mContext.getUserId()
// Since userId specified in content uri, the provider userId would be
@@ -2929,4 +2946,16 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
Trace.traceBegin(traceTag, methodName + subInfo);
}
}
+ /**
+ * Return true if access to content provider is denied because it's a SYSTEM user only
+ * provider and the calling user is not the SYSTEM user.
+ *
+ * @param callingUserId UserId of the caller accessing the content provider.
+ * @param systemUserOnly true when the content provider is only available for the SYSTEM user.
+ */
+ private static boolean deniedAccessSystemUserOnlyProvider(int callingUserId,
+ boolean systemUserOnly) {
+ return Flags.enableSystemUserOnlyForServicesAndProviders()
+ && (callingUserId != UserHandle.USER_SYSTEM && systemUserOnly);
+ }
}
diff --git a/core/java/android/content/pm/IBackgroundInstallControlService.aidl b/core/java/android/content/pm/IBackgroundInstallControlService.aidl
index 4bc8fe16b249..c8e7caebc821 100644
--- a/core/java/android/content/pm/IBackgroundInstallControlService.aidl
+++ b/core/java/android/content/pm/IBackgroundInstallControlService.aidl
@@ -16,20 +16,11 @@
package android.content.pm;
-
import android.content.pm.ParceledListSlice;
-import android.os.IRemoteCallback;
/**
* {@hide}
*/
interface IBackgroundInstallControlService {
- @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest.permission.QUERY_ALL_PACKAGES)")
ParceledListSlice getBackgroundInstalledPackages(long flags, int userId);
-
- @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(allOf = {android.Manifest.permission.QUERY_ALL_PACKAGES, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})")
- void registerBackgroundInstallCallback(IRemoteCallback callback);
-
- @JavaPassthrough(annotation = "@android.annotation.RequiresPermission(allOf = {android.Manifest.permission.QUERY_ALL_PACKAGES, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL})")
- void unregisterBackgroundInstallCallback(IRemoteCallback callback);
-} \ No newline at end of file
+}
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index 9e553dbfb719..de33fa8b2328 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -89,6 +89,15 @@ public final class ProviderInfo extends ComponentInfo
public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000;
/**
+ * Bit in {@link #flags}: If set, this provider will only be available
+ * for the system user.
+ * Set from the android.R.attr#systemUserOnly attribute.
+ * In Sync with {@link ActivityInfo#FLAG_SYSTEM_USER_ONLY}
+ * @hide
+ */
+ public static final int FLAG_SYSTEM_USER_ONLY = ActivityInfo.FLAG_SYSTEM_USER_ONLY;
+
+ /**
* Bit in {@link #flags}: If set, a single instance of the provider will
* run for all users on the device. Set from the
* {@link android.R.attr#singleUser} attribute.
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index ae46c027505e..2b378b1f09d0 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -101,6 +101,14 @@ public class ServiceInfo extends ComponentInfo
public static final int FLAG_VISIBLE_TO_INSTANT_APP = 0x100000;
/**
+ * @hide Bit in {@link #flags}: If set, this service will only be available
+ * for the system user.
+ * Set from the android.R.attr#systemUserOnly attribute.
+ * In Sync with {@link ActivityInfo#FLAG_SYSTEM_USER_ONLY}
+ */
+ public static final int FLAG_SYSTEM_USER_ONLY = ActivityInfo.FLAG_SYSTEM_USER_ONLY;
+
+ /**
* Bit in {@link #flags}: If set, a single instance of the service will
* run for all users on the device. Set from the
* {@link android.R.attr#singleUser} attribute.
diff --git a/core/java/android/content/pm/multiuser.aconfig b/core/java/android/content/pm/multiuser.aconfig
index c7797c719e2c..10368653f0c4 100644
--- a/core/java/android/content/pm/multiuser.aconfig
+++ b/core/java/android/content/pm/multiuser.aconfig
@@ -70,4 +70,11 @@ flag {
namespace: "profile_experiences"
description: "Add support for Private Space in resolver sheet"
bug: "307515485"
-} \ No newline at end of file
+}
+flag {
+ name: "enable_system_user_only_for_services_and_providers"
+ namespace: "multiuser"
+ description: "Enable systemUserOnly manifest attribute for services and providers."
+ bug: "302354856"
+ is_fixed_read_only: true
+}
diff --git a/core/java/android/credentials/GetCandidateCredentialsException.java b/core/java/android/credentials/GetCandidateCredentialsException.java
index 40650d02a93e..0ac5f6c01212 100644
--- a/core/java/android/credentials/GetCandidateCredentialsException.java
+++ b/core/java/android/credentials/GetCandidateCredentialsException.java
@@ -46,6 +46,17 @@ public class GetCandidateCredentialsException extends Exception {
"android.credentials.GetCandidateCredentialsException.TYPE_NO_CREDENTIAL";
@NonNull
+ public static final String TYPE_USER_CANCELED =
+ "android.credentials.GetCredentialException.TYPE_USER_CANCELED";
+ /**
+ * The error type value for when the given operation failed due to internal interruption.
+ * Retrying the same operation should fix the error.
+ */
+ @NonNull
+ public static final String TYPE_INTERRUPTED =
+ "android.credentials.GetCredentialException.TYPE_INTERRUPTED";
+
+ @NonNull
private final String mType;
/** Returns the specific exception type. */
diff --git a/core/java/android/net/vcn/VcnManager.java b/core/java/android/net/vcn/VcnManager.java
index c727a6034006..561db9c8a8ce 100644
--- a/core/java/android/net/vcn/VcnManager.java
+++ b/core/java/android/net/vcn/VcnManager.java
@@ -102,6 +102,24 @@ public class VcnManager {
public static final String VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY =
"vcn_network_selection_wifi_exit_rssi_threshold";
+ /**
+ * Key for the interval to poll IpSecTransformState for packet loss monitoring
+ *
+ * @hide
+ */
+ @NonNull
+ public static final String VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY =
+ "vcn_network_selection_poll_ipsec_state_interval_seconds";
+
+ /**
+ * Key for the threshold of IPSec packet loss rate
+ *
+ * @hide
+ */
+ @NonNull
+ public static final String VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY =
+ "vcn_network_selection_ipsec_packet_loss_percent_threshold";
+
// TODO: Add separate signal strength thresholds for 2.4 GHz and 5GHz
/**
@@ -148,6 +166,8 @@ public class VcnManager {
new String[] {
VCN_NETWORK_SELECTION_WIFI_ENTRY_RSSI_THRESHOLD_KEY,
VCN_NETWORK_SELECTION_WIFI_EXIT_RSSI_THRESHOLD_KEY,
+ VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY,
+ VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY,
VCN_RESTRICTED_TRANSPORTS_INT_ARRAY_KEY,
VCN_SAFE_MODE_TIMEOUT_SECONDS_KEY,
VCN_TUNNEL_AGGREGATION_SA_COUNT_MAX_KEY,
diff --git a/core/java/android/net/vcn/flags.aconfig b/core/java/android/net/vcn/flags.aconfig
index 67a1906d48ed..7afd72195fcb 100644
--- a/core/java/android/net/vcn/flags.aconfig
+++ b/core/java/android/net/vcn/flags.aconfig
@@ -12,4 +12,11 @@ flag {
namespace: "vcn"
description: "Feature flag for adjustable safe mode timeout"
bug: "317406085"
+}
+
+flag{
+ name: "network_metric_monitor"
+ namespace: "vcn"
+ description: "Feature flag for enabling network metric monitor"
+ bug: "282996138"
} \ No newline at end of file
diff --git a/core/java/android/nfc/TEST_MAPPING b/core/java/android/nfc/TEST_MAPPING
deleted file mode 100644
index 5b5ea3790010..000000000000
--- a/core/java/android/nfc/TEST_MAPPING
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "presubmit": [
- {
- "name": "NfcManagerTests"
- },
- {
- "name": "CtsNfcTestCases"
- }
- ]
-}
diff --git a/core/java/android/nfc/tech/OWNERS b/core/java/android/nfc/tech/OWNERS
deleted file mode 100644
index 35e9713f5715..000000000000
--- a/core/java/android/nfc/tech/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48448
-include platform/packages/apps/Nfc:/OWNERS
diff --git a/core/java/android/os/PerformanceHintManager.java b/core/java/android/os/PerformanceHintManager.java
index 37bde3db5e14..746278fc296c 100644
--- a/core/java/android/os/PerformanceHintManager.java
+++ b/core/java/android/os/PerformanceHintManager.java
@@ -204,7 +204,7 @@ public final class PerformanceHintManager {
}
/**
- * Updates this session's target duration for each cycle of work.
+ * Updates this session's target total duration for each cycle of work.
*
* @param targetDurationNanos the new desired duration in nanoseconds
*/
diff --git a/core/java/android/os/WorkDuration.java b/core/java/android/os/WorkDuration.java
index 4fdc34fb60d1..2ebcd830be29 100644
--- a/core/java/android/os/WorkDuration.java
+++ b/core/java/android/os/WorkDuration.java
@@ -26,7 +26,7 @@ import java.util.Objects;
* in each component, see
* {@link PerformanceHintManager.Session#reportActualWorkDuration(WorkDuration)}.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()} and measured in wall time.
*/
@FlaggedApi(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION)
public final class WorkDuration implements Parcelable {
@@ -50,17 +50,9 @@ public final class WorkDuration implements Parcelable {
public WorkDuration() {}
- public WorkDuration(long workPeriodStartTimestampNanos,
- long actualTotalDurationNanos,
- long actualCpuDurationNanos,
- long actualGpuDurationNanos) {
- mWorkPeriodStartTimestampNanos = workPeriodStartTimestampNanos;
- mActualTotalDurationNanos = actualTotalDurationNanos;
- mActualCpuDurationNanos = actualCpuDurationNanos;
- mActualGpuDurationNanos = actualGpuDurationNanos;
- }
-
/**
+ * Constructor for testing.
+ *
* @hide
*/
public WorkDuration(long workPeriodStartTimestampNanos,
@@ -86,7 +78,7 @@ public final class WorkDuration implements Parcelable {
/**
* Sets the work period start timestamp in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public void setWorkPeriodStartTimestampNanos(long workPeriodStartTimestampNanos) {
if (workPeriodStartTimestampNanos <= 0) {
@@ -99,7 +91,7 @@ public final class WorkDuration implements Parcelable {
/**
* Sets the actual total duration in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public void setActualTotalDurationNanos(long actualTotalDurationNanos) {
if (actualTotalDurationNanos <= 0) {
@@ -111,7 +103,7 @@ public final class WorkDuration implements Parcelable {
/**
* Sets the actual CPU duration in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public void setActualCpuDurationNanos(long actualCpuDurationNanos) {
if (actualCpuDurationNanos <= 0) {
@@ -123,7 +115,7 @@ public final class WorkDuration implements Parcelable {
/**
* Sets the actual GPU duration in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public void setActualGpuDurationNanos(long actualGpuDurationNanos) {
if (actualGpuDurationNanos < 0) {
@@ -135,7 +127,7 @@ public final class WorkDuration implements Parcelable {
/**
* Returns the work period start timestamp based in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public long getWorkPeriodStartTimestampNanos() {
return mWorkPeriodStartTimestampNanos;
@@ -144,7 +136,7 @@ public final class WorkDuration implements Parcelable {
/**
* Returns the actual total duration in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public long getActualTotalDurationNanos() {
return mActualTotalDurationNanos;
@@ -153,7 +145,7 @@ public final class WorkDuration implements Parcelable {
/**
* Returns the actual CPU duration in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public long getActualCpuDurationNanos() {
return mActualCpuDurationNanos;
@@ -162,7 +154,7 @@ public final class WorkDuration implements Parcelable {
/**
* Returns the actual GPU duration in nanoseconds.
*
- * All timings should be in {@link SystemClock#elapsedRealtimeNanos()}.
+ * All timings should be in {@link SystemClock#uptimeNanos()}.
*/
public long getActualGpuDurationNanos() {
return mActualGpuDurationNanos;
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 7d9c0a37a13f..2d657c2813a5 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -445,6 +445,19 @@ public class DreamService extends Service implements Window.Callback {
}
/**
+ * Retrieves the current {@link android.app.Activity} associated with the dream.
+ * This method behaves similarly to calling {@link android.app.Activity#getActivity()}.
+ *
+ * @return The current activity, or null if the dream is not associated with an activity
+ * or not started.
+ *
+ * @hide
+ */
+ public Activity getActivity() {
+ return mActivity;
+ }
+
+ /**
* Inflates a layout resource and set it to be the content view for this Dream.
* Behaves similarly to {@link android.app.Activity#setContentView(int)}.
*
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 92c516c38dcc..7658af53a7f8 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -42,6 +42,7 @@ import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
+import android.os.BadParcelableException;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -1056,7 +1057,7 @@ public abstract class NotificationListenerService extends Service {
ParceledListSlice<StatusBarNotification> parceledList = getNotificationInterface()
.getActiveNotificationsFromListener(mWrapper, keys, trim);
return cleanUpNotificationList(parceledList);
- } catch (android.os.RemoteException ex) {
+ } catch (android.os.RemoteException | BadParcelableException ex) {
Log.v(TAG, "Unable to contact notification manager", ex);
}
return null;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 45a0c205a09b..54248be74e04 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -64,6 +64,7 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.time.Instant;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
@@ -233,6 +234,7 @@ public class ZenModeConfig implements Parcelable {
private static final String MANUAL_TAG = "manual";
private static final String AUTOMATIC_TAG = "automatic";
+ private static final String AUTOMATIC_DELETED_TAG = "deleted";
private static final String RULE_ATT_ID = "ruleId";
private static final String RULE_ATT_ENABLED = "enabled";
@@ -251,6 +253,7 @@ public class ZenModeConfig implements Parcelable {
private static final String RULE_ATT_USER_MODIFIED_FIELDS = "userModifiedFields";
private static final String RULE_ATT_ICON = "rule_icon";
private static final String RULE_ATT_TRIGGER_DESC = "triggerDesc";
+ private static final String RULE_ATT_DELETION_INSTANT = "deletionInstant";
private static final String DEVICE_EFFECT_DISPLAY_GRAYSCALE = "zdeDisplayGrayscale";
private static final String DEVICE_EFFECT_SUPPRESS_AMBIENT_DISPLAY =
@@ -292,6 +295,10 @@ public class ZenModeConfig implements Parcelable {
@UnsupportedAppUsage
public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
+ // Note: Map is *pkg|conditionId* (see deletedRuleKey()) -> ZenRule,
+ // unlike automaticRules (which is id -> rule).
+ public final ArrayMap<String, ZenRule> deletedRules = new ArrayMap<>();
+
@UnsupportedAppUsage
public ZenModeConfig() {
}
@@ -306,15 +313,9 @@ public class ZenModeConfig implements Parcelable {
allowMessagesFrom = source.readInt();
user = source.readInt();
manualRule = source.readParcelable(null, ZenRule.class);
- final int len = source.readInt();
- if (len > 0) {
- final String[] ids = new String[len];
- final ZenRule[] rules = new ZenRule[len];
- source.readStringArray(ids);
- source.readTypedArray(rules, ZenRule.CREATOR);
- for (int i = 0; i < len; i++) {
- automaticRules.put(ids[i], rules[i]);
- }
+ readRulesFromParcel(automaticRules, source);
+ if (Flags.modesApi()) {
+ readRulesFromParcel(deletedRules, source);
}
allowAlarms = source.readInt() == 1;
allowMedia = source.readInt() == 1;
@@ -328,6 +329,19 @@ public class ZenModeConfig implements Parcelable {
}
}
+ private static void readRulesFromParcel(ArrayMap<String, ZenRule> ruleMap, Parcel source) {
+ final int len = source.readInt();
+ if (len > 0) {
+ final String[] ids = new String[len];
+ final ZenRule[] rules = new ZenRule[len];
+ source.readStringArray(ids);
+ source.readTypedArray(rules, ZenRule.CREATOR);
+ for (int i = 0; i < len; i++) {
+ ruleMap.put(ids[i], rules[i]);
+ }
+ }
+ }
+
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(allowCalls ? 1 : 0);
@@ -339,19 +353,9 @@ public class ZenModeConfig implements Parcelable {
dest.writeInt(allowMessagesFrom);
dest.writeInt(user);
dest.writeParcelable(manualRule, 0);
- if (!automaticRules.isEmpty()) {
- final int len = automaticRules.size();
- final String[] ids = new String[len];
- final ZenRule[] rules = new ZenRule[len];
- for (int i = 0; i < len; i++) {
- ids[i] = automaticRules.keyAt(i);
- rules[i] = automaticRules.valueAt(i);
- }
- dest.writeInt(len);
- dest.writeStringArray(ids);
- dest.writeTypedArray(rules, 0);
- } else {
- dest.writeInt(0);
+ writeRulesToParcel(automaticRules, dest);
+ if (Flags.modesApi()) {
+ writeRulesToParcel(deletedRules, dest);
}
dest.writeInt(allowAlarms ? 1 : 0);
dest.writeInt(allowMedia ? 1 : 0);
@@ -365,6 +369,23 @@ public class ZenModeConfig implements Parcelable {
}
}
+ private static void writeRulesToParcel(ArrayMap<String, ZenRule> ruleMap, Parcel dest) {
+ if (!ruleMap.isEmpty()) {
+ final int len = ruleMap.size();
+ final String[] ids = new String[len];
+ final ZenRule[] rules = new ZenRule[len];
+ for (int i = 0; i < len; i++) {
+ ids[i] = ruleMap.keyAt(i);
+ rules[i] = ruleMap.valueAt(i);
+ }
+ dest.writeInt(len);
+ dest.writeStringArray(ids);
+ dest.writeTypedArray(rules, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
@@ -389,23 +410,26 @@ public class ZenModeConfig implements Parcelable {
} else {
sb.append(",areChannelsBypassingDnd=").append(areChannelsBypassingDnd);
}
- return sb.append(",\nautomaticRules=").append(rulesToString())
- .append(",\nmanualRule=").append(manualRule)
- .append(']').toString();
+ sb.append(",\nautomaticRules=").append(rulesToString(automaticRules))
+ .append(",\nmanualRule=").append(manualRule);
+ if (Flags.modesApi()) {
+ sb.append(",\ndeletedRules=").append(rulesToString(deletedRules));
+ }
+ return sb.append(']').toString();
}
- private String rulesToString() {
- if (automaticRules.isEmpty()) {
+ private static String rulesToString(ArrayMap<String, ZenRule> ruleList) {
+ if (ruleList.isEmpty()) {
return "{}";
}
- StringBuilder buffer = new StringBuilder(automaticRules.size() * 28);
+ StringBuilder buffer = new StringBuilder(ruleList.size() * 28);
buffer.append("{\n");
- for (int i = 0; i < automaticRules.size(); i++) {
+ for (int i = 0; i < ruleList.size(); i++) {
if (i > 0) {
buffer.append(",\n");
}
- Object value = automaticRules.valueAt(i);
+ Object value = ruleList.valueAt(i);
buffer.append(value);
}
buffer.append('}');
@@ -487,7 +511,9 @@ public class ZenModeConfig implements Parcelable {
&& other.allowConversations == allowConversations
&& other.allowConversationsFrom == allowConversationsFrom;
if (Flags.modesApi()) {
- return eq && other.allowPriorityChannels == allowPriorityChannels;
+ return eq
+ && Objects.equals(other.deletedRules, deletedRules)
+ && other.allowPriorityChannels == allowPriorityChannels;
}
return eq;
}
@@ -644,12 +670,20 @@ public class ZenModeConfig implements Parcelable {
DEFAULT_SUPPRESSED_VISUAL_EFFECTS);
} else if (MANUAL_TAG.equals(tag)) {
rt.manualRule = readRuleXml(parser);
- } else if (AUTOMATIC_TAG.equals(tag)) {
+ } else if (AUTOMATIC_TAG.equals(tag)
+ || (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag))) {
final String id = parser.getAttributeValue(null, RULE_ATT_ID);
final ZenRule automaticRule = readRuleXml(parser);
if (id != null && automaticRule != null) {
automaticRule.id = id;
- rt.automaticRules.put(id, automaticRule);
+ if (Flags.modesApi() && AUTOMATIC_DELETED_TAG.equals(tag)) {
+ String deletedRuleKey = deletedRuleKey(automaticRule);
+ if (deletedRuleKey != null) {
+ rt.deletedRules.put(deletedRuleKey, automaticRule);
+ }
+ } else if (AUTOMATIC_TAG.equals(tag)) {
+ rt.automaticRules.put(id, automaticRule);
+ }
}
} else if (STATE_TAG.equals(tag)) {
rt.areChannelsBypassingDnd = safeBoolean(parser,
@@ -660,13 +694,24 @@ public class ZenModeConfig implements Parcelable {
throw new IllegalStateException("Failed to reach END_DOCUMENT");
}
+ /** Generates the map key used for a {@link ZenRule} in {@link #deletedRules}. */
+ @Nullable
+ public static String deletedRuleKey(ZenRule rule) {
+ if (rule.pkg != null && rule.conditionId != null) {
+ return rule.pkg + "|" + rule.conditionId.toString();
+ } else {
+ return null;
+ }
+ }
+
/**
* Writes XML of current ZenModeConfig
* @param out serializer
* @param version uses XML_VERSION if version is null
* @throws IOException
*/
- public void writeXml(TypedXmlSerializer out, Integer version) throws IOException {
+ public void writeXml(TypedXmlSerializer out, Integer version, boolean forBackup)
+ throws IOException {
out.startTag(null, ZEN_TAG);
out.attribute(null, ZEN_ATT_VERSION, version == null
? Integer.toString(XML_VERSION) : Integer.toString(version));
@@ -707,6 +752,15 @@ public class ZenModeConfig implements Parcelable {
writeRuleXml(automaticRule, out);
out.endTag(null, AUTOMATIC_TAG);
}
+ if (Flags.modesApi() && !forBackup) {
+ for (int i = 0; i < deletedRules.size(); i++) {
+ final ZenRule deletedRule = deletedRules.valueAt(i);
+ out.startTag(null, AUTOMATIC_DELETED_TAG);
+ out.attribute(null, RULE_ATT_ID, deletedRule.id);
+ writeRuleXml(deletedRule, out);
+ out.endTag(null, AUTOMATIC_DELETED_TAG);
+ }
+ }
out.startTag(null, STATE_TAG);
out.attributeBoolean(null, STATE_ATT_CHANNELS_BYPASSING_DND, areChannelsBypassingDnd);
@@ -752,6 +806,11 @@ public class ZenModeConfig implements Parcelable {
rt.triggerDescription = parser.getAttributeValue(null, RULE_ATT_TRIGGER_DESC);
rt.type = safeInt(parser, RULE_ATT_TYPE, AutomaticZenRule.TYPE_UNKNOWN);
rt.userModifiedFields = safeInt(parser, RULE_ATT_USER_MODIFIED_FIELDS, 0);
+ Long deletionInstant = tryParseLong(
+ parser.getAttributeValue(null, RULE_ATT_DELETION_INSTANT), null);
+ if (deletionInstant != null) {
+ rt.deletionInstant = Instant.ofEpochMilli(deletionInstant);
+ }
}
return rt;
}
@@ -799,6 +858,10 @@ public class ZenModeConfig implements Parcelable {
}
out.attributeInt(null, RULE_ATT_TYPE, rule.type);
out.attributeInt(null, RULE_ATT_USER_MODIFIED_FIELDS, rule.userModifiedFields);
+ if (rule.deletionInstant != null) {
+ out.attributeLong(null, RULE_ATT_DELETION_INSTANT,
+ rule.deletionInstant.toEpochMilli());
+ }
}
}
@@ -1998,6 +2061,7 @@ public class ZenModeConfig implements Parcelable {
public String iconResName;
public boolean allowManualInvocation;
public int userModifiedFields;
+ @Nullable public Instant deletionInstant; // Only set on deleted rules.
public ZenRule() { }
@@ -2031,6 +2095,9 @@ public class ZenModeConfig implements Parcelable {
triggerDescription = source.readString();
type = source.readInt();
userModifiedFields = source.readInt();
+ if (source.readInt() == 1) {
+ deletionInstant = Instant.ofEpochMilli(source.readLong());
+ }
}
}
@@ -2091,6 +2158,12 @@ public class ZenModeConfig implements Parcelable {
dest.writeString(triggerDescription);
dest.writeInt(type);
dest.writeInt(userModifiedFields);
+ if (deletionInstant != null) {
+ dest.writeInt(1);
+ dest.writeLong(deletionInstant.toEpochMilli());
+ } else {
+ dest.writeInt(0);
+ }
}
}
@@ -2121,6 +2194,9 @@ public class ZenModeConfig implements Parcelable {
.append(",triggerDescription=").append(triggerDescription)
.append(",type=").append(type)
.append(",userModifiedFields=").append(userModifiedFields);
+ if (deletionInstant != null) {
+ sb.append(",deletionInstant=").append(deletionInstant);
+ }
}
return sb.append(']').toString();
@@ -2180,7 +2256,8 @@ public class ZenModeConfig implements Parcelable {
&& Objects.equals(other.iconResName, iconResName)
&& Objects.equals(other.triggerDescription, triggerDescription)
&& other.type == type
- && other.userModifiedFields == userModifiedFields;
+ && other.userModifiedFields == userModifiedFields
+ && Objects.equals(other.deletionInstant, deletionInstant);
}
return finalEquals;
@@ -2192,7 +2269,7 @@ public class ZenModeConfig implements Parcelable {
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
component, configurationActivity, pkg, id, enabler, zenPolicy,
zenDeviceEffects, modified, allowManualInvocation, iconResName,
- triggerDescription, type, userModifiedFields);
+ triggerDescription, type, userModifiedFields, deletionInstant);
}
return Objects.hash(enabled, snoozing, name, zenMode, conditionId, condition,
component, configurationActivity, pkg, id, enabler, zenPolicy, modified);
diff --git a/core/java/android/service/notification/ZenModeDiff.java b/core/java/android/service/notification/ZenModeDiff.java
index 8902368072bf..91ef11cf1d2d 100644
--- a/core/java/android/service/notification/ZenModeDiff.java
+++ b/core/java/android/service/notification/ZenModeDiff.java
@@ -30,6 +30,11 @@ import java.util.Set;
/**
* ZenModeDiff is a utility class meant to encapsulate the diff between ZenModeConfigs and their
* subcomponents (automatic and manual ZenRules).
+ *
+ * <p>Note that this class is intended to detect <em>meaningful</em> differences, so objects that
+ * are not identical (as per their {@code equals()} implementation) can still produce an empty diff
+ * if only "metadata" fields are updated.
+ *
* @hide
*/
public class ZenModeDiff {
@@ -467,7 +472,6 @@ public class ZenModeDiff {
public static final String FIELD_ICON_RES = "iconResName";
public static final String FIELD_TRIGGER_DESCRIPTION = "triggerDescription";
public static final String FIELD_TYPE = "type";
- public static final String FIELD_USER_MODIFIED_FIELDS = "userModifiedFields";
// NOTE: new field strings must match the variable names in ZenModeConfig.ZenRule
// Special field to track whether this rule became active or inactive
@@ -563,10 +567,6 @@ public class ZenModeDiff {
if (!Objects.equals(from.iconResName, to.iconResName)) {
addField(FIELD_ICON_RES, new FieldDiff<>(from.iconResName, to.iconResName));
}
- if (from.userModifiedFields != to.userModifiedFields) {
- addField(FIELD_USER_MODIFIED_FIELDS,
- new FieldDiff<>(from.userModifiedFields, to.userModifiedFields));
- }
}
}
diff --git a/core/java/android/service/notification/flags.aconfig b/core/java/android/service/notification/flags.aconfig
index a2ade6a9473f..3008b8d45252 100644
--- a/core/java/android/service/notification/flags.aconfig
+++ b/core/java/android/service/notification/flags.aconfig
@@ -21,3 +21,11 @@ flag {
description: "This flag controls the redacting of sensitive notifications from untrusted NotificationListenerServices"
bug: "306271190"
}
+
+flag {
+ name: "callstyle_callback_api"
+ namespace: "systemui"
+ description: "Guards the new CallStyleNotificationEventsCallback"
+ bug: "305095040"
+ is_fixed_read_only: true
+} \ No newline at end of file
diff --git a/core/java/android/service/wearable/OWNERS b/core/java/android/service/wearable/OWNERS
index 073e2d79850b..eca48b742cef 100644
--- a/core/java/android/service/wearable/OWNERS
+++ b/core/java/android/service/wearable/OWNERS
@@ -1,3 +1 @@
-charliewang@google.com
-oni@google.com
-volnov@google.com \ No newline at end of file
+include /core/java/android/app/wearable/OWNERS \ No newline at end of file
diff --git a/core/java/android/speech/RecognizerIntent.java b/core/java/android/speech/RecognizerIntent.java
index 118d0284fb9e..1ca7ac77158c 100644
--- a/core/java/android/speech/RecognizerIntent.java
+++ b/core/java/android/speech/RecognizerIntent.java
@@ -16,6 +16,9 @@
package android.speech;
+import static android.speech.flags.Flags.FLAG_MULTILANG_EXTRA_LAUNCH;
+
+import android.annotation.FlaggedApi;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
@@ -653,4 +656,30 @@ public class RecognizerIntent {
*/
public static final String EXTRA_LANGUAGE_SWITCH_ALLOWED_LANGUAGES =
"android.speech.extra.LANGUAGE_SWITCH_ALLOWED_LANGUAGES";
+
+ /**
+ * Optional integer to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}. If set, the language
+ * switch will be deactivated when LANGUAGE_SWITCH_MAX_SWITCHES reached.
+ *
+ * <p> Depending on the recognizer implementation, this flag may have no effect.
+ *
+ * @see #EXTRA_ENABLE_LANGUAGE_SWITCH
+ */
+ @FlaggedApi(FLAG_MULTILANG_EXTRA_LAUNCH)
+ public static final String EXTRA_LANGUAGE_SWITCH_MAX_SWITCHES =
+ "android.speech.extra.LANGUAGE_SWITCH_MAX_SWITCHES";
+
+ /**
+ * Optional integer to use for {@link #EXTRA_ENABLE_LANGUAGE_SWITCH}. If set, the language
+ * switch will only be activated for this value of ms of audio since the START_OF_SPEECH. This
+ * could provide a more stable recognition result when the language switch is only required in
+ * the beginning of the session.
+ *
+ * <p> Depending on the recognizer implementation, this flag may have no effect.
+ *
+ * @see #EXTRA_ENABLE_LANGUAGE_SWITCH
+ */
+ @FlaggedApi(FLAG_MULTILANG_EXTRA_LAUNCH)
+ public static final String EXTRA_LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS =
+ "android.speech.extra.LANGUAGE_SWITCH_INITIAL_ACTIVE_DURATION_TIME_MILLIS";
}
diff --git a/core/java/android/speech/flags/speech_flags.aconfig b/core/java/android/speech/flags/speech_flags.aconfig
new file mode 100644
index 000000000000..fd8012746a27
--- /dev/null
+++ b/core/java/android/speech/flags/speech_flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.speech.flags"
+
+flag {
+ name: "multilang_extra_launch"
+ namespace: "machine_learning"
+ description: "Feature flag for adding new extra for multi-lang feature"
+ bug: "312489931"
+}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index a74cbe46b404..f0e673b3e3ac 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -378,6 +378,13 @@ public final class Choreographer {
}
/**
+ * @hide
+ */
+ public Looper getLooper() {
+ return mLooper;
+ }
+
+ /**
* The amount of time, in milliseconds, between each frame of the animation.
* <p>
* This is a requested time that the animation will attempt to honor, but the actual delay
diff --git a/core/java/android/view/SurfaceControlInputReceiver.java b/core/java/android/view/SurfaceControlInputReceiver.java
new file mode 100644
index 000000000000..81e444859b76
--- /dev/null
+++ b/core/java/android/view/SurfaceControlInputReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2024 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.view;
+
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
+
+import com.android.window.flags.Flags;
+
+/**
+ * Provides a mechanism for a SurfaceControl to receive input events.
+ */
+@FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+public interface SurfaceControlInputReceiver {
+ /**
+ * When input events are batched, this is called at most once per frame. When non batched, this
+ * is called immediately for the input event.
+ *
+ * @param event The input event that was received. This input event object will become invalid
+ * and recycled after this method is invoked. If there is need to persist this
+ * object beyond the scope of this method, the overriding code should make a copy
+ * of this object. For example, using
+ * {@link MotionEvent#obtain(MotionEvent other)} or
+ * {@link KeyEvent#KeyEvent(KeyEvent)} }
+ * @return true if the event was handled, false otherwise.
+ */
+ boolean onInputEvent(@NonNull InputEvent event);
+
+}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index d8fa41589f29..96aba4c352e6 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -109,6 +109,7 @@ import android.graphics.Region;
import android.os.Build;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
@@ -6015,4 +6016,94 @@ public interface WindowManager extends ViewManager {
default void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * Registers a {@link SurfaceControlInputReceiver} for a {@link SurfaceControl} that will
+ * receive batched input event. For those events that are batched, the invocation will happen
+ * once per {@link Choreographer} frame, and other input events will be delivered immediately.
+ * This is different from
+ * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+ * SurfaceControlInputReceiver)} in that the input events are received batched. The caller must
+ * invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources when
+ * no longer needing to use the {@link SurfaceControlInputReceiver}
+ *
+ * @param displayId The display that the SurfaceControl will be placed on. Input will
+ * only work
+ * if SurfaceControl is on that display and that display was touched.
+ * @param surfaceControl The SurfaceControl to register the InputChannel for
+ * @param hostToken The host token to link the InputChannel for. This is primarily for ANRs
+ * to ensure the host receives the ANR if any issues with touch on the
+ * InputChannel
+ * @param choreographer The Choreographer used for batching. This should match the rendering
+ * Choreographer.
+ * @param receiver The SurfaceControlInputReceiver that will receive the input events
+ * @return an {@link IBinder} token that is used to unregister the input receiver via
+ * {@link #unregisterSurfaceControlInputReceiver(IBinder)}.
+ * @see #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+ * SurfaceControlInputReceiver)
+ */
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+ @NonNull
+ default IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+ @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
+ throw new UnsupportedOperationException(
+ "registerBatchedSurfaceControlInputReceiver is not implemented");
+ }
+
+ /**
+ * Registers a {@link SurfaceControlInputReceiver} for a {@link SurfaceControl} that will
+ * receive every input event. This is different than calling @link
+ * #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
+ * SurfaceControlInputReceiver)} in that the input events are received unbatched. The caller
+ * must invoke {@link #unregisterSurfaceControlInputReceiver(IBinder)} to clean up the resources
+ * when no longer needing to use the {@link SurfaceControlInputReceiver}
+ *
+ * @param displayId The display that the SurfaceControl will be placed on. Input will only
+ * work if SurfaceControl is on that display and that display was
+ * touched.
+ * @param hostToken The host token to link the InputChannel for. This is primarily for ANRs
+ * to ensure the host receives the ANR if any issues with touch on the
+ * InputChannel
+ * @param surfaceControl The SurfaceControl to register the InputChannel for
+ * @param looper The looper to use when invoking callbacks.
+ * @param receiver The SurfaceControlInputReceiver that will receive the input events
+ * @return an {@link IBinder} token that is used to unregister the input receiver via
+ * {@link #unregisterSurfaceControlInputReceiver(IBinder)}.
+ * @see #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Choreographer,
+ * SurfaceControlInputReceiver)
+ **/
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+ @NonNull
+ default IBinder registerUnbatchedSurfaceControlInputReceiver(int displayId,
+ @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
+ throw new UnsupportedOperationException(
+ "registerUnbatchedSurfaceControlInputReceiver is not implemented");
+ }
+
+ /**
+ * Unregisters and cleans up the registered {@link SurfaceControlInputReceiver} for the
+ * specified token.
+ * <p>
+ * Must be called on the same {@link Looper} thread to which was passed to the
+ * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl,
+ * Choreographer,
+ * SurfaceControlInputReceiver)} or
+ * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder, SurfaceControl, Looper,
+ * SurfaceControlInputReceiver)}
+ *
+ * @param token The token that was returned via
+ * {@link #registerBatchedSurfaceControlInputReceiver(int, IBinder,
+ * SurfaceControl,
+ * Choreographer, SurfaceControlInputReceiver)} or
+ * {@link #registerUnbatchedSurfaceControlInputReceiver(int, IBinder,
+ * SurfaceControl,
+ * Looper, SurfaceControlInputReceiver)}
+ */
+ @FlaggedApi(Flags.FLAG_SURFACE_CONTROL_INPUT_RECEIVER)
+ default void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) {
+ throw new UnsupportedOperationException(
+ "unregisterSurfaceControlInputReceiver is not implemented");
+ }
}
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index f1e406196abf..8d40f9a4f7b1 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -24,8 +26,10 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.res.Configuration;
import android.graphics.HardwareRenderer;
+import android.os.Binder;
import android.os.Build;
import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -46,6 +50,7 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.WeakHashMap;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
@@ -151,6 +156,9 @@ public final class WindowManagerGlobal {
private final TrustedPresentationListener mTrustedPresentationListener =
new TrustedPresentationListener();
+ private final ConcurrentHashMap<IBinder, InputEventReceiver> mSurfaceControlInputReceivers =
+ new ConcurrentHashMap<>();
+
private WindowManagerGlobal() {
}
@@ -808,6 +816,74 @@ public final class WindowManagerGlobal {
mTrustedPresentationListener.removeListener(listener);
}
+ IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+ @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
+ IBinder clientToken = new Binder();
+ InputChannel inputChannel = new InputChannel();
+ try {
+ WindowManagerGlobal.getWindowSession().grantInputChannel(displayId, surfaceControl,
+ clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, null,
+ surfaceControl.getName(), inputChannel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create input channel", e);
+ e.rethrowAsRuntimeException();
+ }
+
+ mSurfaceControlInputReceivers.put(clientToken,
+ new BatchedInputEventReceiver(inputChannel, choreographer.getLooper(),
+ choreographer) {
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = receiver.onInputEvent(event);
+ finishInputEvent(event, handled);
+ }
+ });
+ return clientToken;
+ }
+
+ IBinder registerUnbatchedSurfaceControlInputReceiver(
+ int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
+ IBinder clientToken = new Binder();
+ InputChannel inputChannel = new InputChannel();
+ try {
+ WindowManagerGlobal.getWindowSession().grantInputChannel(displayId, surfaceControl,
+ clientToken, hostToken, 0, 0, TYPE_APPLICATION, 0, null, null,
+ surfaceControl.getName(), inputChannel);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to create input channel", e);
+ e.rethrowAsRuntimeException();
+ }
+
+ mSurfaceControlInputReceivers.put(clientToken,
+ new InputEventReceiver(inputChannel, looper) {
+ @Override
+ public void onInputEvent(InputEvent event) {
+ boolean handled = receiver.onInputEvent(event);
+ finishInputEvent(event, handled);
+ }
+ });
+
+ return clientToken;
+ }
+
+ void unregisterSurfaceControlInputReceiver(IBinder token) {
+ InputEventReceiver inputEventReceiver = mSurfaceControlInputReceivers.get(token);
+ if (inputEventReceiver == null) {
+ Log.w(TAG, "No registered input event receiver with token: " + token);
+ return;
+ }
+ try {
+ WindowManagerGlobal.getWindowSession().remove(token);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to remove input channel", e);
+ e.rethrowAsRuntimeException();
+ }
+
+ inputEventReceiver.dispose();
+ }
+
private final class TrustedPresentationListener extends
ITrustedPresentationListener.Stub {
private static int sId = 0;
diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java
index b4b1fde89a46..aaf5fcc6f095 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -32,6 +32,7 @@ import android.graphics.Bitmap;
import android.graphics.Region;
import android.os.Bundle;
import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteException;
import android.os.StrictMode;
import android.util.Log;
@@ -520,6 +521,28 @@ public final class WindowManagerImpl implements WindowManager {
@Override
public void unregisterTrustedPresentationListener(@NonNull Consumer<Boolean> listener) {
mGlobal.unregisterTrustedPresentationListener(listener);
+ }
+
+ @NonNull
+ @Override
+ public IBinder registerBatchedSurfaceControlInputReceiver(int displayId,
+ @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull Choreographer choreographer, @NonNull SurfaceControlInputReceiver receiver) {
+ return mGlobal.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+ surfaceControl, choreographer, receiver);
+ }
+ @NonNull
+ @Override
+ public IBinder registerUnbatchedSurfaceControlInputReceiver(
+ int displayId, @NonNull IBinder hostToken, @NonNull SurfaceControl surfaceControl,
+ @NonNull Looper looper, @NonNull SurfaceControlInputReceiver receiver) {
+ return mGlobal.registerUnbatchedSurfaceControlInputReceiver(displayId, hostToken,
+ surfaceControl, looper, receiver);
+ }
+
+ @Override
+ public void unregisterSurfaceControlInputReceiver(@NonNull IBinder token) {
+ mGlobal.unregisterSurfaceControlInputReceiver(token);
}
}
diff --git a/core/java/android/view/flags/view_flags.aconfig b/core/java/android/view/flags/view_flags.aconfig
index a74b06a491e8..9f9b7b4b68a9 100644
--- a/core/java/android/view/flags/view_flags.aconfig
+++ b/core/java/android/view/flags/view_flags.aconfig
@@ -1,6 +1,13 @@
package: "android.view.flags"
flag {
+ name: "enable_surface_native_alloc_registration"
+ namespace: "toolkit"
+ description: "Feature flag for registering surfaces with the VM for faster cleanup"
+ bug: "306193257"
+}
+
+flag {
name: "enable_use_measure_cache_during_force_layout"
namespace: "toolkit"
description: "Enables using the measure cache during a view force layout from the second "
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index bdaad2b68fc2..473b814fc4a7 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -47,6 +47,7 @@ import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
+import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.ImageView;
@@ -337,7 +338,14 @@ public final class SplashScreenView extends FrameLayout {
"SplashScreenView");
ImageView imageView = new ImageView(viewContext);
imageView.setBackground(mIconDrawable);
- viewHost.setView(imageView, mIconSize, mIconSize);
+ final int windowFlag = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+ | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+ | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ final WindowManager.LayoutParams lp =
+ new WindowManager.LayoutParams(mIconSize, mIconSize,
+ WindowManager.LayoutParams.TYPE_APPLICATION, windowFlag,
+ PixelFormat.TRANSPARENT);
+ viewHost.setView(imageView, lp);
SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage();
surfaceView.setChildSurfacePackage(surfacePackage);
view.mSurfacePackage = surfacePackage;
diff --git a/core/java/android/window/flags/window_surfaces.aconfig b/core/java/android/window/flags/window_surfaces.aconfig
index 3794c5d647a4..3c3c8469b3a4 100644
--- a/core/java/android/window/flags/window_surfaces.aconfig
+++ b/core/java/android/window/flags/window_surfaces.aconfig
@@ -72,3 +72,11 @@ flag {
is_fixed_read_only: true
bug: "295038072"
}
+
+flag {
+ namespace: "window_surfaces"
+ name: "surface_control_input_receiver"
+ description: "Enable public API to register an InputReceiver for a SurfaceControl"
+ is_fixed_read_only: true
+ bug: "278757236"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index f2bce9c44001..bb16ad2cb8de 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -72,7 +72,7 @@ flag {
name: "predictive_back_system_animations"
namespace: "systemui"
description: "Predictive back for system animations"
- bug: "309545085"
+ bug: "319421778"
is_fixed_read_only: true
}
diff --git a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
index e55c64199f45..fab8984ce067 100644
--- a/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
+++ b/core/java/com/android/internal/display/RefreshRateSettingsUtils.java
@@ -33,13 +33,14 @@ public class RefreshRateSettingsUtils {
/**
* Find the highest refresh rate among all the modes of the default display.
*
+ * This method will acquire DisplayManager.mLock, so calling it while holding other locks
+ * should be done with care.
* @param context The context
* @return The highest refresh rate
*/
public static float findHighestRefreshRateForDefaultDisplay(Context context) {
final DisplayManager dm = context.getSystemService(DisplayManager.class);
final Display display = dm.getDisplay(Display.DEFAULT_DISPLAY);
-
if (display == null) {
Log.w(TAG, "No valid default display device");
return DEFAULT_REFRESH_RATE;
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
index 5d82d0469d56..12aff1c6669f 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedProviderUtils.java
@@ -29,6 +29,7 @@ import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.multiuser.Flags;
import android.os.Build;
import android.os.PatternMatcher;
import android.util.Slog;
@@ -126,6 +127,10 @@ public class ParsedProviderUtils {
.setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SINGLE_USER,
R.styleable.AndroidManifestProvider_singleUser, sa));
+ if (Flags.enableSystemUserOnlyForServicesAndProviders()) {
+ provider.setFlags(provider.getFlags() | flag(ProviderInfo.FLAG_SYSTEM_USER_ONLY,
+ R.styleable.AndroidManifestProvider_systemUserOnly, sa));
+ }
visibleToEphemeral = sa.getBoolean(
R.styleable.AndroidManifestProvider_visibleToInstantApps, false);
if (visibleToEphemeral) {
diff --git a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
index a1dd19a3bc90..4ac542f84226 100644
--- a/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
+++ b/core/java/com/android/internal/pm/pkg/component/ParsedServiceUtils.java
@@ -29,6 +29,7 @@ import android.content.pm.parsing.result.ParseResult;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
+import android.multiuser.Flags;
import android.os.Build;
import com.android.internal.R;
@@ -105,6 +106,11 @@ public class ParsedServiceUtils {
| flag(ServiceInfo.FLAG_SINGLE_USER,
R.styleable.AndroidManifestService_singleUser, sa)));
+ if (Flags.enableSystemUserOnlyForServicesAndProviders()) {
+ service.setFlags(service.getFlags() | flag(ServiceInfo.FLAG_SYSTEM_USER_ONLY,
+ R.styleable.AndroidManifestService_systemUserOnly, sa));
+ }
+
visibleToEphemeral = sa.getBoolean(
R.styleable.AndroidManifestService_visibleToInstantApps, false);
if (visibleToEphemeral) {
diff --git a/core/proto/OWNERS b/core/proto/OWNERS
index db391f7a8c35..a854e3626e78 100644
--- a/core/proto/OWNERS
+++ b/core/proto/OWNERS
@@ -18,6 +18,7 @@ per-file usagestatsservice.proto, usagestatsservice_v2.proto = file:/core/java/a
per-file apphibernationservice.proto = file:/core/java/android/apphibernation/OWNERS
per-file android/hardware/sensorprivacy.proto = ntmyren@google.com,evanseverson@google.com
per-file background_install_control.proto = wenhaowang@google.com,georgechan@google.com,billylau@google.com
+per-file android/content/intent.proto = file:/PACKAGE_MANAGER_OWNERS
# Biometrics
jaggies@google.com
@@ -31,5 +32,3 @@ jreck@google.com
# Accessibility
pweaver@google.com
-hongmingjin@google.com
-cbrower@google.com
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index af305329da1a..31acd9af164c 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -90,4 +90,7 @@
{@link MotionEvent#AXIS_SCROLL} generated by {@link InputDevice#SOURCE_ROTARY_ENCODER}
devices. -->
<bool name="config_viewRotaryEncoderHapticScrollFedbackEnabled">true</bool>
+
+ <!-- If this is true, allow wake from theater mode from motion. -->
+ <bool name="config_allowTheaterModeWakeFromMotion">true</bool>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 8fae6db4114a..601952437650 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -506,6 +506,12 @@
receivers, and providers; it can not be used with activities. -->
<attr name="singleUser" format="boolean" />
+ <!-- If set to true, only a single instance of this component will
+ run and be available for the SYSTEM user. Non SYSTEM users will not be
+ allowed to access the component if this flag is enabled.
+ This flag can be used with services, receivers, providers and activities. -->
+ <attr name="systemUserOnly" format="boolean" />
+
<!-- Specify a specific process that the associated code is to run in.
Use with the application tag (to supply a default process for all
application components), or with the activity, receiver, service,
@@ -2859,6 +2865,7 @@
Context.createAttributionContext() using the first attribution tag
contained here. -->
<attr name="attributionTags" />
+ <attr name="systemUserOnly" format="boolean" />
</declare-styleable>
<!-- Attributes that can be supplied in an AndroidManifest.xml
@@ -3017,6 +3024,7 @@
ignored when the process is bound into a shared isolated process by a client.
-->
<attr name="allowSharedIsolatedProcess" format="boolean" />
+ <attr name="systemUserOnly" format="boolean" />
</declare-styleable>
<!-- @hide The <code>apex-system-service</code> tag declares an apex system service
@@ -3144,7 +3152,7 @@
<attr name="uiOptions" />
<attr name="parentActivityName" />
<attr name="singleUser" />
- <!-- @hide This broadcast receiver or activity will only receive broadcasts for the
+ <!-- This broadcast receiver or activity will only receive broadcasts for the
system user-->
<attr name="systemUserOnly" format="boolean" />
<attr name="persistableMode" />
diff --git a/core/res/res/values/public-staging.xml b/core/res/res/values/public-staging.xml
index 53b473e0ac1f..7b5c49c8d9aa 100644
--- a/core/res/res/values/public-staging.xml
+++ b/core/res/res/values/public-staging.xml
@@ -119,6 +119,8 @@
<public name="optional"/>
<!-- @FlaggedApi("android.media.tv.flags.enable_ad_service_fw") -->
<public name="adServiceTypes" />
+ <!-- @FlaggedApi("android.multiuser.enable_system_user_only_for_services_and_providers") -->
+ <public name="systemUserOnly"/>
</staging-public-group>
<staging-public-group type="id" first-id="0x01bc0000">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 542e9d6f936f..f2858066b55b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1825,7 +1825,7 @@
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
<string name="fingerprint_acquired_partial">Press firmly on the sensor</string>
<!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
- <string name="fingerprint_acquired_insufficient">Can\u2019t recognize fingerprint. Try again.</string>
+ <string name="fingerprint_acquired_insufficient">Fingerprint not recognized. Try again.</string>
<!-- Message shown during fingerprint acquisision when the fingerprint sensor needs cleaning -->
<string name="fingerprint_acquired_imager_dirty">Clean fingerprint sensor and try again</string>
<string name="fingerprint_acquired_imager_dirty_alt">Clean sensor and try again</string>
@@ -1959,7 +1959,7 @@
<!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
<string name="face_acquired_recalibrate">Please re-enroll your face.</string>
<!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
- <string name="face_acquired_too_different">Can\u2019t recognize face. Try again.</string>
+ <string name="face_acquired_too_different">Face not recognized. Try again.</string>
<!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
<string name="face_acquired_too_similar">Change the position of your head slightly</string>
<!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
diff --git a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
index 12a28446b0e1..a28bb69244eb 100644
--- a/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
+++ b/core/tests/coretests/src/android/os/PerformanceHintManagerTest.java
@@ -195,9 +195,30 @@ public class PerformanceHintManagerTest {
Session s = createSession();
assumeNotNull(s);
s.updateTargetWorkDuration(16);
- s.reportActualWorkDuration(new WorkDuration(1, 12, 8, 6));
- s.reportActualWorkDuration(new WorkDuration(1, 33, 14, 20));
- s.reportActualWorkDuration(new WorkDuration(1, 14, 10, 6));
+ {
+ WorkDuration workDuration = new WorkDuration();
+ workDuration.setWorkPeriodStartTimestampNanos(1);
+ workDuration.setActualTotalDurationNanos(12);
+ workDuration.setActualCpuDurationNanos(8);
+ workDuration.setActualGpuDurationNanos(6);
+ s.reportActualWorkDuration(workDuration);
+ }
+ {
+ WorkDuration workDuration = new WorkDuration();
+ workDuration.setWorkPeriodStartTimestampNanos(1);
+ workDuration.setActualTotalDurationNanos(33);
+ workDuration.setActualCpuDurationNanos(14);
+ workDuration.setActualGpuDurationNanos(20);
+ s.reportActualWorkDuration(workDuration);
+ }
+ {
+ WorkDuration workDuration = new WorkDuration();
+ workDuration.setWorkPeriodStartTimestampNanos(1);
+ workDuration.setActualTotalDurationNanos(14);
+ workDuration.setActualCpuDurationNanos(10);
+ workDuration.setActualGpuDurationNanos(6);
+ s.reportActualWorkDuration(workDuration);
+ }
}
@Test
@@ -206,25 +227,25 @@ public class PerformanceHintManagerTest {
assumeNotNull(s);
s.updateTargetWorkDuration(16);
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(-1, 12, 8, 6));
+ s.reportActualWorkDuration(new WorkDuration(-1, 12, 8, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(0, 12, 8, 6));
+ s.reportActualWorkDuration(new WorkDuration(0, 12, 8, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(1, -1, 8, 6));
+ s.reportActualWorkDuration(new WorkDuration(1, -1, 8, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(1, 0, 8, 6));
+ s.reportActualWorkDuration(new WorkDuration(1, 0, 8, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(1, 12, -1, 6));
+ s.reportActualWorkDuration(new WorkDuration(1, 12, -1, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 6));
+ s.reportActualWorkDuration(new WorkDuration(1, 12, 0, 6, 1));
});
assertThrows(IllegalArgumentException.class, () -> {
- s.reportActualWorkDuration(new WorkDuration(1, 12, 8, -1));
+ s.reportActualWorkDuration(new WorkDuration(1, 12, 8, -1, 1));
});
}
}
diff --git a/core/tests/coretests/src/android/os/WorkDurationUnitTest.java b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
new file mode 100644
index 000000000000..c70da6e94385
--- /dev/null
+++ b/core/tests/coretests/src/android/os/WorkDurationUnitTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import static org.junit.Assert.assertThrows;
+
+import android.platform.test.annotations.IgnoreUnderRavenwood;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.ravenwood.RavenwoodRule;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+@IgnoreUnderRavenwood(blockedBy = WorkDuration.class)
+public class WorkDurationUnitTest {
+ @Rule
+ public final RavenwoodRule mRavenwood = new RavenwoodRule();
+
+ // Required for RequiresFlagsEnabled and RequiresFlagsDisabled annotations to take effect.
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = RavenwoodRule.isUnderRavenwood() ? null
+ : DeviceFlagsValueProvider.createCheckFlagsRule();
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(Flags.FLAG_ADPF_GPU_REPORT_ACTUAL_WORK_DURATION)
+ public void testWorkDurationSetters_IllegalArgument() {
+ WorkDuration workDuration = new WorkDuration();
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setWorkPeriodStartTimestampNanos(-1);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setWorkPeriodStartTimestampNanos(0);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setActualTotalDurationNanos(-1);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setActualTotalDurationNanos(0);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setActualCpuDurationNanos(-1);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setActualCpuDurationNanos(0);
+ });
+ assertThrows(IllegalArgumentException.class, () -> {
+ workDuration.setActualGpuDurationNanos(-1);
+ });
+ }
+}
diff --git a/core/tests/nfctests/OWNERS b/core/tests/nfctests/OWNERS
deleted file mode 100644
index 34b095c7fda0..000000000000
--- a/core/tests/nfctests/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-include /core/java/android/nfc/OWNERS
diff --git a/libs/WindowManager/Shell/Android.bp b/libs/WindowManager/Shell/Android.bp
index 5ad144d50b87..45540e0fbbb8 100644
--- a/libs/WindowManager/Shell/Android.bp
+++ b/libs/WindowManager/Shell/Android.bp
@@ -175,3 +175,74 @@ android_library {
plugins: ["dagger2-compiler"],
use_resource_processor: true,
}
+
+android_app {
+ name: "WindowManagerShellRobolectric",
+ platform_apis: true,
+ static_libs: [
+ "WindowManager-Shell",
+ ],
+ manifest: "multivalentTests/AndroidManifestRobolectric.xml",
+ use_resource_processor: true,
+}
+
+android_robolectric_test {
+ name: "WMShellRobolectricTests",
+ instrumentation_for: "WindowManagerShellRobolectric",
+ upstream: true,
+ java_resource_dirs: [
+ "multivalentTests/robolectric/config",
+ ],
+ srcs: [
+ "multivalentTests/src/**/*.kt",
+ ],
+ static_libs: [
+ "junit",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "mockito-robolectric-prebuilt",
+ "mockito-kotlin2",
+ "truth",
+ ],
+}
+
+android_test {
+ name: "WMShellMultivalentTestsOnDevice",
+ srcs: [
+ "multivalentTests/src/**/*.kt",
+ ],
+ static_libs: [
+ "WindowManager-Shell",
+ "junit",
+ "androidx.test.runner",
+ "androidx.test.rules",
+ "androidx.test.ext.junit",
+ "frameworks-base-testutils",
+ "mockito-kotlin2",
+ "mockito-target-extended-minus-junit4",
+ "truth",
+ "platform-test-annotations",
+ "platform-test-rules",
+ ],
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ jni_libs: [
+ "libdexmakerjvmtiagent",
+ "libstaticjvmtiagent",
+ ],
+ kotlincflags: ["-Xjvm-default=all"],
+ optimize: {
+ enabled: false,
+ },
+ test_suites: ["device-tests"],
+ platform_apis: true,
+ certificate: "platform",
+ aaptflags: [
+ "--extra-packages",
+ "com.android.wm.shell",
+ ],
+ manifest: "multivalentTests/AndroidManifest.xml",
+}
diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml b/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml
new file mode 100644
index 000000000000..f8f8338e5f04
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.multivalenttests">
+
+ <application android:debuggable="true" android:supportsRtl="true" >
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation
+ android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:label="Multivalent tests for WindowManager-Shell"
+ android:targetPackage="com.android.wm.shell.multivalenttests">
+ </instrumentation>
+</manifest>
diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml b/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml
new file mode 100644
index 000000000000..ffcd7d46fbae
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml
@@ -0,0 +1,3 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.wm.shell.multivalenttests">
+</manifest>
diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidTest.xml b/libs/WindowManager/Shell/multivalentTests/AndroidTest.xml
new file mode 100644
index 000000000000..36fe8ec3370d
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2023 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs Tests for WindowManagerShellLib">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="install-arg" value="-t" />
+ <option name="test-file-name" value="WMShellMultivalentTestsOnDevice.apk" />
+ </target_preparer>
+
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="framework-base-presubmit" />
+ <option name="test-tag" value="WMShellMultivalentTestsOnDevice" />
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.wm.shell.multivalenttests" />
+ <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+ <option name="hidden-api-checks" value="false"/>
+ </test>
+</configuration>
diff --git a/libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties b/libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties
new file mode 100644
index 000000000000..7a0527ccaafb
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/robolectric/config/robolectric.properties
@@ -0,0 +1,2 @@
+sdk=NEWEST_SDK
+
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
new file mode 100644
index 000000000000..ea7c6edd4b56
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubblePositionerTest.kt
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.wm.shell.bubbles
+
+import android.content.Context
+import android.content.Intent
+import android.content.pm.ShortcutInfo
+import android.graphics.Insets
+import android.graphics.PointF
+import android.graphics.Rect
+import android.os.UserHandle
+import android.view.WindowManager
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.R
+import com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT
+import com.google.common.truth.Truth.assertThat
+import com.google.common.util.concurrent.MoreExecutors.directExecutor
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests operations and the resulting state managed by [BubblePositioner]. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class BubblePositionerTest {
+
+ private lateinit var positioner: BubblePositioner
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private val defaultDeviceConfig =
+ DeviceConfig(
+ windowBounds = Rect(0, 0, 1000, 2000),
+ isLargeScreen = false,
+ isSmallTablet = false,
+ isLandscape = false,
+ isRtl = false,
+ insets = Insets.of(0, 0, 0, 0)
+ )
+
+ @Before
+ fun setUp() {
+ val windowManager = context.getSystemService(WindowManager::class.java)
+ positioner = BubblePositioner(context, windowManager)
+ }
+
+ @Test
+ fun testUpdate() {
+ val insets = Insets.of(10, 20, 5, 15)
+ val screenBounds = Rect(0, 0, 1000, 1200)
+ val availableRect = Rect(screenBounds)
+ availableRect.inset(insets)
+ positioner.update(defaultDeviceConfig.copy(insets = insets, windowBounds = screenBounds))
+ assertThat(positioner.availableRect).isEqualTo(availableRect)
+ assertThat(positioner.isLandscape).isFalse()
+ assertThat(positioner.isLargeScreen).isFalse()
+ assertThat(positioner.insets).isEqualTo(insets)
+ }
+
+ @Test
+ fun testShowBubblesVertically_phonePortrait() {
+ positioner.update(defaultDeviceConfig)
+ assertThat(positioner.showBubblesVertically()).isFalse()
+ }
+
+ @Test
+ fun testShowBubblesVertically_phoneLandscape() {
+ positioner.update(defaultDeviceConfig.copy(isLandscape = true))
+ assertThat(positioner.isLandscape).isTrue()
+ assertThat(positioner.showBubblesVertically()).isTrue()
+ }
+
+ @Test
+ fun testShowBubblesVertically_tablet() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true))
+ assertThat(positioner.showBubblesVertically()).isTrue()
+ }
+
+ /** If a resting position hasn't been set, calling it will return the default position. */
+ @Test
+ fun testGetRestingPosition_returnsDefaultPosition() {
+ positioner.update(defaultDeviceConfig)
+ val restingPosition = positioner.getRestingPosition()
+ val defaultPosition = positioner.defaultStartPosition
+ assertThat(restingPosition).isEqualTo(defaultPosition)
+ }
+
+ /** If a resting position has been set, it'll return that instead of the default position. */
+ @Test
+ fun testGetRestingPosition_returnsRestingPosition() {
+ positioner.update(defaultDeviceConfig)
+ val restingPosition = PointF(100f, 100f)
+ positioner.restingPosition = restingPosition
+ assertThat(positioner.getRestingPosition()).isEqualTo(restingPosition)
+ }
+
+ /** Test that the default resting position on phone is in upper left. */
+ @Test
+ fun testGetRestingPosition_bubble_onPhone() {
+ positioner.update(defaultDeviceConfig)
+ val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ val restingPosition = positioner.getRestingPosition()
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left)
+ assertThat(restingPosition.y).isEqualTo(defaultYPosition)
+ }
+
+ @Test
+ fun testGetRestingPosition_bubble_onPhone_RTL() {
+ positioner.update(defaultDeviceConfig.copy(isRtl = true))
+ val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ val restingPosition = positioner.getRestingPosition()
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right)
+ assertThat(restingPosition.y).isEqualTo(defaultYPosition)
+ }
+
+ /** Test that the default resting position on tablet is middle left. */
+ @Test
+ fun testGetRestingPosition_chatBubble_onTablet() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true))
+ val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ val restingPosition = positioner.getRestingPosition()
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left)
+ assertThat(restingPosition.y).isEqualTo(defaultYPosition)
+ }
+
+ @Test
+ fun testGetRestingPosition_chatBubble_onTablet_RTL() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true))
+ val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ val restingPosition = positioner.getRestingPosition()
+ assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right)
+ assertThat(restingPosition.y).isEqualTo(defaultYPosition)
+ }
+
+ /** Test that the default resting position on tablet is middle right. */
+ @Test
+ fun testGetDefaultPosition_appBubble_onTablet() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true))
+ val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */)
+ assertThat(startPosition.x).isEqualTo(allowableStackRegion.right)
+ assertThat(startPosition.y).isEqualTo(defaultYPosition)
+ }
+
+ @Test
+ fun testGetRestingPosition_appBubble_onTablet_RTL() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true))
+ val allowableStackRegion = positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ val startPosition = positioner.getDefaultStartPosition(true /* isAppBubble */)
+ assertThat(startPosition.x).isEqualTo(allowableStackRegion.left)
+ assertThat(startPosition.y).isEqualTo(defaultYPosition)
+ }
+
+ @Test
+ fun testHasUserModifiedDefaultPosition_false() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true))
+ assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse()
+ positioner.restingPosition = positioner.defaultStartPosition
+ assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse()
+ }
+
+ @Test
+ fun testHasUserModifiedDefaultPosition_true() {
+ positioner.update(defaultDeviceConfig.copy(isLargeScreen = true, isRtl = true))
+ assertThat(positioner.hasUserModifiedDefaultPosition()).isFalse()
+ positioner.restingPosition = PointF(0f, 100f)
+ assertThat(positioner.hasUserModifiedDefaultPosition()).isTrue()
+ }
+
+ @Test
+ fun testGetExpandedViewHeight_max() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT)
+ }
+
+ @Test
+ fun testGetExpandedViewHeight_customHeight_valid() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+ val minHeight =
+ context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height)
+ val bubble =
+ Bubble(
+ "key",
+ ShortcutInfo.Builder(context, "id").build(),
+ minHeight + 100 /* desiredHeight */,
+ 0 /* desiredHeightResId */,
+ "title",
+ 0 /* taskId */,
+ null /* locus */,
+ true /* isDismissable */,
+ directExecutor()) {}
+
+ // Ensure the height is the same as the desired value
+ assertThat(positioner.getExpandedViewHeight(bubble))
+ .isEqualTo(bubble.getDesiredHeight(context))
+ }
+
+ @Test
+ fun testGetExpandedViewHeight_customHeight_tooSmall() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val bubble =
+ Bubble(
+ "key",
+ ShortcutInfo.Builder(context, "id").build(),
+ 10 /* desiredHeight */,
+ 0 /* desiredHeightResId */,
+ "title",
+ 0 /* taskId */,
+ null /* locus */,
+ true /* isDismissable */,
+ directExecutor()) {}
+
+ // Ensure the height is the same as the desired value
+ val minHeight =
+ context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_default_height)
+ assertThat(positioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight)
+ }
+
+ @Test
+ fun testGetMaxExpandedViewHeight_onLargeTablet() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val manageButtonHeight =
+ context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height)
+ val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width)
+ val expandedViewPadding =
+ context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding)
+ val expectedHeight =
+ 1800 - 2 * 20 - manageButtonHeight - pointerWidth - expandedViewPadding * 2
+ assertThat(positioner.getMaxExpandedViewHeight(false /* isOverflow */))
+ .isEqualTo(expectedHeight)
+ }
+
+ @Test
+ fun testAreBubblesBottomAligned_largeScreen_true() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ assertThat(positioner.areBubblesBottomAligned()).isTrue()
+ }
+
+ @Test
+ fun testAreBubblesBottomAligned_largeScreen_landscape_false() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ isLandscape = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ assertThat(positioner.areBubblesBottomAligned()).isFalse()
+ }
+
+ @Test
+ fun testAreBubblesBottomAligned_smallTablet_false() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ isSmallTablet = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ assertThat(positioner.areBubblesBottomAligned()).isFalse()
+ }
+
+ @Test
+ fun testAreBubblesBottomAligned_phone_false() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ assertThat(positioner.areBubblesBottomAligned()).isFalse()
+ }
+
+ @Test
+ fun testExpandedViewY_phoneLandscape() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLandscape = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ // This bubble will have max height so it'll always be top aligned
+ assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(positioner.getExpandedViewYTopAligned())
+ }
+
+ @Test
+ fun testExpandedViewY_phonePortrait() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ // Always top aligned in phone portrait
+ assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(positioner.getExpandedViewYTopAligned())
+ }
+
+ @Test
+ fun testExpandedViewY_smallTabletLandscape() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isSmallTablet = true,
+ isLandscape = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ // This bubble will have max height which is always top aligned on small tablets
+ assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(positioner.getExpandedViewYTopAligned())
+ }
+
+ @Test
+ fun testExpandedViewY_smallTabletPortrait() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isSmallTablet = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ // This bubble will have max height which is always top aligned on small tablets
+ assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(positioner.getExpandedViewYTopAligned())
+ }
+
+ @Test
+ fun testExpandedViewY_largeScreenLandscape() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ isLandscape = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ // This bubble will have max height which is always top aligned on landscape, large tablet
+ assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(positioner.getExpandedViewYTopAligned())
+ }
+
+ @Test
+ fun testExpandedViewY_largeScreenPortrait() {
+ val deviceConfig =
+ defaultDeviceConfig.copy(
+ isLargeScreen = true,
+ insets = Insets.of(10, 20, 5, 15),
+ windowBounds = Rect(0, 0, 1800, 2600)
+ )
+ positioner.update(deviceConfig)
+
+ val intent = Intent(Intent.ACTION_VIEW).setPackage(context.packageName)
+ val bubble = Bubble.createAppBubble(intent, UserHandle(1), null, directExecutor())
+
+ val manageButtonHeight =
+ context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_height)
+ val manageButtonPlusMargin =
+ manageButtonHeight +
+ 2 * context.resources.getDimensionPixelSize(R.dimen.bubble_manage_button_margin)
+ val pointerWidth = context.resources.getDimensionPixelSize(R.dimen.bubble_pointer_width)
+
+ val expectedExpandedViewY =
+ positioner.availableRect.bottom -
+ manageButtonPlusMargin -
+ positioner.getExpandedViewHeightForLargeScreen() -
+ pointerWidth
+
+ // Bubbles are bottom aligned on portrait, large tablet
+ assertThat(positioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
+ .isEqualTo(expectedExpandedViewY)
+ }
+
+ private val defaultYPosition: Float
+ /**
+ * Calculates the Y position bubbles should be placed based on the config. Based on the
+ * calculations in [BubblePositioner.getDefaultStartPosition] and
+ * [BubbleStackView.RelativeStackPosition].
+ */
+ get() {
+ val isTablet = positioner.isLargeScreen
+
+ // On tablet the position is centered, on phone it is an offset from the top.
+ val desiredY =
+ if (isTablet) {
+ positioner.screenRect.height() / 2f - positioner.bubbleSize / 2f
+ } else {
+ context.resources
+ .getDimensionPixelOffset(R.dimen.bubble_stack_starting_offset_y)
+ .toFloat()
+ }
+ // Since we're visually centering the bubbles on tablet, use total screen height rather
+ // than the available height.
+ val height =
+ if (isTablet) {
+ positioner.screenRect.height()
+ } else {
+ positioner.availableRect.height()
+ }
+ val offsetPercent = (desiredY / height).coerceIn(0f, 1f)
+ val allowableStackRegion =
+ positioner.getAllowableStackPositionRegion(1 /* bubbleCount */)
+ return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent
+ }
+}
diff --git a/libs/WindowManager/Shell/multivalentTestsForDevice b/libs/WindowManager/Shell/multivalentTestsForDevice
new file mode 120000
index 000000000000..20ee34ada103
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTestsForDevice
@@ -0,0 +1 @@
+multivalentTests \ No newline at end of file
diff --git a/libs/WindowManager/Shell/multivalentTestsForDeviceless b/libs/WindowManager/Shell/multivalentTestsForDeviceless
new file mode 120000
index 000000000000..20ee34ada103
--- /dev/null
+++ b/libs/WindowManager/Shell/multivalentTestsForDeviceless
@@ -0,0 +1 @@
+multivalentTests \ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index 81d963877e4c..bb433dbbd2ce 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -176,6 +176,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private StatusBarCustomizer mCustomizer;
private boolean mTrackingLatency;
+ // Keep previous navigation type before remove mBackNavigationInfo.
+ @BackNavigationInfo.BackTargetType
+ private int mPreviousNavigationType;
+
public BackAnimationController(
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
@@ -871,6 +875,7 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mShellBackAnimationRegistry.resetDefaultCrossActivity();
cancelLatencyTracking();
if (mBackNavigationInfo != null) {
+ mPreviousNavigationType = mBackNavigationInfo.getType();
mBackNavigationInfo.onBackNavigationFinished(triggerBack);
mBackNavigationInfo = null;
}
@@ -983,7 +988,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mShellExecutor.execute(
() -> {
if (!mShellBackAnimationRegistry.cancel(
- mBackNavigationInfo.getType())) {
+ mBackNavigationInfo != null
+ ? mBackNavigationInfo.getType()
+ : mPreviousNavigationType)) {
return;
}
if (!mBackGestureStarted) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
index 80fc3a867d48..ac2a1c867462 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/CrossTaskBackAnimation.java
@@ -136,6 +136,9 @@ public class CrossTaskBackAnimation extends ShellBackAnimation {
mStartTaskRect.set(mClosingTarget.windowConfiguration.getBounds());
mStartTaskRect.offsetTo(0, 0);
+ // inset bottom in case of pinned taskbar being present
+ mStartTaskRect.inset(0, 0, 0, mClosingTarget.contentInsets.bottom);
+
// Draw background.
mBackground.ensureBackground(mClosingTarget.windowConfiguration.getBounds(),
BACKGROUNDCOLOR, mTransaction);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index 8c861c63a70d..bf783e6af36f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -197,60 +197,61 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (mType == TYPE_ENTER_PIP_FROM_SPLIT) {
- return animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
- finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
- } else if (mType == TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING) {
- return animateEnterPipFromActivityEmbedding(
- info, startTransaction, finishTransaction, finishCallback);
- } else if (mType == TYPE_DISPLAY_AND_SPLIT_CHANGE) {
- return false;
- } else if (mType == TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) {
- final boolean handledToPip = animateOpenIntentWithRemoteAndPip(
- info, startTransaction, finishTransaction, finishCallback);
- // Consume the transition on remote handler if the leftover handler already handle
- // this transition. And if it cannot, the transition will be handled by remote
- // handler, so don't consume here.
- // Need to check leftOverHandler as it may change in
- // #animateOpenIntentWithRemoteAndPip
- if (handledToPip && mHasRequestToRemote
- && mLeftoversHandler != mPlayer.getRemoteTransitionHandler()) {
- mPlayer.getRemoteTransitionHandler().onTransitionConsumed(
- transition, false, null);
- }
- return handledToPip;
- } else if (mType == TYPE_RECENTS_DURING_SPLIT) {
- for (int i = info.getChanges().size() - 1; i >= 0; --i) {
- final TransitionInfo.Change change = info.getChanges().get(i);
- // Pip auto-entering info might be appended to recent transition like pressing
- // home-key in 3-button navigation. This offers split handler the opportunity to
- // handle split to pip animation.
- if (mPipHandler.isEnteringPip(change, info.getType())
- && mSplitHandler.getSplitItemPosition(change.getLastParent())
- != SPLIT_POSITION_UNDEFINED) {
- return animateEnterPipFromSplit(
- this, info, startTransaction, finishTransaction, finishCallback,
- mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ switch (mType) {
+ case TYPE_ENTER_PIP_FROM_SPLIT:
+ return animateEnterPipFromSplit(this, info, startTransaction, finishTransaction,
+ finishCallback, mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING:
+ return animateEnterPipFromActivityEmbedding(
+ info, startTransaction, finishTransaction, finishCallback);
+ case TYPE_DISPLAY_AND_SPLIT_CHANGE:
+ return false;
+ case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE:
+ final boolean handledToPip = animateOpenIntentWithRemoteAndPip(
+ info, startTransaction, finishTransaction, finishCallback);
+ // Consume the transition on remote handler if the leftover handler already
+ // handle this transition. And if it cannot, the transition will be handled by
+ // remote handler, so don't consume here.
+ // Need to check leftOverHandler as it may change in
+ // #animateOpenIntentWithRemoteAndPip
+ if (handledToPip && mHasRequestToRemote
+ && mLeftoversHandler != mPlayer.getRemoteTransitionHandler()) {
+ mPlayer.getRemoteTransitionHandler().onTransitionConsumed(
+ transition, false, null);
+ }
+ return handledToPip;
+ case TYPE_RECENTS_DURING_SPLIT:
+ for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+ final TransitionInfo.Change change = info.getChanges().get(i);
+ // Pip auto-entering info might be appended to recent transition like
+ // pressing home-key in 3-button navigation. This offers split handler the
+ // opportunity to handle split to pip animation.
+ if (mPipHandler.isEnteringPip(change, info.getType())
+ && mSplitHandler.getSplitItemPosition(change.getLastParent())
+ != SPLIT_POSITION_UNDEFINED) {
+ return animateEnterPipFromSplit(
+ this, info, startTransaction, finishTransaction, finishCallback,
+ mPlayer, mMixedHandler, mPipHandler, mSplitHandler);
+ }
}
- }
- return animateRecentsDuringSplit(
- info, startTransaction, finishTransaction, finishCallback);
- } else if (mType == TYPE_KEYGUARD) {
- return animateKeyguard(this, info, startTransaction, finishTransaction,
- finishCallback, mKeyguardHandler, mPipHandler);
- } else if (mType == TYPE_RECENTS_DURING_KEYGUARD) {
- return animateRecentsDuringKeyguard(
- info, startTransaction, finishTransaction, finishCallback);
- } else if (mType == TYPE_RECENTS_DURING_DESKTOP) {
- return animateRecentsDuringDesktop(
- info, startTransaction, finishTransaction, finishCallback);
- } else if (mType == TYPE_UNFOLD) {
- return animateUnfold(
- info, startTransaction, finishTransaction, finishCallback);
- } else {
- throw new IllegalStateException(
- "Starting mixed animation without a known mixed type? " + mType);
+ return animateRecentsDuringSplit(
+ info, startTransaction, finishTransaction, finishCallback);
+ case TYPE_KEYGUARD:
+ return animateKeyguard(this, info, startTransaction, finishTransaction,
+ finishCallback, mKeyguardHandler, mPipHandler);
+ case TYPE_RECENTS_DURING_KEYGUARD:
+ return animateRecentsDuringKeyguard(
+ info, startTransaction, finishTransaction, finishCallback);
+ case TYPE_RECENTS_DURING_DESKTOP:
+ return animateRecentsDuringDesktop(
+ info, startTransaction, finishTransaction, finishCallback);
+ case TYPE_UNFOLD:
+ return animateUnfold(
+ info, startTransaction, finishTransaction, finishCallback);
+ default:
+ throw new IllegalStateException(
+ "Starting mixed animation without a known mixed type? " + mType);
}
}
@@ -457,79 +458,100 @@ public class DefaultMixedHandler implements Transitions.TransitionHandler,
@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- if (mType == TYPE_DISPLAY_AND_SPLIT_CHANGE) {
- // queue since no actual animation.
- } else if (mType == TYPE_ENTER_PIP_FROM_SPLIT) {
- if (mAnimType == ANIM_TYPE_GOING_HOME) {
- boolean ended = mSplitHandler.end();
- // If split couldn't end (because it is remote), then don't end everything else
- // since we have to play out the animation anyways.
- if (!ended) return;
- mPipHandler.end();
- if (mLeftoversHandler != null) {
- mLeftoversHandler.mergeAnimation(
- transition, info, t, mergeTarget, finishCallback);
+ switch (mType) {
+ case TYPE_DISPLAY_AND_SPLIT_CHANGE:
+ // queue since no actual animation.
+ break;
+ case TYPE_ENTER_PIP_FROM_SPLIT:
+ if (mAnimType == ANIM_TYPE_GOING_HOME) {
+ boolean ended = mSplitHandler.end();
+ // If split couldn't end (because it is remote), then don't end everything
+ // else since we have to play out the animation anyways.
+ if (!ended) return;
+ mPipHandler.end();
+ if (mLeftoversHandler != null) {
+ mLeftoversHandler.mergeAnimation(
+ transition, info, t, mergeTarget, finishCallback);
+ }
+ } else {
+ mPipHandler.end();
}
- } else {
+ break;
+ case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING:
mPipHandler.end();
- }
- } else if (mType == TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING) {
- mPipHandler.end();
- mActivityEmbeddingController.mergeAnimation(transition, info, t, mergeTarget,
- finishCallback);
- } else if (mType == TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) {
- mPipHandler.end();
- if (mLeftoversHandler != null) {
- mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
+ mActivityEmbeddingController.mergeAnimation(transition, info, t, mergeTarget,
finishCallback);
- }
- } else if (mType == TYPE_RECENTS_DURING_SPLIT) {
- if (mSplitHandler.isPendingEnter(transition)) {
- // Recents -> enter-split means that we are switching from one pair to
- // another pair.
- mAnimType = ANIM_TYPE_PAIR_TO_PAIR;
- }
- mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
- } else if (mType == TYPE_KEYGUARD) {
- mKeyguardHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
- } else if (mType == TYPE_RECENTS_DURING_KEYGUARD) {
- if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
- DefaultMixedHandler.handoverTransitionLeashes(mInfo, info, t, mFinishT);
- if (animateKeyguard(
- this, info, t, mFinishT, mFinishCB, mKeyguardHandler, mPipHandler)) {
- finishCallback.onTransitionFinished(null);
+ break;
+ case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE:
+ mPipHandler.end();
+ if (mLeftoversHandler != null) {
+ mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget,
+ finishCallback);
}
- }
- mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
- } else if (mType == TYPE_RECENTS_DURING_DESKTOP) {
- mLeftoversHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
- } else if (mType == TYPE_UNFOLD) {
- mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
- } else {
- throw new IllegalStateException(
- "Playing a mixed transition with unknown type? " + mType);
+ break;
+ case TYPE_RECENTS_DURING_SPLIT:
+ if (mSplitHandler.isPendingEnter(transition)) {
+ // Recents -> enter-split means that we are switching from one pair to
+ // another pair.
+ mAnimType = ANIM_TYPE_PAIR_TO_PAIR;
+ }
+ mLeftoversHandler.mergeAnimation(
+ transition, info, t, mergeTarget, finishCallback);
+ break;
+ case TYPE_KEYGUARD:
+ mKeyguardHandler.mergeAnimation(
+ transition, info, t, mergeTarget, finishCallback);
+ break;
+ case TYPE_RECENTS_DURING_KEYGUARD:
+ if ((info.getFlags() & TRANSIT_FLAG_KEYGUARD_UNOCCLUDING) != 0) {
+ DefaultMixedHandler.handoverTransitionLeashes(mInfo, info, t, mFinishT);
+ if (animateKeyguard(this, info, t, mFinishT, mFinishCB, mKeyguardHandler,
+ mPipHandler)) {
+ finishCallback.onTransitionFinished(null);
+ }
+ }
+ mLeftoversHandler.mergeAnimation(
+ transition, info, t, mergeTarget, finishCallback);
+ break;
+ case TYPE_RECENTS_DURING_DESKTOP:
+ mLeftoversHandler.mergeAnimation(
+ transition, info, t, mergeTarget, finishCallback);
+ break;
+ case TYPE_UNFOLD:
+ mUnfoldHandler.mergeAnimation(transition, info, t, mergeTarget, finishCallback);
+ break;
+ default:
+ throw new IllegalStateException(
+ "Playing a mixed transition with unknown type? " + mType);
}
}
void onTransitionConsumed(
@NonNull IBinder transition, boolean aborted,
@Nullable SurfaceControl.Transaction finishT) {
- if (mType == TYPE_ENTER_PIP_FROM_SPLIT) {
- mPipHandler.onTransitionConsumed(transition, aborted, finishT);
- } else if (mType == TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING) {
- mPipHandler.onTransitionConsumed(transition, aborted, finishT);
- mActivityEmbeddingController.onTransitionConsumed(transition, aborted, finishT);
- } else if (mType == TYPE_RECENTS_DURING_SPLIT) {
- mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
- } else if (mType == TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE) {
- mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
- } else if (mType == TYPE_KEYGUARD) {
- mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
- } else if (mType == TYPE_RECENTS_DURING_DESKTOP) {
- mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
- } else if (mType == TYPE_UNFOLD) {
- mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
+ switch (mType) {
+ case TYPE_ENTER_PIP_FROM_SPLIT:
+ mPipHandler.onTransitionConsumed(transition, aborted, finishT);
+ break;
+ case TYPE_ENTER_PIP_FROM_ACTIVITY_EMBEDDING:
+ mPipHandler.onTransitionConsumed(transition, aborted, finishT);
+ mActivityEmbeddingController.onTransitionConsumed(transition, aborted, finishT);
+ break;
+ case TYPE_RECENTS_DURING_SPLIT:
+ case TYPE_OPTIONS_REMOTE_AND_PIP_CHANGE:
+ case TYPE_RECENTS_DURING_DESKTOP:
+ mLeftoversHandler.onTransitionConsumed(transition, aborted, finishT);
+ break;
+ case TYPE_KEYGUARD:
+ mKeyguardHandler.onTransitionConsumed(transition, aborted, finishT);
+ break;
+ case TYPE_UNFOLD:
+ mUnfoldHandler.onTransitionConsumed(transition, aborted, finishT);
+ break;
+ default:
+ break;
}
+
if (mHasRequestToRemote) {
mPlayer.getRemoteTransitionHandler().onTransitionConsumed(
transition, aborted, finishT);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
deleted file mode 100644
index 6ebee730756e..000000000000
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubblePositionerTest.java
+++ /dev/null
@@ -1,602 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.wm.shell.bubbles;
-
-import static com.android.wm.shell.bubbles.BubblePositioner.MAX_HEIGHT;
-
-import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.util.concurrent.MoreExecutors.directExecutor;
-
-import static org.mockito.Mockito.mock;
-
-import android.content.Intent;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Insets;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.os.UserHandle;
-import android.testing.AndroidTestingRunner;
-import android.view.WindowManager;
-
-import androidx.test.filters.SmallTest;
-
-import com.android.wm.shell.R;
-import com.android.wm.shell.ShellTestCase;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests operations and the resulting state managed by {@link BubblePositioner}.
- */
-@SmallTest
-@RunWith(AndroidTestingRunner.class)
-public class BubblePositionerTest extends ShellTestCase {
-
- private BubblePositioner mPositioner;
-
- @Before
- public void setUp() {
- WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- mPositioner = new BubblePositioner(mContext, windowManager);
- }
-
- @Test
- public void testUpdate() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1000, 1200);
- Rect availableRect = new Rect(screenBounds);
- availableRect.inset(insets);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.getAvailableRect()).isEqualTo(availableRect);
- assertThat(mPositioner.isLandscape()).isFalse();
- assertThat(mPositioner.isLargeScreen()).isFalse();
- assertThat(mPositioner.getInsets()).isEqualTo(insets);
- }
-
- @Test
- public void testShowBubblesVertically_phonePortrait() {
- DeviceConfig deviceConfig = new ConfigBuilder().build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.showBubblesVertically()).isFalse();
- }
-
- @Test
- public void testShowBubblesVertically_phoneLandscape() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLandscape().build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.isLandscape()).isTrue();
- assertThat(mPositioner.showBubblesVertically()).isTrue();
- }
-
- @Test
- public void testShowBubblesVertically_tablet() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.showBubblesVertically()).isTrue();
- }
-
- /** If a resting position hasn't been set, calling it will return the default position. */
- @Test
- public void testGetRestingPosition_returnsDefaultPosition() {
- DeviceConfig deviceConfig = new ConfigBuilder().build();
- mPositioner.update(deviceConfig);
-
- PointF restingPosition = mPositioner.getRestingPosition();
- PointF defaultPosition = mPositioner.getDefaultStartPosition();
-
- assertThat(restingPosition).isEqualTo(defaultPosition);
- }
-
- /** If a resting position has been set, it'll return that instead of the default position. */
- @Test
- public void testGetRestingPosition_returnsRestingPosition() {
- DeviceConfig deviceConfig = new ConfigBuilder().build();
- mPositioner.update(deviceConfig);
-
- PointF restingPosition = new PointF(100, 100);
- mPositioner.setRestingPosition(restingPosition);
-
- assertThat(mPositioner.getRestingPosition()).isEqualTo(restingPosition);
- }
-
- /** Test that the default resting position on phone is in upper left. */
- @Test
- public void testGetRestingPosition_bubble_onPhone() {
- DeviceConfig deviceConfig = new ConfigBuilder().build();
- mPositioner.update(deviceConfig);
-
- RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- PointF restingPosition = mPositioner.getRestingPosition();
-
- assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left);
- assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
- }
-
- @Test
- public void testGetRestingPosition_bubble_onPhone_RTL() {
- DeviceConfig deviceConfig = new ConfigBuilder().setRtl().build();
- mPositioner.update(deviceConfig);
-
- RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- PointF restingPosition = mPositioner.getRestingPosition();
-
- assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right);
- assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
- }
-
- /** Test that the default resting position on tablet is middle left. */
- @Test
- public void testGetRestingPosition_chatBubble_onTablet() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build();
- mPositioner.update(deviceConfig);
-
- RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- PointF restingPosition = mPositioner.getRestingPosition();
-
- assertThat(restingPosition.x).isEqualTo(allowableStackRegion.left);
- assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
- }
-
- @Test
- public void testGetRestingPosition_chatBubble_onTablet_RTL() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
- mPositioner.update(deviceConfig);
-
- RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- PointF restingPosition = mPositioner.getRestingPosition();
-
- assertThat(restingPosition.x).isEqualTo(allowableStackRegion.right);
- assertThat(restingPosition.y).isEqualTo(getDefaultYPosition());
- }
-
- /** Test that the default resting position on tablet is middle right. */
- @Test
- public void testGetDefaultPosition_appBubble_onTablet() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().build();
- mPositioner.update(deviceConfig);
-
- RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- PointF startPosition = mPositioner.getDefaultStartPosition(true /* isAppBubble */);
-
- assertThat(startPosition.x).isEqualTo(allowableStackRegion.right);
- assertThat(startPosition.y).isEqualTo(getDefaultYPosition());
- }
-
- @Test
- public void testGetRestingPosition_appBubble_onTablet_RTL() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
- mPositioner.update(deviceConfig);
-
- RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- PointF startPosition = mPositioner.getDefaultStartPosition(true /* isAppBubble */);
-
- assertThat(startPosition.x).isEqualTo(allowableStackRegion.left);
- assertThat(startPosition.y).isEqualTo(getDefaultYPosition());
- }
-
- @Test
- public void testHasUserModifiedDefaultPosition_false() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse();
-
- mPositioner.setRestingPosition(mPositioner.getDefaultStartPosition());
-
- assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse();
- }
-
- @Test
- public void testHasUserModifiedDefaultPosition_true() {
- DeviceConfig deviceConfig = new ConfigBuilder().setLargeScreen().setRtl().build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.hasUserModifiedDefaultPosition()).isFalse();
-
- mPositioner.setRestingPosition(new PointF(0, 100));
-
- assertThat(mPositioner.hasUserModifiedDefaultPosition()).isTrue();
- }
-
- @Test
- public void testGetExpandedViewHeight_max() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(MAX_HEIGHT);
- }
-
- @Test
- public void testGetExpandedViewHeight_customHeight_valid() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- final int minHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_expanded_default_height);
- Bubble bubble = new Bubble("key",
- mock(ShortcutInfo.class),
- minHeight + 100 /* desiredHeight */,
- 0 /* desiredHeightResId */,
- "title",
- 0 /* taskId */,
- null /* locus */,
- true /* isDismissable */,
- directExecutor(),
- mock(Bubbles.BubbleMetadataFlagListener.class));
-
- // Ensure the height is the same as the desired value
- assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(
- bubble.getDesiredHeight(mContext));
- }
-
-
- @Test
- public void testGetExpandedViewHeight_customHeight_tooSmall() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Bubble bubble = new Bubble("key",
- mock(ShortcutInfo.class),
- 10 /* desiredHeight */,
- 0 /* desiredHeightResId */,
- "title",
- 0 /* taskId */,
- null /* locus */,
- true /* isDismissable */,
- directExecutor(),
- mock(Bubbles.BubbleMetadataFlagListener.class));
-
- // Ensure the height is the same as the minimum value
- final int minHeight = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_expanded_default_height);
- assertThat(mPositioner.getExpandedViewHeight(bubble)).isEqualTo(minHeight);
- }
-
- @Test
- public void testGetMaxExpandedViewHeight_onLargeTablet() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- int manageButtonHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height);
- int pointerWidth = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_pointer_width);
- int expandedViewPadding = mContext.getResources().getDimensionPixelSize(R
- .dimen.bubble_expanded_view_padding);
- float expectedHeight = 1800 - 2 * 20 - manageButtonHeight - pointerWidth
- - expandedViewPadding * 2;
- assertThat(((float) mPositioner.getMaxExpandedViewHeight(false /* isOverflow */)))
- .isWithin(0.1f).of(expectedHeight);
- }
-
- @Test
- public void testAreBubblesBottomAligned_largeScreen_true() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.areBubblesBottomAligned()).isTrue();
- }
-
- @Test
- public void testAreBubblesBottomAligned_largeScreen_false() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setLandscape()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.areBubblesBottomAligned()).isFalse();
- }
-
- @Test
- public void testAreBubblesBottomAligned_smallTablet_false() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setSmallTablet()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.areBubblesBottomAligned()).isFalse();
- }
-
- @Test
- public void testAreBubblesBottomAligned_phone_false() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- assertThat(mPositioner.areBubblesBottomAligned()).isFalse();
- }
-
- @Test
- public void testExpandedViewY_phoneLandscape() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLandscape()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- // This bubble will have max height so it'll always be top aligned
- assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
- .isEqualTo(mPositioner.getExpandedViewYTopAligned());
- }
-
- @Test
- public void testExpandedViewY_phonePortrait() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- // Always top aligned in phone portrait
- assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
- .isEqualTo(mPositioner.getExpandedViewYTopAligned());
- }
-
- @Test
- public void testExpandedViewY_smallTabletLandscape() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setSmallTablet()
- .setLandscape()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- // This bubble will have max height which is always top aligned on small tablets
- assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
- .isEqualTo(mPositioner.getExpandedViewYTopAligned());
- }
-
- @Test
- public void testExpandedViewY_smallTabletPortrait() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setSmallTablet()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- // This bubble will have max height which is always top aligned on small tablets
- assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
- .isEqualTo(mPositioner.getExpandedViewYTopAligned());
- }
-
- @Test
- public void testExpandedViewY_largeScreenLandscape() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setLandscape()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- // This bubble will have max height which is always top aligned on landscape, large tablet
- assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
- .isEqualTo(mPositioner.getExpandedViewYTopAligned());
- }
-
- @Test
- public void testExpandedViewY_largeScreenPortrait() {
- Insets insets = Insets.of(10, 20, 5, 15);
- Rect screenBounds = new Rect(0, 0, 1800, 2600);
-
- DeviceConfig deviceConfig = new ConfigBuilder()
- .setLargeScreen()
- .setInsets(insets)
- .setScreenBounds(screenBounds)
- .build();
- mPositioner.update(deviceConfig);
-
- Intent intent = new Intent(Intent.ACTION_VIEW).setPackage(mContext.getPackageName());
- Bubble bubble = Bubble.createAppBubble(intent, new UserHandle(1), null, directExecutor());
-
- int manageButtonHeight =
- mContext.getResources().getDimensionPixelSize(R.dimen.bubble_manage_button_height);
- int manageButtonPlusMargin = manageButtonHeight + 2
- * mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_manage_button_margin);
- int pointerWidth = mContext.getResources().getDimensionPixelSize(
- R.dimen.bubble_pointer_width);
-
- final float expectedExpandedViewY = mPositioner.getAvailableRect().bottom
- - manageButtonPlusMargin
- - mPositioner.getExpandedViewHeightForLargeScreen()
- - pointerWidth;
-
- // Bubbles are bottom aligned on portrait, large tablet
- assertThat(mPositioner.getExpandedViewY(bubble, 0f /* bubblePosition */))
- .isEqualTo(expectedExpandedViewY);
- }
-
- /**
- * Calculates the Y position bubbles should be placed based on the config. Based on
- * the calculations in {@link BubblePositioner#getDefaultStartPosition()} and
- * {@link BubbleStackView.RelativeStackPosition}.
- */
- private float getDefaultYPosition() {
- final boolean isTablet = mPositioner.isLargeScreen();
-
- // On tablet the position is centered, on phone it is an offset from the top.
- final float desiredY = isTablet
- ? mPositioner.getScreenRect().height() / 2f - (mPositioner.getBubbleSize() / 2f)
- : mContext.getResources().getDimensionPixelOffset(
- R.dimen.bubble_stack_starting_offset_y);
- // Since we're visually centering the bubbles on tablet, use total screen height rather
- // than the available height.
- final float height = isTablet
- ? mPositioner.getScreenRect().height()
- : mPositioner.getAvailableRect().height();
- float offsetPercent = desiredY / height;
- offsetPercent = Math.max(0f, Math.min(1f, offsetPercent));
- final RectF allowableStackRegion =
- mPositioner.getAllowableStackPositionRegion(1 /* bubbleCount */);
- return allowableStackRegion.top + allowableStackRegion.height() * offsetPercent;
- }
-
- /**
- * Sets up window manager to return config values based on what you need for the test.
- * By default it sets up a portrait phone without any insets.
- */
- private static class ConfigBuilder {
- private Rect mScreenBounds = new Rect(0, 0, 1000, 2000);
- private boolean mIsLargeScreen = false;
- private boolean mIsSmallTablet = false;
- private boolean mIsLandscape = false;
- private boolean mIsRtl = false;
- private Insets mInsets = Insets.of(0, 0, 0, 0);
-
- public ConfigBuilder setScreenBounds(Rect screenBounds) {
- mScreenBounds = screenBounds;
- return this;
- }
-
- public ConfigBuilder setLargeScreen() {
- mIsLargeScreen = true;
- return this;
- }
-
- public ConfigBuilder setSmallTablet() {
- mIsSmallTablet = true;
- return this;
- }
-
- public ConfigBuilder setLandscape() {
- mIsLandscape = true;
- return this;
- }
-
- public ConfigBuilder setRtl() {
- mIsRtl = true;
- return this;
- }
-
- public ConfigBuilder setInsets(Insets insets) {
- mInsets = insets;
- return this;
- }
-
- private DeviceConfig build() {
- return new DeviceConfig(mIsLargeScreen, mIsSmallTablet, mIsLandscape, mIsRtl,
- mScreenBounds, mInsets);
- }
- }
-}
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 6c3172a26751..d58c872dbc56 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -56,6 +56,7 @@ std::optional<std::int32_t> render_ahead() {
bool Properties::debugLayersUpdates = false;
bool Properties::debugOverdraw = false;
+bool Properties::debugTraceGpuResourceCategories = false;
bool Properties::showDirtyRegions = false;
bool Properties::skipEmptyFrames = true;
bool Properties::useBufferAge = true;
@@ -151,10 +152,12 @@ bool Properties::load() {
skpCaptureEnabled = debuggingEnabled && base::GetBoolProperty(PROPERTY_CAPTURE_SKP_ENABLED, false);
- SkAndroidFrameworkTraceUtil::setEnableTracing(
- base::GetBoolProperty(PROPERTY_SKIA_TRACING_ENABLED, false));
+ bool skiaBroadTracing = base::GetBoolProperty(PROPERTY_SKIA_TRACING_ENABLED, false);
+ SkAndroidFrameworkTraceUtil::setEnableTracing(skiaBroadTracing);
SkAndroidFrameworkTraceUtil::setUsePerfettoTrackEvents(
base::GetBoolProperty(PROPERTY_SKIA_USE_PERFETTO_TRACK_EVENTS, false));
+ debugTraceGpuResourceCategories =
+ base::GetBoolProperty(PROPERTY_TRACE_GPU_RESOURCES, skiaBroadTracing);
runningInEmulator = base::GetBoolProperty(PROPERTY_IS_EMULATOR, false);
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index bca57e9e4678..b956facf6f90 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -143,6 +143,15 @@ enum DebugLevel {
#define PROPERTY_CAPTURE_SKP_ENABLED "debug.hwui.capture_skp_enabled"
/**
+ * Might split Skia's GPU resource utilization into separate tracing tracks (slow).
+ *
+ * Aggregate total and purgeable numbers will still be reported under a "misc" track when this is
+ * disabled, they just won't be split into distinct categories. Results may vary depending on GPU
+ * backend/API, and the category mappings defined in ATraceMemoryDump's hardcoded sResourceMap.
+ */
+#define PROPERTY_TRACE_GPU_RESOURCES "debug.hwui.trace_gpu_resources"
+
+/**
* Allows broad recording of Skia drawing commands.
*
* If disabled, a very minimal set of trace events *may* be recorded.
@@ -254,6 +263,7 @@ public:
static bool debugLayersUpdates;
static bool debugOverdraw;
+ static bool debugTraceGpuResourceCategories;
static bool showDirtyRegions;
// TODO: Remove after stabilization period
static bool skipEmptyFrames;
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
index 234f42d79cb7..756b937f7de3 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -20,6 +20,8 @@
#include <cstring>
+#include "GrDirectContext.h"
+
namespace android {
namespace uirenderer {
namespace skiapipeline {
@@ -114,8 +116,16 @@ void ATraceMemoryDump::startFrame() {
/**
* logTraces reads from mCurrentValues and logs the counters with ATRACE.
+ *
+ * gpuMemoryIsAlreadyInDump must be true if GrDirectContext::dumpMemoryStatistics(...) was called
+ * with this tracer, false otherwise. Leaving this false allows this function to quickly query total
+ * and purgable GPU memory without the caller having to spend time in
+ * GrDirectContext::dumpMemoryStatistics(...) first, which iterates over every resource in the GPU
+ * cache. This can save significant time, but buckets all GPU memory into a single "misc" track,
+ * which may be a loss of granularity depending on the GPU backend and the categories defined in
+ * sResourceMap.
*/
-void ATraceMemoryDump::logTraces() {
+void ATraceMemoryDump::logTraces(bool gpuMemoryIsAlreadyInDump, GrDirectContext* grContext) {
// Accumulate data from last dumpName
recordAndResetCountersIfNeeded("");
uint64_t hwui_all_frame_memory = 0;
@@ -126,6 +136,20 @@ void ATraceMemoryDump::logTraces() {
ATRACE_INT64((std::string("Purgeable ") + it.first).c_str(), it.second.purgeableMemory);
}
}
+
+ if (!gpuMemoryIsAlreadyInDump && grContext) {
+ // Total GPU memory
+ int gpuResourceCount;
+ size_t gpuResourceBytes;
+ grContext->getResourceCacheUsage(&gpuResourceCount, &gpuResourceBytes);
+ hwui_all_frame_memory += (uint64_t)gpuResourceBytes;
+ ATRACE_INT64("HWUI Misc Memory", gpuResourceBytes);
+
+ // Purgable subset of GPU memory
+ size_t purgeableGpuResourceBytes = grContext->getResourceCachePurgeableBytes();
+ ATRACE_INT64("Purgeable HWUI Misc Memory", purgeableGpuResourceBytes);
+ }
+
ATRACE_INT64("HWUI All Memory", hwui_all_frame_memory);
}
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.h b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
index 4592711dd5b5..777d1a2ddb5b 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.h
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.h
@@ -16,6 +16,7 @@
#pragma once
+#include <GrDirectContext.h>
#include <SkString.h>
#include <SkTraceMemoryDump.h>
@@ -50,7 +51,7 @@ public:
void startFrame();
- void logTraces();
+ void logTraces(bool gpuMemoryIsAlreadyInDump, GrDirectContext* grContext);
private:
std::string mLastDumpName;
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 30d461271c89..eb4d4948dc53 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -269,13 +269,14 @@ void CacheManager::onFrameCompleted() {
cancelDestroyContext();
mFrameCompletions.next() = systemTime(CLOCK_MONOTONIC);
if (ATRACE_ENABLED()) {
+ ATRACE_NAME("dumpingMemoryStatistics");
static skiapipeline::ATraceMemoryDump tracer;
tracer.startFrame();
SkGraphics::DumpMemoryStatistics(&tracer);
- if (mGrContext) {
+ if (mGrContext && Properties::debugTraceGpuResourceCategories) {
mGrContext->dumpMemoryStatistics(&tracer);
}
- tracer.logTraces();
+ tracer.logTraces(Properties::debugTraceGpuResourceCategories, mGrContext.get());
}
}
diff --git a/lint-baseline.xml b/lint-baseline.xml
index 79b21551a76e..660884a18010 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NonUserGetterCalled"
@@ -433,7 +433,7 @@
<issue
id="NonUserGetterCalled"
message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. "
- errorLine1=" boolean cap = System.getInt(resolver, System.TEXT_AUTO_CAPS, 1) > 0;"
+ errorLine1=" boolean cap = System.getInt(resolver, System.TEXT_AUTO_CAPS, 1) &gt; 0;"
errorLine2=" ~~~~~~">
<location
file="frameworks/base/core/java/android/text/method/TextKeyListener.java"
@@ -444,7 +444,7 @@
<issue
id="NonUserGetterCalled"
message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. "
- errorLine1=" boolean text = System.getInt(resolver, System.TEXT_AUTO_REPLACE, 1) > 0;"
+ errorLine1=" boolean text = System.getInt(resolver, System.TEXT_AUTO_REPLACE, 1) &gt; 0;"
errorLine2=" ~~~~~~">
<location
file="frameworks/base/core/java/android/text/method/TextKeyListener.java"
@@ -455,7 +455,7 @@
<issue
id="NonUserGetterCalled"
message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. "
- errorLine1=" boolean period = System.getInt(resolver, System.TEXT_AUTO_PUNCTUATE, 1) > 0;"
+ errorLine1=" boolean period = System.getInt(resolver, System.TEXT_AUTO_PUNCTUATE, 1) &gt; 0;"
errorLine2=" ~~~~~~">
<location
file="frameworks/base/core/java/android/text/method/TextKeyListener.java"
@@ -466,7 +466,7 @@
<issue
id="NonUserGetterCalled"
message="`android.provider.Settings.System#getInt()` called from system process. Please call `android.provider.Settings.System#getIntForUser()` instead. "
- errorLine1=" boolean pw = System.getInt(resolver, System.TEXT_SHOW_PASSWORD, 1) > 0;"
+ errorLine1=" boolean pw = System.getInt(resolver, System.TEXT_SHOW_PASSWORD, 1) &gt; 0;"
errorLine2=" ~~~~~~">
<location
file="frameworks/base/core/java/android/text/method/TextKeyListener.java"
@@ -562,4 +562,4 @@
column="74"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 89792c7638cb..9616b5d44540 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -48,6 +48,7 @@ import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -141,7 +142,9 @@ public final class MediaRouter2 {
* dispatch. This is only used to determine what callback a route should be assigned to (added,
* removed, changed) in {@link #dispatchFilteredRoutesUpdatedOnHandler(List)}.
*/
- private volatile ArrayMap<String, MediaRoute2Info> mPreviousRoutes = new ArrayMap<>();
+ private volatile ArrayMap<String, MediaRoute2Info> mPreviousFilteredRoutes = new ArrayMap<>();
+
+ private final Map<String, MediaRoute2Info> mPreviousUnfilteredRoutes = new ArrayMap<>();
/**
* Stores the latest copy of exposed routes after filtering, sorting, and deduplication. Can be
@@ -282,6 +285,8 @@ public final class MediaRouter2 {
MediaRouter2 instance = sAppToProxyRouterMap.get(key);
if (instance == null) {
instance = new MediaRouter2(context, looper, clientPackageName, user);
+ // Register proxy router after instantiation to avoid race condition.
+ ((ProxyMediaRouter2Impl) instance.mImpl).registerProxyRouter();
sAppToProxyRouterMap.put(key, instance);
}
return instance;
@@ -368,6 +373,7 @@ public final class MediaRouter2 {
new SystemRoutingController(
ProxyMediaRouter2Impl.getSystemSessionInfoImpl(
mMediaRouterService, clientPackageName));
+
mImpl = new ProxyMediaRouter2Impl(context, clientPackageName, user);
}
@@ -713,7 +719,7 @@ public final class MediaRouter2 {
mImpl.transfer(
controller.getRoutingSessionInfo(),
route,
- android.os.Process.myUserHandle(),
+ Process.myUserHandle(),
mContext.getPackageName());
}
@@ -883,7 +889,7 @@ public final class MediaRouter2 {
newRoutes.stream().map(MediaRoute2Info::getId).collect(Collectors.toSet());
for (MediaRoute2Info route : newRoutes) {
- MediaRoute2Info prevRoute = mPreviousRoutes.get(route.getId());
+ MediaRoute2Info prevRoute = mPreviousFilteredRoutes.get(route.getId());
if (prevRoute == null) {
addedRoutes.add(route);
} else if (!prevRoute.equals(route)) {
@@ -891,21 +897,21 @@ public final class MediaRouter2 {
}
}
- for (int i = 0; i < mPreviousRoutes.size(); i++) {
- if (!newRouteIds.contains(mPreviousRoutes.keyAt(i))) {
- removedRoutes.add(mPreviousRoutes.valueAt(i));
+ for (int i = 0; i < mPreviousFilteredRoutes.size(); i++) {
+ if (!newRouteIds.contains(mPreviousFilteredRoutes.keyAt(i))) {
+ removedRoutes.add(mPreviousFilteredRoutes.valueAt(i));
}
}
// update previous routes
for (MediaRoute2Info route : removedRoutes) {
- mPreviousRoutes.remove(route.getId());
+ mPreviousFilteredRoutes.remove(route.getId());
}
for (MediaRoute2Info route : addedRoutes) {
- mPreviousRoutes.put(route.getId(), route);
+ mPreviousFilteredRoutes.put(route.getId(), route);
}
for (MediaRoute2Info route : changedRoutes) {
- mPreviousRoutes.put(route.getId(), route);
+ mPreviousFilteredRoutes.put(route.getId(), route);
}
if (!addedRoutes.isEmpty()) {
@@ -924,6 +930,27 @@ public final class MediaRouter2 {
}
}
+ void dispatchControllerUpdatedIfNeededOnHandler(Map<String, MediaRoute2Info> routesMap) {
+ List<RoutingController> controllers = getControllers();
+ for (RoutingController controller : controllers) {
+
+ for (String selectedRoute : controller.getRoutingSessionInfo().getSelectedRoutes()) {
+ if (routesMap.containsKey(selectedRoute)
+ && mPreviousUnfilteredRoutes.containsKey(selectedRoute)) {
+ MediaRoute2Info currentRoute = routesMap.get(selectedRoute);
+ MediaRoute2Info oldRoute = mPreviousUnfilteredRoutes.get(selectedRoute);
+ if (!currentRoute.equals(oldRoute)) {
+ notifyControllerUpdated(controller);
+ break;
+ }
+ }
+ }
+ }
+
+ mPreviousUnfilteredRoutes.clear();
+ mPreviousUnfilteredRoutes.putAll(routesMap);
+ }
+
void updateRoutesOnHandler(List<MediaRoute2Info> newRoutes) {
synchronized (mLock) {
mRoutes.clear();
@@ -945,6 +972,11 @@ public final class MediaRouter2 {
MediaRouter2::dispatchFilteredRoutesUpdatedOnHandler,
this,
mFilteredRoutes));
+ mHandler.sendMessage(
+ obtainMessage(
+ MediaRouter2::dispatchControllerUpdatedIfNeededOnHandler,
+ this,
+ new HashMap<>(mRoutes)));
}
/**
@@ -1528,7 +1560,7 @@ public final class MediaRouter2 {
UserHandle transferInitiatorUserHandle = sessionInfo.getTransferInitiatorUserHandle();
String transferInitiatorPackageName = sessionInfo.getTransferInitiatorPackageName();
- return Objects.equals(android.os.Process.myUserHandle(), transferInitiatorUserHandle)
+ return Objects.equals(Process.myUserHandle(), transferInitiatorUserHandle)
&& Objects.equals(mContext.getPackageName(), transferInitiatorPackageName);
}
@@ -2153,18 +2185,19 @@ public final class MediaRouter2 {
mClientUser = user;
mClientPackageName = clientPackageName;
mClient = new Client();
+ mDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
+ }
+ public void registerProxyRouter() {
try {
mMediaRouterService.registerProxyRouter(
mClient,
- context.getApplicationContext().getPackageName(),
- clientPackageName,
- user);
+ mContext.getApplicationContext().getPackageName(),
+ mClientPackageName,
+ mClientUser);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
-
- mDiscoveryPreference = RouteDiscoveryPreference.EMPTY;
}
@Override
@@ -2294,11 +2327,7 @@ public final class MediaRouter2 {
List<RoutingSessionInfo> sessionInfos = getRoutingSessions();
RoutingSessionInfo targetSession = sessionInfos.get(sessionInfos.size() - 1);
- transfer(
- targetSession,
- route,
- android.os.Process.myUserHandle(),
- mContext.getPackageName());
+ transfer(targetSession, route, Process.myUserHandle(), mContext.getPackageName());
}
@Override
@@ -3165,8 +3194,12 @@ public final class MediaRouter2 {
return;
}
- requestCreateController(controller, route, MANAGER_REQUEST_ID_NONE,
- android.os.Process.myUserHandle(), mContext.getPackageName());
+ requestCreateController(
+ controller,
+ route,
+ MANAGER_REQUEST_ID_NONE,
+ Process.myUserHandle(),
+ mContext.getPackageName());
}
@Override
diff --git a/media/java/android/media/projection/IMediaProjectionManager.aidl b/media/java/android/media/projection/IMediaProjectionManager.aidl
index a7ec6c692416..8ce1b6d5264d 100644
--- a/media/java/android/media/projection/IMediaProjectionManager.aidl
+++ b/media/java/android/media/projection/IMediaProjectionManager.aidl
@@ -37,31 +37,41 @@ interface IMediaProjectionManager {
const String EXTRA_PACKAGE_REUSING_GRANTED_CONSENT =
"extra_media_projection_package_reusing_consent";
+ /**
+ * Returns whether a combination of process UID and package has the projection permission.
+ *
+ * @param processUid the process UID as returned by {@link android.os.Process.myUid()}.
+ */
@UnsupportedAppUsage
- boolean hasProjectionPermission(int uid, String packageName);
+ boolean hasProjectionPermission(int processUid, String packageName);
/**
* Returns a new {@link IMediaProjection} instance associated with the given package.
+ *
+ * @param processUid the process UID as returned by {@link android.os.Process.myUid()}.
*/
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- IMediaProjection createProjection(int uid, String packageName, int type,
+ IMediaProjection createProjection(int processUid, String packageName, int type,
boolean permanentGrant);
/**
* Returns the current {@link IMediaProjection} instance associated with the given
- * package, or {@code null} if it is not possible to re-use the current projection.
+ * package and process UID, or {@code null} if it is not possible to re-use the current
+ * projection.
*
* <p>Should only be invoked when the user has reviewed consent for a re-used projection token.
* Requires that there is a prior session waiting for the user to review consent, and the given
* package details match those on the current projection.
*
* @see {@link #isCurrentProjection}
+ *
+ * @param processUid the process UID as returned by {@link android.os.Process.myUid()}.
*/
@EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- IMediaProjection getProjection(int uid, String packageName);
+ IMediaProjection getProjection(int processUid, String packageName);
/**
* Returns {@code true} if the given {@link IMediaProjection} corresponds to the current
@@ -162,8 +172,8 @@ interface IMediaProjectionManager {
*
* <p>Only used for emitting atoms.
*
- * @param hostUid The uid of the process requesting consent to capture, may be an app or
- * SystemUI.
+ * @param hostProcessUid The uid of the process requesting consent to capture, may be an
+ * app or SystemUI.
* @param sessionCreationSource Only set if the state is MEDIA_PROJECTION_STATE_INITIATED.
* Indicates the entry point for requesting the permission. Must be
* a valid state defined
@@ -172,49 +182,49 @@ interface IMediaProjectionManager {
@EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- oneway void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource);
+ oneway void notifyPermissionRequestInitiated(int hostProcessUid, int sessionCreationSource);
/**
* Notifies system server that the permission request was displayed.
*
* <p>Only used for emitting atoms.
*
- * @param hostUid The uid of the process requesting consent to capture, may be an app or
- * SystemUI.
+ * @param hostProcessUid The uid of the process requesting consent to capture, may be an app or
+ * SystemUI.
*/
@EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- oneway void notifyPermissionRequestDisplayed(int hostUid);
+ oneway void notifyPermissionRequestDisplayed(int hostProcessUid);
/**
* Notifies system server that the permission request was cancelled.
*
* <p>Only used for emitting atoms.
*
- * @param hostUid The uid of the process requesting consent to capture, may be an app or
- * SystemUI.
+ * @param hostProcessUid The uid of the process requesting consent to capture, may be an app or
+ * SystemUI.
*/
@EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- oneway void notifyPermissionRequestCancelled(int hostUid);
+ oneway void notifyPermissionRequestCancelled(int hostProcessUid);
/**
* Notifies system server that the app selector was displayed.
*
* <p>Only used for emitting atoms.
*
- * @param hostUid The uid of the process requesting consent to capture, may be an app or
- * SystemUI.
+ * @param hostProcessUid The uid of the process requesting consent to capture, may be an app or
+ * SystemUI.
*/
@EnforcePermission("android.Manifest.permission.MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- oneway void notifyAppSelectorDisplayed(int hostUid);
+ oneway void notifyAppSelectorDisplayed(int hostProcessUid);
@EnforcePermission("MANAGE_MEDIA_PROJECTION")
@JavaPassthrough(annotation = "@android.annotation.RequiresPermission(android.Manifest"
+ ".permission.MANAGE_MEDIA_PROJECTION)")
- void notifyWindowingModeChanged(int contentToRecord, int targetUid, int windowingMode);
+ void notifyWindowingModeChanged(int contentToRecord, int targetProcessUid, int windowingMode);
}
diff --git a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
index 262f5f198c22..096e8adf2f68 100644
--- a/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
+++ b/media/packages/BluetoothMidiService/src/com/android/bluetoothmidiservice/BluetoothMidiDevice.java
@@ -50,8 +50,16 @@ public final class BluetoothMidiDevice {
private static final String TAG = "BluetoothMidiDevice";
private static final boolean DEBUG = false;
- private static final int DEFAULT_PACKET_SIZE = 20;
- private static final int MAX_PACKET_SIZE = 512;
+ // Bluetooth services should subtract 5 bytes from the MTU for headers.
+ private static final int HEADER_SIZE = 5;
+ // Min MTU size for BLE
+ private static final int MIN_L2CAP_MTU = 23;
+ // 23 (min L2CAP MTU) - 5 (header size)
+ private static final int DEFAULT_PACKET_SIZE = MIN_L2CAP_MTU - HEADER_SIZE;
+ // Max MTU size on Android
+ private static final int MAX_ANDROID_MTU = 517;
+ // 517 (max Android MTU) - 5 (header size)
+ private static final int MAX_PACKET_SIZE = MAX_ANDROID_MTU - HEADER_SIZE;
// Bluetooth MIDI Gatt service UUID
private static final UUID MIDI_SERVICE = UUID.fromString(
@@ -135,8 +143,8 @@ public final class BluetoothMidiDevice {
// switch to receiving notifications
mBluetoothGatt.readCharacteristic(characteristic);
- // Request higher MTU size
- if (!gatt.requestMtu(MAX_PACKET_SIZE)) {
+ // Request max MTU size
+ if (!gatt.requestMtu(MAX_ANDROID_MTU)) {
Log.e(TAG, "request mtu failed");
mPacketEncoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
mPacketDecoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
@@ -204,8 +212,15 @@ public final class BluetoothMidiDevice {
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
Log.d(TAG, "onMtuChanged callback received. mtu: " + mtu + ", status: " + status);
if (status == BluetoothGatt.GATT_SUCCESS) {
- mPacketEncoder.setMaxPacketSize(Math.min(mtu, MAX_PACKET_SIZE));
- mPacketDecoder.setMaxPacketSize(Math.min(mtu, MAX_PACKET_SIZE));
+ int packetSize = Math.min(mtu - HEADER_SIZE, MAX_PACKET_SIZE);
+ if (packetSize <= 0) {
+ Log.e(TAG, "onMtuChanged non-positive packet size: " + packetSize);
+ packetSize = DEFAULT_PACKET_SIZE;
+ } else if (packetSize < DEFAULT_PACKET_SIZE) {
+ Log.w(TAG, "onMtuChanged small packet size: " + packetSize);
+ }
+ mPacketEncoder.setMaxPacketSize(packetSize);
+ mPacketDecoder.setMaxPacketSize(packetSize);
} else {
mPacketEncoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
mPacketDecoder.setMaxPacketSize(DEFAULT_PACKET_SIZE);
diff --git a/nfc-extras/Android.bp b/nfc-extras/Android.bp
index cb9ac6fd1d33..1f187e8eab74 100644
--- a/nfc-extras/Android.bp
+++ b/nfc-extras/Android.bp
@@ -23,9 +23,13 @@ package {
default_applicable_licenses: ["frameworks_base_license"],
}
+// TODO(b/303286040): Deprecate this API surface since this is no longer supported (see ag/443092)
java_sdk_library {
name: "com.android.nfc_extras",
srcs: ["java/**/*.java"],
+ libs: [
+ "framework-nfc.impl"
+ ],
api_packages: ["com.android.nfc_extras"],
dist_group: "android",
}
diff --git a/nfc/Android.bp b/nfc/Android.bp
index bf9f47ceb0a7..5d1404a56a9e 100644
--- a/nfc/Android.bp
+++ b/nfc/Android.bp
@@ -10,7 +10,15 @@ package {
filegroup {
name: "framework-nfc-non-updatable-sources",
path: "java",
- srcs: [],
+ srcs: [
+ "java/android/nfc/NfcServiceManager.java",
+ "java/android/nfc/cardemulation/ApduServiceInfo.aidl",
+ "java/android/nfc/cardemulation/ApduServiceInfo.java",
+ "java/android/nfc/cardemulation/NfcFServiceInfo.aidl",
+ "java/android/nfc/cardemulation/NfcFServiceInfo.java",
+ "java/android/nfc/cardemulation/AidGroup.aidl",
+ "java/android/nfc/cardemulation/AidGroup.java",
+ ],
}
filegroup {
@@ -30,10 +38,22 @@ java_sdk_library {
libs: [
"unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
],
+ static_libs: [
+ "android.nfc.flags-aconfig-java",
+ "android.permission.flags-aconfig-java",
+ ],
srcs: [
":framework-nfc-updatable-sources",
+ ":framework-nfc-javastream-protos",
],
- defaults: ["framework-non-updatable-unbundled-defaults"],
+ defaults: ["framework-module-defaults"],
+ sdk_version: "module_current",
+ min_sdk_version: "34", // should be 35 (making it 34 for compiling for `-next`)
+ installable: true,
+ optimize: {
+ enabled: false,
+ },
+ hostdex: true, // for hiddenapi check
permitted_packages: [
"android.nfc",
"com.android.nfc",
@@ -41,11 +61,18 @@ java_sdk_library {
hidden_api_packages: [
"com.android.nfc",
],
- aidl: {
- include_dirs: [
- // TODO (b/303286040): Remove these when we change to |framework-module-defaults|
- "frameworks/base/nfc/java",
- "frameworks/base/core/java",
- ],
+ impl_library_visibility: [
+ "//frameworks/base:__subpackages__",
+ "//cts/tests/tests/nfc",
+ "//packages/apps/Nfc:__subpackages__",
+ ],
+ jarjar_rules: ":nfc-jarjar-rules",
+ lint: {
+ strict_updatability_linting: true,
},
}
+
+filegroup {
+ name: "nfc-jarjar-rules",
+ srcs: ["jarjar-rules.txt"],
+}
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
index d802177e249b..24c145f890c4 100644
--- a/nfc/api/current.txt
+++ b/nfc/api/current.txt
@@ -1 +1,455 @@
// Signature format: 2.0
+package android.nfc {
+
+ public final class AvailableNfcAntenna implements android.os.Parcelable {
+ ctor public AvailableNfcAntenna(int, int);
+ method public int describeContents();
+ method public int getLocationX();
+ method public int getLocationY();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.AvailableNfcAntenna> CREATOR;
+ }
+
+ public class FormatException extends java.lang.Exception {
+ ctor public FormatException();
+ ctor public FormatException(String);
+ ctor public FormatException(String, Throwable);
+ }
+
+ public final class NdefMessage implements android.os.Parcelable {
+ ctor public NdefMessage(byte[]) throws android.nfc.FormatException;
+ ctor public NdefMessage(android.nfc.NdefRecord, android.nfc.NdefRecord...);
+ ctor public NdefMessage(android.nfc.NdefRecord[]);
+ method public int describeContents();
+ method public int getByteArrayLength();
+ method public android.nfc.NdefRecord[] getRecords();
+ method public byte[] toByteArray();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefMessage> CREATOR;
+ }
+
+ public final class NdefRecord implements android.os.Parcelable {
+ ctor public NdefRecord(short, byte[], byte[], byte[]);
+ ctor @Deprecated public NdefRecord(byte[]) throws android.nfc.FormatException;
+ method public static android.nfc.NdefRecord createApplicationRecord(String);
+ method public static android.nfc.NdefRecord createExternal(String, String, byte[]);
+ method public static android.nfc.NdefRecord createMime(String, byte[]);
+ method public static android.nfc.NdefRecord createTextRecord(String, String);
+ method public static android.nfc.NdefRecord createUri(android.net.Uri);
+ method public static android.nfc.NdefRecord createUri(String);
+ method public int describeContents();
+ method public byte[] getId();
+ method public byte[] getPayload();
+ method public short getTnf();
+ method public byte[] getType();
+ method @Deprecated public byte[] toByteArray();
+ method public String toMimeType();
+ method public android.net.Uri toUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NdefRecord> CREATOR;
+ field public static final byte[] RTD_ALTERNATIVE_CARRIER;
+ field public static final byte[] RTD_HANDOVER_CARRIER;
+ field public static final byte[] RTD_HANDOVER_REQUEST;
+ field public static final byte[] RTD_HANDOVER_SELECT;
+ field public static final byte[] RTD_SMART_POSTER;
+ field public static final byte[] RTD_TEXT;
+ field public static final byte[] RTD_URI;
+ field public static final short TNF_ABSOLUTE_URI = 3; // 0x3
+ field public static final short TNF_EMPTY = 0; // 0x0
+ field public static final short TNF_EXTERNAL_TYPE = 4; // 0x4
+ field public static final short TNF_MIME_MEDIA = 2; // 0x2
+ field public static final short TNF_UNCHANGED = 6; // 0x6
+ field public static final short TNF_UNKNOWN = 5; // 0x5
+ field public static final short TNF_WELL_KNOWN = 1; // 0x1
+ }
+
+ public final class NfcAdapter {
+ method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean allowTransaction();
+ method public void disableForegroundDispatch(android.app.Activity);
+ method public void disableReaderMode(android.app.Activity);
+ method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean disallowTransaction();
+ method public void enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]);
+ method public void enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle);
+ method public static android.nfc.NfcAdapter getDefaultAdapter(android.content.Context);
+ method @Nullable public android.nfc.NfcAntennaInfo getNfcAntennaInfo();
+ method @FlaggedApi("android.nfc.enable_nfc_charging") @Nullable public android.nfc.WlcLDeviceInfo getWlcLDeviceInfo();
+ method public boolean ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler);
+ method public boolean isEnabled();
+ method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean isObserveModeSupported();
+ method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionEnabled();
+ method @FlaggedApi("android.nfc.enable_nfc_reader_option") public boolean isReaderOptionSupported();
+ method public boolean isSecureNfcEnabled();
+ method public boolean isSecureNfcSupported();
+ method @FlaggedApi("android.nfc.enable_nfc_charging") public boolean isWlcEnabled();
+ method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void resetDiscoveryTechnology(@NonNull android.app.Activity);
+ method @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public void setDiscoveryTechnology(@NonNull android.app.Activity, int, int);
+ field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
+ field public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
+ field @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public static final String ACTION_PREFERRED_PAYMENT_CHANGED = "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
+ field public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
+ field public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
+ field @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT) public static final String ACTION_TRANSACTION_DETECTED = "android.nfc.action.TRANSACTION_DETECTED";
+ field public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
+ field public static final String EXTRA_AID = "android.nfc.extra.AID";
+ field public static final String EXTRA_DATA = "android.nfc.extra.DATA";
+ field public static final String EXTRA_ID = "android.nfc.extra.ID";
+ field public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
+ field public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON = "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON";
+ field public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
+ field public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
+ field public static final String EXTRA_TAG = "android.nfc.extra.TAG";
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_DISABLE = 0; // 0x0
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_KEEP = -1; // 0xffffffff
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_A = 1; // 0x1
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_B = 2; // 0x2
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_LISTEN_NFC_PASSIVE_F = 4; // 0x4
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_DISABLE = 0; // 0x0
+ field @FlaggedApi("android.nfc.enable_nfc_set_discovery_tech") public static final int FLAG_READER_KEEP = -1; // 0xffffffff
+ field public static final int FLAG_READER_NFC_A = 1; // 0x1
+ field public static final int FLAG_READER_NFC_B = 2; // 0x2
+ field public static final int FLAG_READER_NFC_BARCODE = 16; // 0x10
+ field public static final int FLAG_READER_NFC_F = 4; // 0x4
+ field public static final int FLAG_READER_NFC_V = 8; // 0x8
+ field public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 256; // 0x100
+ field public static final int FLAG_READER_SKIP_NDEF_CHECK = 128; // 0x80
+ field public static final int PREFERRED_PAYMENT_CHANGED = 2; // 0x2
+ field public static final int PREFERRED_PAYMENT_LOADED = 1; // 0x1
+ field public static final int PREFERRED_PAYMENT_UPDATED = 3; // 0x3
+ field public static final int STATE_OFF = 1; // 0x1
+ field public static final int STATE_ON = 3; // 0x3
+ field public static final int STATE_TURNING_OFF = 4; // 0x4
+ field public static final int STATE_TURNING_ON = 2; // 0x2
+ }
+
+ @Deprecated public static interface NfcAdapter.CreateBeamUrisCallback {
+ method @Deprecated public android.net.Uri[] createBeamUris(android.nfc.NfcEvent);
+ }
+
+ @Deprecated public static interface NfcAdapter.CreateNdefMessageCallback {
+ method @Deprecated public android.nfc.NdefMessage createNdefMessage(android.nfc.NfcEvent);
+ }
+
+ @Deprecated public static interface NfcAdapter.OnNdefPushCompleteCallback {
+ method @Deprecated public void onNdefPushComplete(android.nfc.NfcEvent);
+ }
+
+ public static interface NfcAdapter.OnTagRemovedListener {
+ method public void onTagRemoved();
+ }
+
+ public static interface NfcAdapter.ReaderCallback {
+ method public void onTagDiscovered(android.nfc.Tag);
+ }
+
+ public final class NfcAntennaInfo implements android.os.Parcelable {
+ ctor public NfcAntennaInfo(int, int, boolean, @NonNull java.util.List<android.nfc.AvailableNfcAntenna>);
+ method public int describeContents();
+ method @NonNull public java.util.List<android.nfc.AvailableNfcAntenna> getAvailableNfcAntennas();
+ method public int getDeviceHeight();
+ method public int getDeviceWidth();
+ method public boolean isDeviceFoldable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.NfcAntennaInfo> CREATOR;
+ }
+
+ public final class NfcEvent {
+ field public final android.nfc.NfcAdapter nfcAdapter;
+ field public final int peerLlcpMajorVersion;
+ field public final int peerLlcpMinorVersion;
+ }
+
+ public final class NfcManager {
+ method public android.nfc.NfcAdapter getDefaultAdapter();
+ }
+
+ public final class Tag implements android.os.Parcelable {
+ method public int describeContents();
+ method public byte[] getId();
+ method public String[] getTechList();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.Tag> CREATOR;
+ }
+
+ public class TagLostException extends java.io.IOException {
+ ctor public TagLostException();
+ ctor public TagLostException(String);
+ }
+
+ @FlaggedApi("android.nfc.enable_nfc_charging") public final class WlcLDeviceInfo implements android.os.Parcelable {
+ ctor public WlcLDeviceInfo(double, double, double, int);
+ method public int describeContents();
+ method public double getBatteryLevel();
+ method public double getProductId();
+ method public int getState();
+ method public double getTemperature();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CONNECTED_CHARGING = 2; // 0x2
+ field public static final int CONNECTED_DISCHARGING = 3; // 0x3
+ field @NonNull public static final android.os.Parcelable.Creator<android.nfc.WlcLDeviceInfo> CREATOR;
+ field public static final int DISCONNECTED = 1; // 0x1
+ }
+
+}
+
+package android.nfc.cardemulation {
+
+ public final class CardEmulation {
+ method public boolean categoryAllowsForegroundPreference(String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public java.util.List<java.lang.String> getAidsForPreferredPaymentService();
+ method public java.util.List<java.lang.String> getAidsForService(android.content.ComponentName, String);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public CharSequence getDescriptionForPreferredPaymentService();
+ method public static android.nfc.cardemulation.CardEmulation getInstance(android.nfc.NfcAdapter);
+ method @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public String getRouteDestinationForPreferredPaymentService();
+ method public int getSelectionModeForCategory(String);
+ method public boolean isDefaultServiceForAid(android.content.ComponentName, String);
+ method public boolean isDefaultServiceForCategory(android.content.ComponentName, String);
+ method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
+ method public boolean removeAidsForService(android.content.ComponentName, String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean setOffHostForService(@NonNull android.content.ComponentName, @NonNull String);
+ method public boolean setPreferredService(android.app.Activity, android.content.ComponentName);
+ method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setServiceObserveModeDefault(@NonNull android.content.ComponentName, boolean);
+ method public boolean supportsAidPrefixRegistration();
+ method @NonNull @RequiresPermission(android.Manifest.permission.NFC) public boolean unsetOffHostForService(@NonNull android.content.ComponentName);
+ method public boolean unsetPreferredService(android.app.Activity);
+ field @Deprecated public static final String ACTION_CHANGE_DEFAULT = "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
+ field public static final String CATEGORY_OTHER = "other";
+ field public static final String CATEGORY_PAYMENT = "payment";
+ field public static final String EXTRA_CATEGORY = "category";
+ field public static final String EXTRA_SERVICE_COMPONENT = "component";
+ field public static final int SELECTION_MODE_ALWAYS_ASK = 1; // 0x1
+ field public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2; // 0x2
+ field public static final int SELECTION_MODE_PREFER_DEFAULT = 0; // 0x0
+ }
+
+ public abstract class HostApduService extends android.app.Service {
+ ctor public HostApduService();
+ method public final void notifyUnhandled();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onDeactivated(int);
+ method public abstract byte[] processCommandApdu(byte[], android.os.Bundle);
+ method @FlaggedApi("android.nfc.nfc_read_polling_loop") public void processPollingFrames(@NonNull java.util.List<android.os.Bundle>);
+ method public final void sendResponseApdu(byte[]);
+ field public static final int DEACTIVATION_DESELECTED = 1; // 0x1
+ field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_DATA_KEY = "android.nfc.cardemulation.DATA";
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_GAIN_KEY = "android.nfc.cardemulation.GAIN";
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TIMESTAMP_KEY = "android.nfc.cardemulation.TIMESTAMP";
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_A = 65; // 0x0041 'A'
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_B = 66; // 0x0042 'B'
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_F = 70; // 0x0046 'F'
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final String POLLING_LOOP_TYPE_KEY = "android.nfc.cardemulation.TYPE";
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_OFF = 88; // 0x0058 'X'
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_ON = 79; // 0x004f 'O'
+ field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final char POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x0055 'U'
+ field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
+ field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_apdu_service";
+ }
+
+ public abstract class HostNfcFService extends android.app.Service {
+ ctor public HostNfcFService();
+ method public final android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onDeactivated(int);
+ method public abstract byte[] processNfcFPacket(byte[], android.os.Bundle);
+ method public final void sendResponsePacket(byte[]);
+ field public static final int DEACTIVATION_LINK_LOSS = 0; // 0x0
+ field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
+ field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.host_nfcf_service";
+ }
+
+ public final class NfcFCardEmulation {
+ method public boolean disableService(android.app.Activity) throws java.lang.RuntimeException;
+ method public boolean enableService(android.app.Activity, android.content.ComponentName) throws java.lang.RuntimeException;
+ method public static android.nfc.cardemulation.NfcFCardEmulation getInstance(android.nfc.NfcAdapter);
+ method public String getNfcid2ForService(android.content.ComponentName) throws java.lang.RuntimeException;
+ method public String getSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
+ method public boolean registerSystemCodeForService(android.content.ComponentName, String) throws java.lang.RuntimeException;
+ method public boolean setNfcid2ForService(android.content.ComponentName, String) throws java.lang.RuntimeException;
+ method public boolean unregisterSystemCodeForService(android.content.ComponentName) throws java.lang.RuntimeException;
+ }
+
+ public abstract class OffHostApduService extends android.app.Service {
+ ctor public OffHostApduService();
+ field public static final String SERVICE_INTERFACE = "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
+ field public static final String SERVICE_META_DATA = "android.nfc.cardemulation.off_host_apdu_service";
+ }
+
+}
+
+package android.nfc.tech {
+
+ public final class IsoDep implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.IsoDep get(android.nfc.Tag);
+ method public byte[] getHiLayerResponse();
+ method public byte[] getHistoricalBytes();
+ method public int getMaxTransceiveLength();
+ method public android.nfc.Tag getTag();
+ method public int getTimeout();
+ method public boolean isConnected();
+ method public boolean isExtendedLengthApduSupported();
+ method public void setTimeout(int);
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ }
+
+ public final class MifareClassic implements android.nfc.tech.TagTechnology {
+ method public boolean authenticateSectorWithKeyA(int, byte[]) throws java.io.IOException;
+ method public boolean authenticateSectorWithKeyB(int, byte[]) throws java.io.IOException;
+ method public int blockToSector(int);
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public void decrement(int, int) throws java.io.IOException;
+ method public static android.nfc.tech.MifareClassic get(android.nfc.Tag);
+ method public int getBlockCount();
+ method public int getBlockCountInSector(int);
+ method public int getMaxTransceiveLength();
+ method public int getSectorCount();
+ method public int getSize();
+ method public android.nfc.Tag getTag();
+ method public int getTimeout();
+ method public int getType();
+ method public void increment(int, int) throws java.io.IOException;
+ method public boolean isConnected();
+ method public byte[] readBlock(int) throws java.io.IOException;
+ method public void restore(int) throws java.io.IOException;
+ method public int sectorToBlock(int);
+ method public void setTimeout(int);
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ method public void transfer(int) throws java.io.IOException;
+ method public void writeBlock(int, byte[]) throws java.io.IOException;
+ field public static final int BLOCK_SIZE = 16; // 0x10
+ field public static final byte[] KEY_DEFAULT;
+ field public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY;
+ field public static final byte[] KEY_NFC_FORUM;
+ field public static final int SIZE_1K = 1024; // 0x400
+ field public static final int SIZE_2K = 2048; // 0x800
+ field public static final int SIZE_4K = 4096; // 0x1000
+ field public static final int SIZE_MINI = 320; // 0x140
+ field public static final int TYPE_CLASSIC = 0; // 0x0
+ field public static final int TYPE_PLUS = 1; // 0x1
+ field public static final int TYPE_PRO = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public final class MifareUltralight implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.MifareUltralight get(android.nfc.Tag);
+ method public int getMaxTransceiveLength();
+ method public android.nfc.Tag getTag();
+ method public int getTimeout();
+ method public int getType();
+ method public boolean isConnected();
+ method public byte[] readPages(int) throws java.io.IOException;
+ method public void setTimeout(int);
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ method public void writePage(int, byte[]) throws java.io.IOException;
+ field public static final int PAGE_SIZE = 4; // 0x4
+ field public static final int TYPE_ULTRALIGHT = 1; // 0x1
+ field public static final int TYPE_ULTRALIGHT_C = 2; // 0x2
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public final class Ndef implements android.nfc.tech.TagTechnology {
+ method public boolean canMakeReadOnly();
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.Ndef get(android.nfc.Tag);
+ method public android.nfc.NdefMessage getCachedNdefMessage();
+ method public int getMaxSize();
+ method public android.nfc.NdefMessage getNdefMessage() throws android.nfc.FormatException, java.io.IOException;
+ method public android.nfc.Tag getTag();
+ method public String getType();
+ method public boolean isConnected();
+ method public boolean isWritable();
+ method public boolean makeReadOnly() throws java.io.IOException;
+ method public void writeNdefMessage(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
+ field public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
+ field public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
+ field public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
+ field public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
+ field public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
+ }
+
+ public final class NdefFormatable implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public void format(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
+ method public void formatReadOnly(android.nfc.NdefMessage) throws android.nfc.FormatException, java.io.IOException;
+ method public static android.nfc.tech.NdefFormatable get(android.nfc.Tag);
+ method public android.nfc.Tag getTag();
+ method public boolean isConnected();
+ }
+
+ public final class NfcA implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.NfcA get(android.nfc.Tag);
+ method public byte[] getAtqa();
+ method public int getMaxTransceiveLength();
+ method public short getSak();
+ method public android.nfc.Tag getTag();
+ method public int getTimeout();
+ method public boolean isConnected();
+ method public void setTimeout(int);
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ }
+
+ public final class NfcB implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.NfcB get(android.nfc.Tag);
+ method public byte[] getApplicationData();
+ method public int getMaxTransceiveLength();
+ method public byte[] getProtocolInfo();
+ method public android.nfc.Tag getTag();
+ method public boolean isConnected();
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ }
+
+ public final class NfcBarcode implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.NfcBarcode get(android.nfc.Tag);
+ method public byte[] getBarcode();
+ method public android.nfc.Tag getTag();
+ method public int getType();
+ method public boolean isConnected();
+ field public static final int TYPE_KOVIO = 1; // 0x1
+ field public static final int TYPE_UNKNOWN = -1; // 0xffffffff
+ }
+
+ public final class NfcF implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.NfcF get(android.nfc.Tag);
+ method public byte[] getManufacturer();
+ method public int getMaxTransceiveLength();
+ method public byte[] getSystemCode();
+ method public android.nfc.Tag getTag();
+ method public int getTimeout();
+ method public boolean isConnected();
+ method public void setTimeout(int);
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ }
+
+ public final class NfcV implements android.nfc.tech.TagTechnology {
+ method public void close() throws java.io.IOException;
+ method public void connect() throws java.io.IOException;
+ method public static android.nfc.tech.NfcV get(android.nfc.Tag);
+ method public byte getDsfId();
+ method public int getMaxTransceiveLength();
+ method public byte getResponseFlags();
+ method public android.nfc.Tag getTag();
+ method public boolean isConnected();
+ method public byte[] transceive(byte[]) throws java.io.IOException;
+ }
+
+ public interface TagTechnology extends java.io.Closeable {
+ method public void connect() throws java.io.IOException;
+ method public android.nfc.Tag getTag();
+ method public boolean isConnected();
+ }
+
+}
+
diff --git a/nfc/api/lint-baseline.txt b/nfc/api/lint-baseline.txt
new file mode 100644
index 000000000000..ef9aab6e7641
--- /dev/null
+++ b/nfc/api/lint-baseline.txt
@@ -0,0 +1,95 @@
+// Baseline format: 1.0
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED:
+ Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED:
+ Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED:
+ Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior
+
+
+MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent):
+ Missing nullability on method `onBind` return
+MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent) parameter #0:
+ Missing nullability on parameter `intent` in method `onBind`
+
+
+RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity):
+ Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]):
+ Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String):
+ Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String):
+ Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String):
+ Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]):
+ Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]):
+ Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int):
+ Method 'decrement' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int):
+ Method 'increment' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int):
+ Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#restore(int):
+ Method 'restore' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#transfer(int):
+ Method 'transfer' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]):
+ Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int):
+ Method 'readPages' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]):
+ Method 'writePage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#getNdefMessage():
+ Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#isWritable():
+ Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#makeReadOnly():
+ Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage):
+ Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage):
+ Method 'format' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage):
+ Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.TagTechnology#close():
+ Method 'close' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.TagTechnology#connect():
+ Method 'connect' documentation mentions permissions without declaring @RequiresPermission
diff --git a/nfc/api/module-lib-current.txt b/nfc/api/module-lib-current.txt
index d802177e249b..5ebe91111ec0 100644
--- a/nfc/api/module-lib-current.txt
+++ b/nfc/api/module-lib-current.txt
@@ -1 +1,10 @@
// Signature format: 2.0
+package android.nfc {
+
+ public class NfcFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ method public static void setNfcServiceManager(@NonNull android.nfc.NfcServiceManager);
+ }
+
+}
+
diff --git a/nfc/api/module-lib-lint-baseline.txt b/nfc/api/module-lib-lint-baseline.txt
new file mode 100644
index 000000000000..f7f8ee3ddda5
--- /dev/null
+++ b/nfc/api/module-lib-lint-baseline.txt
@@ -0,0 +1,93 @@
+// Baseline format: 1.0
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED:
+ Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED:
+ Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
+ Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED:
+ Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior
+
+RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity):
+ Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]):
+ Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String):
+ Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String):
+ Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String):
+ Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]):
+ Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]):
+ Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int):
+ Method 'decrement' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int):
+ Method 'increment' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int):
+ Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#restore(int):
+ Method 'restore' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#transfer(int):
+ Method 'transfer' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]):
+ Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int):
+ Method 'readPages' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]):
+ Method 'writePage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#getNdefMessage():
+ Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#isWritable():
+ Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#makeReadOnly():
+ Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage):
+ Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage):
+ Method 'format' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage):
+ Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.TagTechnology#close():
+ Method 'close' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.TagTechnology#connect():
+ Method 'connect' documentation mentions permissions without declaring @RequiresPermission
+
+SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
+ Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
diff --git a/nfc/api/removed.txt b/nfc/api/removed.txt
index d802177e249b..fb82b5ddbb21 100644
--- a/nfc/api/removed.txt
+++ b/nfc/api/removed.txt
@@ -1 +1,17 @@
// Signature format: 2.0
+package android.nfc {
+
+ public final class NfcAdapter {
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void disableForegroundNdefPush(android.app.Activity);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void enableForegroundNdefPush(android.app.Activity, android.nfc.NdefMessage);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public boolean invokeBeam(android.app.Activity);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public boolean isNdefPushEnabled();
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setBeamPushUris(android.net.Uri[], android.app.Activity);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setBeamPushUrisCallback(android.nfc.NfcAdapter.CreateBeamUrisCallback, android.app.Activity);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, android.app.Activity...);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setNdefPushMessageCallback(android.nfc.NfcAdapter.CreateNdefMessageCallback, android.app.Activity, android.app.Activity...);
+ method @Deprecated @android.compat.annotation.UnsupportedAppUsage public void setOnNdefPushCompleteCallback(android.nfc.NfcAdapter.OnNdefPushCompleteCallback, android.app.Activity, android.app.Activity...);
+ }
+
+}
+
diff --git a/nfc/api/system-current.txt b/nfc/api/system-current.txt
index d802177e249b..40672a1adc15 100644
--- a/nfc/api/system-current.txt
+++ b/nfc/api/system-current.txt
@@ -1 +1,53 @@
// Signature format: 2.0
+package android.nfc {
+
+ public final class NfcAdapter {
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean addNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler, String[]);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable(boolean);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
+ method @FlaggedApi("android.nfc.enable_nfc_reader_option") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableReaderOption(boolean);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableSecureNfc(boolean);
+ method @FlaggedApi("android.nfc.enable_nfc_charging") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableWlc(boolean);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") public int getAdapterState();
+ method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.Map<java.lang.String,java.lang.Boolean> getTagIntentAppPreferenceForUser(int);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOn();
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean isControllerAlwaysOnSupported();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagIntentAppPreferenceSupported();
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+ method @FlaggedApi("android.nfc.enable_nfc_charging") public void registerWlcStateListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.WlcStateListener);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean removeNfcUnlockHandler(android.nfc.NfcAdapter.NfcUnlockHandler);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public boolean setControllerAlwaysOn(boolean);
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setReaderMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
+ method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
+ method @FlaggedApi("android.nfc.enable_nfc_charging") public void unregisterWlcStateListener(@NonNull android.nfc.NfcAdapter.WlcStateListener);
+ field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC = "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
+ field public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1; // 0xffffffff
+ field public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0; // 0x0
+ field public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2; // 0xfffffffe
+ }
+
+ public static interface NfcAdapter.ControllerAlwaysOnListener {
+ method public void onControllerAlwaysOnChanged(boolean);
+ }
+
+ public static interface NfcAdapter.NfcUnlockHandler {
+ method public boolean onUnlockAttempted(android.nfc.Tag);
+ }
+
+ @FlaggedApi("android.nfc.enable_nfc_charging") public static interface NfcAdapter.WlcStateListener {
+ method public void onWlcStateChanged(@NonNull android.nfc.WlcLDeviceInfo);
+ }
+
+}
+
+package android.nfc.cardemulation {
+
+ public final class CardEmulation {
+ method @FlaggedApi("android.permission.flags.wallet_role_enabled") @Nullable @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO) public android.nfc.cardemulation.ApduServiceInfo getPreferredPaymentService();
+ method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
+ }
+
+}
+
diff --git a/nfc/api/system-lint-baseline.txt b/nfc/api/system-lint-baseline.txt
new file mode 100644
index 000000000000..761c8e63df81
--- /dev/null
+++ b/nfc/api/system-lint-baseline.txt
@@ -0,0 +1,105 @@
+// Baseline format: 1.0
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_ADAPTER_STATE_CHANGED:
+ Field 'ACTION_ADAPTER_STATE_CHANGED' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_PREFERRED_PAYMENT_CHANGED:
+ Field 'ACTION_PREFERRED_PAYMENT_CHANGED' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
+ Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @BroadcastBehavior
+BroadcastBehavior: android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED:
+ Field 'ACTION_TRANSACTION_DETECTED' is missing @BroadcastBehavior
+
+
+MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent):
+ Missing nullability on method `onBind` return
+MissingNullability: android.nfc.cardemulation.OffHostApduService#onBind(android.content.Intent) parameter #0:
+ Missing nullability on parameter `intent` in method `onBind`
+
+
+RequiresPermission: android.nfc.NfcAdapter#disableForegroundDispatch(android.app.Activity):
+ Method 'disableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.NfcAdapter#enableForegroundDispatch(android.app.Activity, android.app.PendingIntent, android.content.IntentFilter[], String[][]):
+ Method 'enableForegroundDispatch' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForAid(android.content.ComponentName, String):
+ Method 'isDefaultServiceForAid' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String):
+ Method 'isDefaultServiceForCategory' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.cardemulation.CardEmulation#setOffHostForService(android.content.ComponentName, String):
+ Method 'setOffHostForService' documentation mentions permissions already declared by @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.IsoDep#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyA(int, byte[]):
+ Method 'authenticateSectorWithKeyA' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#authenticateSectorWithKeyB(int, byte[]):
+ Method 'authenticateSectorWithKeyB' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#decrement(int, int):
+ Method 'decrement' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#increment(int, int):
+ Method 'increment' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#readBlock(int):
+ Method 'readBlock' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#restore(int):
+ Method 'restore' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#transfer(int):
+ Method 'transfer' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareClassic#writeBlock(int, byte[]):
+ Method 'writeBlock' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#readPages(int):
+ Method 'readPages' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.MifareUltralight#writePage(int, byte[]):
+ Method 'writePage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#getNdefMessage():
+ Method 'getNdefMessage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#isWritable():
+ Method 'isWritable' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#makeReadOnly():
+ Method 'makeReadOnly' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.Ndef#writeNdefMessage(android.nfc.NdefMessage):
+ Method 'writeNdefMessage' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NdefFormatable#format(android.nfc.NdefMessage):
+ Method 'format' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NdefFormatable#formatReadOnly(android.nfc.NdefMessage):
+ Method 'formatReadOnly' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcA#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcB#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#getTimeout():
+ Method 'getTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#setTimeout(int):
+ Method 'setTimeout' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcF#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.NfcV#transceive(byte[]):
+ Method 'transceive' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.TagTechnology#close():
+ Method 'close' documentation mentions permissions without declaring @RequiresPermission
+RequiresPermission: android.nfc.tech.TagTechnology#connect():
+ Method 'connect' documentation mentions permissions without declaring @RequiresPermission
+
+SamShouldBeLast: android.nfc.NfcAdapter#enableReaderMode(android.app.Activity, android.nfc.NfcAdapter.ReaderCallback, int, android.os.Bundle):
+ SAM-compatible parameters (such as parameter 2, "callback", in android.nfc.NfcAdapter.enableReaderMode) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+SamShouldBeLast: android.nfc.NfcAdapter#ignore(android.nfc.Tag, int, android.nfc.NfcAdapter.OnTagRemovedListener, android.os.Handler):
+ SAM-compatible parameters (such as parameter 3, "tagRemovedListener", in android.nfc.NfcAdapter.ignore) should be last to improve Kotlin interoperability; see https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions
+
+SdkConstant: android.nfc.NfcAdapter#ACTION_REQUIRE_UNLOCK_FOR_NFC:
+ Field 'ACTION_REQUIRE_UNLOCK_FOR_NFC' is missing @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
diff --git a/nfc/api/system-removed.txt b/nfc/api/system-removed.txt
index d802177e249b..c6eaa57b6b06 100644
--- a/nfc/api/system-removed.txt
+++ b/nfc/api/system-removed.txt
@@ -1 +1,12 @@
// Signature format: 2.0
+package android.nfc {
+
+ public final class NfcAdapter {
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disableNdefPush();
+ method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enableNdefPush();
+ method public void setNdefPushMessage(android.nfc.NdefMessage, android.app.Activity, int);
+ field public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 1; // 0x1
+ }
+
+}
+
diff --git a/nfc/jarjar-rules.txt b/nfc/jarjar-rules.txt
new file mode 100644
index 000000000000..4cd652d6af7f
--- /dev/null
+++ b/nfc/jarjar-rules.txt
@@ -0,0 +1,38 @@
+# Used by framework-nfc for proto debug dumping
+rule android.app.PendingIntentProto* com.android.nfc.x.@0
+rule android.content.ComponentNameProto* com.android.nfc.x.@0
+rule android.content.IntentProto* com.android.nfc.x.@0
+rule android.content.IntentFilterProto* com.android.nfc.x.@0
+rule android.content.AuthorityEntryProto* com.android.nfc.x.@0
+rule android.nfc.cardemulation.AidGroupProto* com.android.nfc.x.@0
+rule android.nfc.cardemulation.ApduServiceInfoProto* com.android.nfc.x.@0
+rule android.nfc.cardemulation.NfcFServiceInfoProto* com.android.nfc.x.@0
+rule android.nfc.NdefMessageProto* com.android.nfc.x.@0
+rule android.nfc.NdefRecordProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.CardEmulationManagerProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.RegisteredServicesCacheProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.RegisteredNfcFServicesCacheProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.PreferredServicesProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.EnabledNfcFServicesProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.RegisteredAidCacheProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.AidRoutingManagerProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.RegisteredT3tIdentifiersCacheProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.SystemCodeRoutingManagerProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.HostEmulationManagerProto* com.android.nfc.x.@0
+rule com.android.nfc.cardemulation.HostNfcFEmulationManagerProto* com.android.nfc.x.@0
+rule com.android.nfc.NfcServiceDumpProto* com.android.nfc.x.@0
+rule com.android.nfc.DiscoveryParamsProto* com.android.nfc.x.@0
+rule com.android.nfc.NfcDispatcherProto* com.android.nfc.x.@0
+rule android.os.PersistableBundleProto* com.android.nfc.x.@0
+
+# Used by framework-nfc for reading trunk stable flags
+rule android.nfc.FakeFeatureFlagsImpl* com.android.nfc.x.@0
+rule android.nfc.FeatureFlags* com.android.nfc.x.@0
+rule android.nfc.Flags* com.android.nfc.x.@0
+rule android.permission.flags.** com.android.nfc.x.@0
+
+# Used by framework-nfc for misc utilities
+rule android.os.PatternMatcher* com.android.nfc.x.@0
+
+rule com.android.incident.Privacy* com.android.nfc.x.@0
+rule com.android.incident.PrivacyFlags* com.android.nfc.x.@0
diff --git a/core/java/android/nfc/ApduList.aidl b/nfc/java/android/nfc/ApduList.aidl
index f6236b2bfb3b..f6236b2bfb3b 100644
--- a/core/java/android/nfc/ApduList.aidl
+++ b/nfc/java/android/nfc/ApduList.aidl
diff --git a/core/java/android/nfc/ApduList.java b/nfc/java/android/nfc/ApduList.java
index 027141d99c30..027141d99c30 100644
--- a/core/java/android/nfc/ApduList.java
+++ b/nfc/java/android/nfc/ApduList.java
diff --git a/core/java/android/nfc/AvailableNfcAntenna.aidl b/nfc/java/android/nfc/AvailableNfcAntenna.aidl
index 9d06e2d7d5eb..9d06e2d7d5eb 100644
--- a/core/java/android/nfc/AvailableNfcAntenna.aidl
+++ b/nfc/java/android/nfc/AvailableNfcAntenna.aidl
diff --git a/core/java/android/nfc/AvailableNfcAntenna.java b/nfc/java/android/nfc/AvailableNfcAntenna.java
index 6e6512a04971..6e6512a04971 100644
--- a/core/java/android/nfc/AvailableNfcAntenna.java
+++ b/nfc/java/android/nfc/AvailableNfcAntenna.java
diff --git a/core/java/android/nfc/Constants.java b/nfc/java/android/nfc/Constants.java
index f76833063605..f76833063605 100644
--- a/core/java/android/nfc/Constants.java
+++ b/nfc/java/android/nfc/Constants.java
diff --git a/core/java/android/nfc/ErrorCodes.java b/nfc/java/android/nfc/ErrorCodes.java
index d2c81cd27d90..d2c81cd27d90 100644
--- a/core/java/android/nfc/ErrorCodes.java
+++ b/nfc/java/android/nfc/ErrorCodes.java
diff --git a/core/java/android/nfc/FormatException.java b/nfc/java/android/nfc/FormatException.java
index a57de1e0e21a..a57de1e0e21a 100644
--- a/core/java/android/nfc/FormatException.java
+++ b/nfc/java/android/nfc/FormatException.java
diff --git a/core/java/android/nfc/IAppCallback.aidl b/nfc/java/android/nfc/IAppCallback.aidl
index b06bf06d5197..b06bf06d5197 100644
--- a/core/java/android/nfc/IAppCallback.aidl
+++ b/nfc/java/android/nfc/IAppCallback.aidl
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
index 286cf2890eea..286cf2890eea 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/nfc/java/android/nfc/INfcAdapter.aidl
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/nfc/java/android/nfc/INfcAdapterExtras.aidl
index cde57c58ca1f..cde57c58ca1f 100644
--- a/core/java/android/nfc/INfcAdapterExtras.aidl
+++ b/nfc/java/android/nfc/INfcAdapterExtras.aidl
diff --git a/core/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
index f4b46046bc3e..f4b46046bc3e 100644
--- a/core/java/android/nfc/INfcCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcCardEmulation.aidl
diff --git a/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl b/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl
index 1bb7680d2fed..1bb7680d2fed 100644
--- a/core/java/android/nfc/INfcControllerAlwaysOnListener.aidl
+++ b/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl
diff --git a/core/java/android/nfc/INfcDta.aidl b/nfc/java/android/nfc/INfcDta.aidl
index 4cc59271362b..4cc59271362b 100644
--- a/core/java/android/nfc/INfcDta.aidl
+++ b/nfc/java/android/nfc/INfcDta.aidl
diff --git a/core/java/android/nfc/INfcFCardEmulation.aidl b/nfc/java/android/nfc/INfcFCardEmulation.aidl
index 124bfac4f0d0..124bfac4f0d0 100644
--- a/core/java/android/nfc/INfcFCardEmulation.aidl
+++ b/nfc/java/android/nfc/INfcFCardEmulation.aidl
diff --git a/core/java/android/nfc/INfcTag.aidl b/nfc/java/android/nfc/INfcTag.aidl
index 170df71385bb..170df71385bb 100644
--- a/core/java/android/nfc/INfcTag.aidl
+++ b/nfc/java/android/nfc/INfcTag.aidl
diff --git a/core/java/android/nfc/INfcUnlockHandler.aidl b/nfc/java/android/nfc/INfcUnlockHandler.aidl
index e1cace987dc3..e1cace987dc3 100644
--- a/core/java/android/nfc/INfcUnlockHandler.aidl
+++ b/nfc/java/android/nfc/INfcUnlockHandler.aidl
diff --git a/core/java/android/nfc/INfcWlcStateListener.aidl b/nfc/java/android/nfc/INfcWlcStateListener.aidl
index c2b7075bc6e4..c2b7075bc6e4 100644
--- a/core/java/android/nfc/INfcWlcStateListener.aidl
+++ b/nfc/java/android/nfc/INfcWlcStateListener.aidl
diff --git a/core/java/android/nfc/ITagRemovedCallback.aidl b/nfc/java/android/nfc/ITagRemovedCallback.aidl
index 2a06ff314b22..2a06ff314b22 100644
--- a/core/java/android/nfc/ITagRemovedCallback.aidl
+++ b/nfc/java/android/nfc/ITagRemovedCallback.aidl
diff --git a/core/java/android/nfc/NdefMessage.aidl b/nfc/java/android/nfc/NdefMessage.aidl
index 378b9d05b385..378b9d05b385 100644
--- a/core/java/android/nfc/NdefMessage.aidl
+++ b/nfc/java/android/nfc/NdefMessage.aidl
diff --git a/core/java/android/nfc/NdefMessage.java b/nfc/java/android/nfc/NdefMessage.java
index 553f6c01b016..553f6c01b016 100644
--- a/core/java/android/nfc/NdefMessage.java
+++ b/nfc/java/android/nfc/NdefMessage.java
diff --git a/core/java/android/nfc/NdefRecord.aidl b/nfc/java/android/nfc/NdefRecord.aidl
index 10f89d0936e4..10f89d0936e4 100644
--- a/core/java/android/nfc/NdefRecord.aidl
+++ b/nfc/java/android/nfc/NdefRecord.aidl
diff --git a/core/java/android/nfc/NdefRecord.java b/nfc/java/android/nfc/NdefRecord.java
index 7bf4355d5b35..7bf4355d5b35 100644
--- a/core/java/android/nfc/NdefRecord.java
+++ b/nfc/java/android/nfc/NdefRecord.java
diff --git a/core/java/android/nfc/NfcActivityManager.java b/nfc/java/android/nfc/NfcActivityManager.java
index f03fc0af86b3..f03fc0af86b3 100644
--- a/core/java/android/nfc/NfcActivityManager.java
+++ b/nfc/java/android/nfc/NfcActivityManager.java
diff --git a/core/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
index 75f5491a416f..75f5491a416f 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/nfc/java/android/nfc/NfcAdapter.java
diff --git a/core/java/android/nfc/NfcAntennaInfo.aidl b/nfc/java/android/nfc/NfcAntennaInfo.aidl
index d5e79fc37282..d5e79fc37282 100644
--- a/core/java/android/nfc/NfcAntennaInfo.aidl
+++ b/nfc/java/android/nfc/NfcAntennaInfo.aidl
diff --git a/core/java/android/nfc/NfcAntennaInfo.java b/nfc/java/android/nfc/NfcAntennaInfo.java
index b002ca21e8e3..b002ca21e8e3 100644
--- a/core/java/android/nfc/NfcAntennaInfo.java
+++ b/nfc/java/android/nfc/NfcAntennaInfo.java
diff --git a/core/java/android/nfc/NfcControllerAlwaysOnListener.java b/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java
index 6ae58fd38cbe..6ae58fd38cbe 100644
--- a/core/java/android/nfc/NfcControllerAlwaysOnListener.java
+++ b/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java
diff --git a/core/java/android/nfc/NfcEvent.java b/nfc/java/android/nfc/NfcEvent.java
index aff4f52f2bab..aff4f52f2bab 100644
--- a/core/java/android/nfc/NfcEvent.java
+++ b/nfc/java/android/nfc/NfcEvent.java
diff --git a/core/java/android/nfc/NfcFrameworkInitializer.java b/nfc/java/android/nfc/NfcFrameworkInitializer.java
index 1ab8a1ebd72c..1ab8a1ebd72c 100644
--- a/core/java/android/nfc/NfcFrameworkInitializer.java
+++ b/nfc/java/android/nfc/NfcFrameworkInitializer.java
diff --git a/core/java/android/nfc/NfcManager.java b/nfc/java/android/nfc/NfcManager.java
index 644e3122774b..644e3122774b 100644
--- a/core/java/android/nfc/NfcManager.java
+++ b/nfc/java/android/nfc/NfcManager.java
diff --git a/core/java/android/nfc/NfcServiceManager.java b/nfc/java/android/nfc/NfcServiceManager.java
index 5582f1154cad..5582f1154cad 100644
--- a/core/java/android/nfc/NfcServiceManager.java
+++ b/nfc/java/android/nfc/NfcServiceManager.java
diff --git a/core/java/android/nfc/NfcWlcStateListener.java b/nfc/java/android/nfc/NfcWlcStateListener.java
index 8d793101f41f..8d793101f41f 100644
--- a/core/java/android/nfc/NfcWlcStateListener.java
+++ b/nfc/java/android/nfc/NfcWlcStateListener.java
diff --git a/core/java/android/nfc/Tag.aidl b/nfc/java/android/nfc/Tag.aidl
index 312261ebe76d..312261ebe76d 100644
--- a/core/java/android/nfc/Tag.aidl
+++ b/nfc/java/android/nfc/Tag.aidl
diff --git a/core/java/android/nfc/Tag.java b/nfc/java/android/nfc/Tag.java
index 500038f14d9d..500038f14d9d 100644
--- a/core/java/android/nfc/Tag.java
+++ b/nfc/java/android/nfc/Tag.java
diff --git a/core/java/android/nfc/TagLostException.java b/nfc/java/android/nfc/TagLostException.java
index 1981d7c0c6e0..1981d7c0c6e0 100644
--- a/core/java/android/nfc/TagLostException.java
+++ b/nfc/java/android/nfc/TagLostException.java
diff --git a/core/java/android/nfc/TechListParcel.aidl b/nfc/java/android/nfc/TechListParcel.aidl
index 92e646f220f0..92e646f220f0 100644
--- a/core/java/android/nfc/TechListParcel.aidl
+++ b/nfc/java/android/nfc/TechListParcel.aidl
diff --git a/core/java/android/nfc/TechListParcel.java b/nfc/java/android/nfc/TechListParcel.java
index 9f01559bd344..9f01559bd344 100644
--- a/core/java/android/nfc/TechListParcel.java
+++ b/nfc/java/android/nfc/TechListParcel.java
diff --git a/core/java/android/nfc/TransceiveResult.aidl b/nfc/java/android/nfc/TransceiveResult.aidl
index 98f92ee03eef..98f92ee03eef 100644
--- a/core/java/android/nfc/TransceiveResult.aidl
+++ b/nfc/java/android/nfc/TransceiveResult.aidl
diff --git a/core/java/android/nfc/TransceiveResult.java b/nfc/java/android/nfc/TransceiveResult.java
index 7992094e6ba1..7992094e6ba1 100644
--- a/core/java/android/nfc/TransceiveResult.java
+++ b/nfc/java/android/nfc/TransceiveResult.java
diff --git a/core/java/android/nfc/WlcLDeviceInfo.aidl b/nfc/java/android/nfc/WlcLDeviceInfo.aidl
index 33143fe81162..33143fe81162 100644
--- a/core/java/android/nfc/WlcLDeviceInfo.aidl
+++ b/nfc/java/android/nfc/WlcLDeviceInfo.aidl
diff --git a/core/java/android/nfc/WlcLDeviceInfo.java b/nfc/java/android/nfc/WlcLDeviceInfo.java
index 016431e90d8e..016431e90d8e 100644
--- a/core/java/android/nfc/WlcLDeviceInfo.java
+++ b/nfc/java/android/nfc/WlcLDeviceInfo.java
diff --git a/core/java/android/nfc/cardemulation/AidGroup.aidl b/nfc/java/android/nfc/cardemulation/AidGroup.aidl
index 56d6fa559677..56d6fa559677 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.aidl
+++ b/nfc/java/android/nfc/cardemulation/AidGroup.aidl
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/nfc/java/android/nfc/cardemulation/AidGroup.java
index ae3e333051d7..ae3e333051d7 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/nfc/java/android/nfc/cardemulation/AidGroup.java
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.aidl
index a62fdd6a6c5c..a62fdd6a6c5c 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.aidl
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.aidl
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
index 41dee3ab035c..41dee3ab035c 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/ApduServiceInfo.java
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
index 81eab71fe080..81eab71fe080 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/CardEmulation.java
diff --git a/core/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
index 7cd2533a7dbf..7cd2533a7dbf 100644
--- a/core/java/android/nfc/cardemulation/HostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/HostApduService.java
diff --git a/core/java/android/nfc/cardemulation/HostNfcFService.java b/nfc/java/android/nfc/cardemulation/HostNfcFService.java
index 65b5ca77de62..65b5ca77de62 100644
--- a/core/java/android/nfc/cardemulation/HostNfcFService.java
+++ b/nfc/java/android/nfc/cardemulation/HostNfcFService.java
diff --git a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java b/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java
index 48bbf5b61052..48bbf5b61052 100644
--- a/core/java/android/nfc/cardemulation/NfcFCardEmulation.java
+++ b/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
index 56b98ebd90fa..56b98ebd90fa 100644
--- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
+++ b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.aidl
diff --git a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.java
index 33bc16978721..33bc16978721 100644
--- a/core/java/android/nfc/cardemulation/NfcFServiceInfo.java
+++ b/nfc/java/android/nfc/cardemulation/NfcFServiceInfo.java
diff --git a/core/java/android/nfc/OWNERS b/nfc/java/android/nfc/cardemulation/OWNERS
index 35e9713f5715..35e9713f5715 100644
--- a/core/java/android/nfc/OWNERS
+++ b/nfc/java/android/nfc/cardemulation/OWNERS
diff --git a/core/java/android/nfc/cardemulation/OffHostApduService.java b/nfc/java/android/nfc/cardemulation/OffHostApduService.java
index 2286e8476d94..2286e8476d94 100644
--- a/core/java/android/nfc/cardemulation/OffHostApduService.java
+++ b/nfc/java/android/nfc/cardemulation/OffHostApduService.java
diff --git a/core/java/android/nfc/cardemulation/Utils.java b/nfc/java/android/nfc/cardemulation/Utils.java
index 202e1cfb48f6..202e1cfb48f6 100644
--- a/core/java/android/nfc/cardemulation/Utils.java
+++ b/nfc/java/android/nfc/cardemulation/Utils.java
diff --git a/core/java/android/nfc/dta/NfcDta.java b/nfc/java/android/nfc/dta/NfcDta.java
index 88016623434d..88016623434d 100644
--- a/core/java/android/nfc/dta/NfcDta.java
+++ b/nfc/java/android/nfc/dta/NfcDta.java
diff --git a/core/java/android/nfc/cardemulation/OWNERS b/nfc/java/android/nfc/dta/OWNERS
index 35e9713f5715..35e9713f5715 100644
--- a/core/java/android/nfc/cardemulation/OWNERS
+++ b/nfc/java/android/nfc/dta/OWNERS
diff --git a/core/java/android/nfc/flags.aconfig b/nfc/java/android/nfc/flags.aconfig
index 01a45708fddf..01a45708fddf 100644
--- a/core/java/android/nfc/flags.aconfig
+++ b/nfc/java/android/nfc/flags.aconfig
diff --git a/core/java/android/nfc/package.html b/nfc/java/android/nfc/package.html
index 55c1d1650aa9..55c1d1650aa9 100644
--- a/core/java/android/nfc/package.html
+++ b/nfc/java/android/nfc/package.html
diff --git a/core/java/android/nfc/tech/BasicTagTechnology.java b/nfc/java/android/nfc/tech/BasicTagTechnology.java
index ae468fead7a2..ae468fead7a2 100644
--- a/core/java/android/nfc/tech/BasicTagTechnology.java
+++ b/nfc/java/android/nfc/tech/BasicTagTechnology.java
diff --git a/core/java/android/nfc/tech/IsoDep.java b/nfc/java/android/nfc/tech/IsoDep.java
index 0ba0c5a8d13b..0ba0c5a8d13b 100644
--- a/core/java/android/nfc/tech/IsoDep.java
+++ b/nfc/java/android/nfc/tech/IsoDep.java
diff --git a/core/java/android/nfc/tech/MifareClassic.java b/nfc/java/android/nfc/tech/MifareClassic.java
index 26f54e692289..26f54e692289 100644
--- a/core/java/android/nfc/tech/MifareClassic.java
+++ b/nfc/java/android/nfc/tech/MifareClassic.java
diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/nfc/java/android/nfc/tech/MifareUltralight.java
index c0416a39ba76..c0416a39ba76 100644
--- a/core/java/android/nfc/tech/MifareUltralight.java
+++ b/nfc/java/android/nfc/tech/MifareUltralight.java
diff --git a/core/java/android/nfc/tech/Ndef.java b/nfc/java/android/nfc/tech/Ndef.java
index 7d83f157a314..7d83f157a314 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/nfc/java/android/nfc/tech/Ndef.java
diff --git a/core/java/android/nfc/tech/NdefFormatable.java b/nfc/java/android/nfc/tech/NdefFormatable.java
index 2240fe7f7d3b..2240fe7f7d3b 100644
--- a/core/java/android/nfc/tech/NdefFormatable.java
+++ b/nfc/java/android/nfc/tech/NdefFormatable.java
diff --git a/core/java/android/nfc/tech/NfcA.java b/nfc/java/android/nfc/tech/NfcA.java
index 7e6648361670..7e6648361670 100644
--- a/core/java/android/nfc/tech/NfcA.java
+++ b/nfc/java/android/nfc/tech/NfcA.java
diff --git a/core/java/android/nfc/tech/NfcB.java b/nfc/java/android/nfc/tech/NfcB.java
index 3ebd47f610c0..3ebd47f610c0 100644
--- a/core/java/android/nfc/tech/NfcB.java
+++ b/nfc/java/android/nfc/tech/NfcB.java
diff --git a/core/java/android/nfc/tech/NfcBarcode.java b/nfc/java/android/nfc/tech/NfcBarcode.java
index 421ba7827cb1..421ba7827cb1 100644
--- a/core/java/android/nfc/tech/NfcBarcode.java
+++ b/nfc/java/android/nfc/tech/NfcBarcode.java
diff --git a/core/java/android/nfc/tech/NfcF.java b/nfc/java/android/nfc/tech/NfcF.java
index 2ccd38875f07..2ccd38875f07 100644
--- a/core/java/android/nfc/tech/NfcF.java
+++ b/nfc/java/android/nfc/tech/NfcF.java
diff --git a/core/java/android/nfc/tech/NfcV.java b/nfc/java/android/nfc/tech/NfcV.java
index 186c63bf07fd..186c63bf07fd 100644
--- a/core/java/android/nfc/tech/NfcV.java
+++ b/nfc/java/android/nfc/tech/NfcV.java
diff --git a/core/java/android/nfc/dta/OWNERS b/nfc/java/android/nfc/tech/OWNERS
index 35e9713f5715..35e9713f5715 100644
--- a/core/java/android/nfc/dta/OWNERS
+++ b/nfc/java/android/nfc/tech/OWNERS
diff --git a/core/java/android/nfc/tech/TagTechnology.java b/nfc/java/android/nfc/tech/TagTechnology.java
index 839fe429b338..839fe429b338 100644
--- a/core/java/android/nfc/tech/TagTechnology.java
+++ b/nfc/java/android/nfc/tech/TagTechnology.java
diff --git a/core/java/android/nfc/tech/package.html b/nfc/java/android/nfc/tech/package.html
index a99828f90c5b..a99828f90c5b 100644
--- a/core/java/android/nfc/tech/package.html
+++ b/nfc/java/android/nfc/tech/package.html
diff --git a/core/tests/nfctests/Android.bp b/nfc/tests/Android.bp
index f81be494ad18..62566ee89fb8 100644
--- a/core/tests/nfctests/Android.bp
+++ b/nfc/tests/Android.bp
@@ -30,6 +30,7 @@ android_test {
"truth",
],
libs: [
+ "framework-nfc.impl",
"android.test.runner",
],
srcs: ["src/**/*.java"],
diff --git a/core/tests/nfctests/AndroidManifest.xml b/nfc/tests/AndroidManifest.xml
index 99e2c34c656b..99e2c34c656b 100644
--- a/core/tests/nfctests/AndroidManifest.xml
+++ b/nfc/tests/AndroidManifest.xml
diff --git a/core/tests/nfctests/AndroidTest.xml b/nfc/tests/AndroidTest.xml
index 490d6f5df197..490d6f5df197 100644
--- a/core/tests/nfctests/AndroidTest.xml
+++ b/nfc/tests/AndroidTest.xml
diff --git a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
index 48f4288d401e..48f4288d401e 100644
--- a/core/tests/nfctests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
+++ b/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
diff --git a/core/tests/nfctests/src/android/nfc/TechListParcelTest.java b/nfc/tests/src/android/nfc/TechListParcelTest.java
index a12bbbc6884b..a12bbbc6884b 100644
--- a/core/tests/nfctests/src/android/nfc/TechListParcelTest.java
+++ b/nfc/tests/src/android/nfc/TechListParcelTest.java
diff --git a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml b/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
deleted file mode 100644
index 9d16f32db932..000000000000
--- a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<!-- Copied from //frameworks/base/core/res/res/drawable/item_background_material.xml -->
-<ripple xmlns:android="http://schemas.android.com/apk/res/android"
- android:color="@color/autofill_light_colorControlHighlight">
- <item android:id="@android:id/mask">
- <color android:color="@android:color/white"/>
- </item>
-</ripple> \ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
index 2f0c83b6556a..5becc86927d2 100644
--- a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2023 The Android Open Source Project
+ ~ Copyright (C) 2024 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.
@@ -23,8 +23,8 @@
android:shape="rectangle"
android:top="1dp">
<shape>
- <corners android:radius="28dp" />
- <solid android:color="@android:color/system_surface_container_high_light" />
+ <corners android:radius="16dp" />
+ <solid android:color="@color/dropdown_container" />
</shape>
</item>
</ripple> \ No newline at end of file
diff --git a/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml b/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml
deleted file mode 100644
index e4e9f7ac85a9..000000000000
--- a/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<!--
- ~ Copyright (C) 2023 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@android:id/content"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/autofill.Dataset">
- <ImageView
- android:id="@android:id/icon1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerVertical="true"
- android:layout_alignParentStart="true"
- android:background="@null"/>
- <TextView
- android:id="@android:id/text1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentTop="true"
- android:layout_toEndOf="@android:id/icon1"
- style="@style/autofill.TextAppearance"/>
-
-</RelativeLayout>
diff --git a/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
new file mode 100644
index 000000000000..cb6c6b473244
--- /dev/null
+++ b/packages/CredentialManager/res/layout/credman_dropdown_presentation_layout.xml
@@ -0,0 +1,45 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/content"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:maxWidth="@dimen/autofill_dropdown_layout_width"
+ android:elevation="3dp">
+
+ <ImageView
+ android:id="@android:id/icon1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentStart="true"
+ android:background="@null"/>
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="@dimen/autofill_dropdown_text_width"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@android:id/icon1"
+ style="@style/autofill.TextTitle"/>
+ <TextView
+ android:id="@android:id/text2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@android:id/text1"
+ android:layout_toEndOf="@android:id/icon1"
+ style="@style/autofill.TextSubtitle"/>
+
+</RelativeLayout>
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
index 63b9f24d9033..dcb7ef9c3ed8 100644
--- a/packages/CredentialManager/res/values/colors.xml
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -16,23 +16,8 @@
<!-- Color palette -->
<resources>
- <color name="autofill_light_colorPrimary">@color/primary_material_light</color>
- <color name="autofill_light_colorAccent">@color/accent_material_light</color>
- <color name="autofill_light_colorControlHighlight">@color/ripple_material_light</color>
- <color name="autofill_light_colorButtonNormal">@color/button_material_light</color>
-
- <!-- Text colors -->
- <color name="autofill_light_textColorPrimary">@color/abc_primary_text_material_light</color>
- <color name="autofill_light_textColorSecondary">@color/abc_secondary_text_material_light</color>
- <color name="autofill_light_textColorHint">@color/abc_hint_foreground_material_light</color>
- <color name="autofill_light_textColorHintInverse">@color/abc_hint_foreground_material_dark
- </color>
- <color name="autofill_light_textColorHighlight">@color/highlighted_text_material_light</color>
- <color name="autofill_light_textColorLink">@color/autofill_light_colorAccent</color>
-
<!-- These colors are used for Remote Views. -->
- <color name="background_dark_mode">#0E0C0B</color>
- <color name="background">#F1F3F4</color>
- <color name="text_primary_dark_mode">#DFDEDB</color>
- <color name="text_primary">#202124</color>
+ <color name="text_primary">#1A1B20</color>
+ <color name="text_secondary">#44474F</color>
+ <color name="dropdown_container">#F3F3FA</color>
</resources> \ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
index 67003a330974..2a4719d027e2 100644
--- a/packages/CredentialManager/res/values/dimens.xml
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -17,6 +17,12 @@
-->
<resources>
- <dimen name="autofill_view_padding">16dp</dimen>
- <dimen name="autofill_icon_size">16dp</dimen>
+ <dimen name="autofill_view_top_padding">12dp</dimen>
+ <dimen name="autofill_view_right_padding">24dp</dimen>
+ <dimen name="autofill_view_bottom_padding">12dp</dimen>
+ <dimen name="autofill_view_left_padding">16dp</dimen>
+ <dimen name="autofill_view_icon_to_text_padding">10dp</dimen>
+ <dimen name="autofill_icon_size">24dp</dimen>
+ <dimen name="autofill_dropdown_layout_width">296dp</dimen>
+ <dimen name="autofill_dropdown_text_width">240dp</dimen>
</resources> \ No newline at end of file
diff --git a/packages/CredentialManager/res/values/styles.xml b/packages/CredentialManager/res/values/styles.xml
index 4a5761acdd83..7de941ebd4a5 100644
--- a/packages/CredentialManager/res/values/styles.xml
+++ b/packages/CredentialManager/res/values/styles.xml
@@ -15,24 +15,13 @@
-->
<resources>
- <style name="autofill.TextAppearance.Small" parent="@style/autofill.TextAppearance">
- <item name="android:textSize">12sp</item>
- </style>
-
-
- <style name="autofill.Dataset" parent="">
- <item name="android:background">@drawable/autofill_light_selectable_item_background</item>
- </style>
-
- <style name="autofill.TextAppearance" parent="">
- <item name="android:textColor">@color/autofill_light_textColorPrimary</item>
- <item name="android:textColorHint">@color/autofill_light_textColorHint</item>
- <item name="android:textColorHighlight">@color/autofill_light_textColorHighlight</item>
- <item name="android:textColorLink">@color/autofill_light_textColorLink</item>
+ <style name="autofill.TextTitle" parent="">
+ <item name="android:fontFamily">google-sans-medium</item>
<item name="android:textSize">14sp</item>
</style>
- <style name="autofill.TextAppearance.Primary">
- <item name="android:textColor">@color/autofill_light_textColorPrimary</item>
+ <style name="autofill.TextSubtitle" parent="">
+ <item name="android:fontFamily">google-sans-text</item>
+ <item name="android:textSize">12sp</item>
</style>
</resources> \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index b2c23a401117..58467afe43a4 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -57,6 +57,7 @@ import com.android.credentialmanager.common.ui.RemoteViewsFactory
import com.android.credentialmanager.getflow.ProviderDisplayInfo
import com.android.credentialmanager.getflow.toProviderDisplayInfo
import com.android.credentialmanager.ktx.credentialEntry
+import com.android.credentialmanager.model.CredentialType
import com.android.credentialmanager.model.get.CredentialEntryInfo
import com.android.credentialmanager.model.get.ProviderInfo
import org.json.JSONException
@@ -313,12 +314,14 @@ class CredentialAutofillService : AutofillService() {
var i = 0
var datasetAdded = false
- val duplicateDisplayNames: MutableMap<String, Boolean> = mutableMapOf()
+ val duplicateDisplayNamesForPasskeys: MutableMap<String, Boolean> = mutableMapOf()
providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach {
val credentialEntry = it.sortedCredentialEntryList.first()
- credentialEntry.displayName?.let {displayName ->
- val duplicateEntry = duplicateDisplayNames.contains(displayName)
- duplicateDisplayNames[displayName] = duplicateEntry
+ if (credentialEntry.credentialType == CredentialType.PASSKEY) {
+ credentialEntry.displayName?.let { displayName ->
+ val duplicateEntry = duplicateDisplayNamesForPasskeys.contains(displayName)
+ duplicateDisplayNamesForPasskeys[displayName] = duplicateEntry
+ }
}
}
providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
@@ -355,12 +358,19 @@ class CredentialAutofillService : AutofillService() {
} else {
spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
}
- val displayName : String = primaryEntry.displayName ?: primaryEntry.userName
+ val displayName: String = if (primaryEntry.credentialType == CredentialType.PASSKEY
+ && primaryEntry.displayName != null) {
+ primaryEntry.displayName!!
+ } else {
+ primaryEntry.userName
+ }
val sliceBuilder = InlineSuggestionUi
.newContentBuilder(pendingIntent)
.setTitle(displayName)
sliceBuilder.setStartIcon(icon)
- if (duplicateDisplayNames[displayName] == true) {
+ if (primaryEntry.credentialType ==
+ CredentialType.PASSKEY && duplicateDisplayNamesForPasskeys[displayName]
+ == true) {
sliceBuilder.setSubtitle(primaryEntry.userName)
}
inlinePresentation = InlinePresentation(
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
index 4dc7f00c1550..e039dead043e 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -21,6 +21,7 @@ import android.content.res.Configuration
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.CredentialType
import android.graphics.drawable.Icon
class RemoteViewsFactory {
@@ -29,48 +30,87 @@ class RemoteViewsFactory {
private const val setAdjustViewBoundsMethodName = "setAdjustViewBounds"
private const val setMaxHeightMethodName = "setMaxHeight"
private const val setBackgroundResourceMethodName = "setBackgroundResource"
+ private const val bulletPoint = "\u2022"
+ private const val passwordCharacterLength = 15
fun createDropdownPresentation(
context: Context,
icon: Icon,
credentialEntryInfo: CredentialEntryInfo
): RemoteViews {
- val padding = context.resources.getDimensionPixelSize(com.android
- .credentialmanager.R.dimen.autofill_view_padding)
var layoutId: Int = com.android.credentialmanager.R.layout
- .autofill_dataset_left_with_item_tag_hint
+ .credman_dropdown_presentation_layout
val remoteViews = RemoteViews(context.packageName, layoutId)
- setRemoteViewsPaddings(remoteViews, padding)
- val textColorPrimary = getTextColorPrimary(isDarkMode(context), context);
- remoteViews.setTextColor(android.R.id.text1, textColorPrimary);
- remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName)
-
+ if (credentialEntryInfo.credentialType == CredentialType.UNKNOWN) {
+ return remoteViews
+ }
+ setRemoteViewsPaddings(remoteViews, context)
+ if (credentialEntryInfo.credentialType == CredentialType.PASSKEY) {
+ val displayName = credentialEntryInfo.displayName ?: credentialEntryInfo.userName
+ remoteViews.setTextViewText(android.R.id.text1, displayName)
+ val secondaryText = if (credentialEntryInfo.displayName != null)
+ (credentialEntryInfo.userName + " " + bulletPoint + " "
+ + credentialEntryInfo.credentialTypeDisplayName
+ + " " + bulletPoint + " " + credentialEntryInfo.providerDisplayName)
+ else (credentialEntryInfo.credentialTypeDisplayName + " " + bulletPoint + " "
+ + credentialEntryInfo.providerDisplayName)
+ remoteViews.setTextViewText(android.R.id.text2, secondaryText)
+ } else {
+ remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName)
+ remoteViews.setTextViewText(android.R.id.text2,
+ bulletPoint.repeat(passwordCharacterLength))
+ }
+ val textColorPrimary = ContextCompat.getColor(context,
+ com.android.credentialmanager.R.color.text_primary)
+ remoteViews.setTextColor(android.R.id.text1, textColorPrimary)
+ val textColorSecondary = ContextCompat.getColor(context, com.android
+ .credentialmanager.R.color.text_secondary)
+ remoteViews.setTextColor(android.R.id.text2, textColorSecondary)
remoteViews.setImageViewIcon(android.R.id.icon1, icon);
remoteViews.setBoolean(
android.R.id.icon1, setAdjustViewBoundsMethodName, true);
remoteViews.setInt(
android.R.id.icon1,
- setMaxHeightMethodName,
+ setMaxHeightMethodName,
context.resources.getDimensionPixelSize(
com.android.credentialmanager.R.dimen.autofill_icon_size));
- val drawableId = if (isDarkMode(context))
- com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one_dark
- else com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+ val drawableId =
+ com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
remoteViews.setInt(
android.R.id.content, setBackgroundResourceMethodName, drawableId);
return remoteViews
}
private fun setRemoteViewsPaddings(
- remoteViews: RemoteViews,
- padding: Int) {
- val halfPadding = padding / 2
+ remoteViews: RemoteViews, context: Context) {
+ val leftPadding = context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_view_left_padding)
+ val iconToTextPadding = context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_view_icon_to_text_padding)
+ val rightPadding = context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_view_right_padding)
+ val topPadding = context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_view_top_padding)
+ val bottomPadding = context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_view_bottom_padding)
+ remoteViews.setViewPadding(
+ android.R.id.icon1,
+ leftPadding,
+ /* top=*/0,
+ /* right=*/0,
+ /* bottom=*/0)
remoteViews.setViewPadding(
android.R.id.text1,
- halfPadding,
- halfPadding,
- halfPadding,
- halfPadding)
+ iconToTextPadding,
+ /* top=*/topPadding,
+ /* right=*/rightPadding,
+ /* bottom=*/0)
+ remoteViews.setViewPadding(
+ android.R.id.text2,
+ iconToTextPadding,
+ /* top=*/0,
+ /* right=*/rightPadding,
+ /* bottom=*/bottomPadding)
}
private fun isDarkMode(context: Context): Boolean {
@@ -78,11 +118,5 @@ class RemoteViewsFactory {
Configuration.UI_MODE_NIGHT_MASK
return currentNightMode == Configuration.UI_MODE_NIGHT_YES
}
-
- private fun getTextColorPrimary(darkMode: Boolean, context: Context): Int {
- return if (darkMode) ContextCompat.getColor(
- context, com.android.credentialmanager.R.color.text_primary_dark_mode)
- else ContextCompat.getColor(context, com.android.credentialmanager.R.color.text_primary)
- }
}
}
diff --git a/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml b/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml
index 7f1651721d84..8127e1a6d5a2 100644
--- a/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml
+++ b/packages/SettingsLib/AdaptiveIcon/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
@@ -8,7 +8,7 @@
errorLine2=" ~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveIcon.java"
- line="78"
+ line="79"
column="34"/>
</issue>
@@ -19,7 +19,7 @@
errorLine2=" ~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveIcon.java"
- line="90"
+ line="91"
column="36"/>
</issue>
@@ -30,7 +30,7 @@
errorLine2=" ~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java"
- line="43"
+ line="45"
column="46"/>
</issue>
@@ -41,7 +41,7 @@
errorLine2=" ~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java"
- line="65"
+ line="67"
column="9"/>
</issue>
@@ -52,7 +52,7 @@
errorLine2=" ~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java"
- line="72"
+ line="74"
column="9"/>
</issue>
@@ -63,7 +63,7 @@
errorLine2=" ~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java"
- line="80"
+ line="82"
column="9"/>
</issue>
@@ -74,8 +74,8 @@
errorLine2=" ~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java"
- line="105"
+ line="107"
column="26"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp
index 8b16d64bcfe7..5da4b9518a31 100644
--- a/packages/SettingsLib/Android.bp
+++ b/packages/SettingsLib/Android.bp
@@ -61,7 +61,6 @@ android_library {
"src/**/*.kt",
],
lint: {
- baseline_filename: "lint-baseline.xml",
extra_check_modules: ["SettingsLibLintChecker"],
},
}
diff --git a/packages/SettingsLib/EmergencyNumber/lint-baseline.xml b/packages/SettingsLib/EmergencyNumber/lint-baseline.xml
index e9c687fd3227..13bf5f54ead3 100644
--- a/packages/SettingsLib/EmergencyNumber/lint-baseline.xml
+++ b/packages/SettingsLib/EmergencyNumber/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
@@ -8,7 +8,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="77"
+ line="81"
column="41"/>
</issue>
@@ -19,7 +19,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="78"
+ line="82"
column="45"/>
</issue>
@@ -30,18 +30,18 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="78"
+ line="82"
column="62"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 29 (current min is 21): `android.telephony.TelephonyManager#getEmergencyNumberList`"
- errorLine1=" Map&lt;Integer, List&lt;EmergencyNumber>> allLists = mTelephonyManager.getEmergencyNumberList("
+ errorLine1=" Map&lt;Integer, List&lt;EmergencyNumber&gt;&gt; allLists = mTelephonyManager.getEmergencyNumberList("
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="173"
+ line="177"
column="74"/>
</issue>
@@ -52,7 +52,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="196"
+ line="200"
column="41"/>
</issue>
@@ -63,7 +63,7 @@
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="219"
+ line="223"
column="69"/>
</issue>
@@ -74,7 +74,7 @@
errorLine2=" ~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="234"
+ line="238"
column="41"/>
</issue>
@@ -85,8 +85,8 @@
errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/EmergencyNumber/src/com/android/settingslib/emergencynumber/EmergencyNumberUtils.java"
- line="251"
+ line="255"
column="52"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/MainSwitchPreference/Android.bp b/packages/SettingsLib/MainSwitchPreference/Android.bp
index d9f74dadf281..010a6ce9d4d9 100644
--- a/packages/SettingsLib/MainSwitchPreference/Android.bp
+++ b/packages/SettingsLib/MainSwitchPreference/Android.bp
@@ -28,7 +28,4 @@ android_library {
"com.android.extservices",
"com.android.healthfitness",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
diff --git a/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml b/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml
deleted file mode 100644
index cfa64a487407..000000000000
--- a/packages/SettingsLib/MainSwitchPreference/lint-baseline.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
-
- <issue
- id="NewApi"
- message="`@android:dimen/config_restrictedIconSize` requires API level 29 (current min is 28)"
- errorLine1=' &lt;dimen name="settingslib_restricted_icon_size"&gt;@android:dimen/config_restrictedIconSize&lt;/dimen&gt;'
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/MainSwitchPreference/res/values/dimens.xml"
- line="21"
- column="52"/>
- </issue>
-
-</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml b/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
index 26d05a621c22..45a07fe9eee3 100644
--- a/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
+++ b/packages/SettingsLib/RestrictedLockUtils/lint-baseline.xml
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`"
- errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));"
- errorLine2=" ~~">
+ message="Call requires API level 28 (current min is 23): `android.content.Context#createPackageContextAsUser`"
+ errorLine1=" userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="97"
- column="56"/>
+ line="64"
+ column="35"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`"
- errorLine1=" return um.getUserProfiles().contains(UserHandle.of(userId));"
- errorLine2=" ~~">
+ message="Call requires API level 29 (current min is 23): `android.app.admin.DevicePolicyManager#getDeviceOwnerUser`"
+ errorLine1=" if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="140"
- column="57"/>
+ line="74"
+ column="32"/>
</issue>
<issue
@@ -36,35 +36,35 @@
<issue
id="NewApi"
- message="Call requires API level 28 (current min is 23): `android.content.Context#createPackageContextAsUser`"
- errorLine1=" userContext = context.createPackageContextAsUser(context.getPackageName(), 0, user);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`"
+ errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));"
+ errorLine2=" ~~">
<location
file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="64"
- column="35"/>
+ line="97"
+ column="56"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 29 (current min is 23): `android.app.admin.DevicePolicyManager#getDeviceOwnerUser`"
- errorLine1=" if (Objects.equals(dpm.getDeviceOwnerUser(), user)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 29 (current min is 23): `android.content.Context#startActivityAsUser`"
+ errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="74"
- column="32"/>
+ line="97"
+ column="17"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 29 (current min is 23): `android.content.Context#startActivityAsUser`"
- errorLine1=" context.startActivityAsUser(intent, UserHandle.of(targetUserId));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 24 (current min is 23): `android.os.UserHandle#of`"
+ errorLine1=" return um.getUserProfiles().contains(UserHandle.of(userId));"
+ errorLine2=" ~~">
<location
file="frameworks/base/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java"
- line="97"
- column="17"/>
+ line="120"
+ column="57"/>
</issue>
</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/SchedulesProvider/lint-baseline.xml b/packages/SettingsLib/SchedulesProvider/lint-baseline.xml
index 0744710e5224..db6a88210cd4 100644
--- a/packages/SettingsLib/SchedulesProvider/lint-baseline.xml
+++ b/packages/SettingsLib/SchedulesProvider/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
diff --git a/packages/SettingsLib/SearchProvider/lint-baseline.xml b/packages/SettingsLib/SearchProvider/lint-baseline.xml
index 53346e030be2..3cfca1d2cdcb 100644
--- a/packages/SettingsLib/SearchProvider/lint-baseline.xml
+++ b/packages/SettingsLib/SearchProvider/lint-baseline.xml
@@ -1,36 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableResource`"
- errorLine1=" super("
- errorLine2=" ~~~~~">
+ message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexablesProvider`"
+ errorLine1="public abstract class SettingsXmlIndexProvider extends SearchIndexablesProvider {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="107"
- column="13"/>
+ line="34"
+ column="56"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableResource`"
- errorLine1=" public static final class SearchIndexableIntentResource extends SearchIndexableResource {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexablesContract#INDEXABLES_XML_RES_COLUMNS`"
+ errorLine1=" final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="97"
- column="69"/>
+ line="45"
+ column="54"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexablesProvider`"
- errorLine1="public abstract class SettingsXmlIndexProvider extends SearchIndexablesProvider {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#rank`"
+ errorLine1=" .add(XmlResource.COLUMN_RANK, indexableResource.rank)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="34"
+ line="50"
+ column="51"/>
+ </issue>
+
+ <issue
+ id="NewApi"
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableResource#xmlResId`"
+ errorLine1=" .add(XmlResource.COLUMN_XML_RESID, indexableResource.xmlResId)"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
+ line="51"
column="56"/>
</issue>
@@ -58,79 +69,68 @@
<issue
id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`"
- errorLine1=' this.intentAction = "android.intent.action.MAIN";'
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="113"
- column="17"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`"
- errorLine1=" this.intentAction = intentAction;"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`"
+ errorLine1=" indexableResource.intentTargetClass);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="115"
- column="17"/>
+ line="56"
+ column="29"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`"
- errorLine1=" indexableResource.intentTargetClass);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableResource`"
+ errorLine1=" public static final class SearchIndexableIntentResource extends SearchIndexableResource {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="56"
- column="29"/>
+ line="97"
+ column="69"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`"
- errorLine1=" this.intentTargetClass = className;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableResource`"
+ errorLine1=" super("
+ errorLine2=" ~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="117"
+ line="107"
column="13"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#rank`"
- errorLine1=" .add(XmlResource.COLUMN_RANK, indexableResource.rank)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`"
+ errorLine1=' this.intentAction = "android.intent.action.MAIN";'
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="50"
- column="51"/>
+ line="113"
+ column="17"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableResource#xmlResId`"
- errorLine1=" .add(XmlResource.COLUMN_XML_RESID, indexableResource.xmlResId)"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentAction`"
+ errorLine1=" this.intentAction = intentAction;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="51"
- column="56"/>
+ line="115"
+ column="17"/>
</issue>
<issue
id="NewApi"
- message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexablesContract#INDEXABLES_XML_RES_COLUMNS`"
- errorLine1=" final MatrixCursor cursor = new MatrixCursor(INDEXABLES_XML_RES_COLUMNS);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Field requires API level 23 (current min is 21): `android.provider.SearchIndexableData#intentTargetClass`"
+ errorLine1=" this.intentTargetClass = className;"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/SearchProvider/src/com/android/settingslib/searchprovider/SettingsXmlIndexProvider.java"
- line="45"
- column="54"/>
+ line="117"
+ column="13"/>
</issue>
</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
index a9974dc7d389..514ad66919ee 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/ui/Spinner.kt
@@ -39,6 +39,9 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.tooling.preview.Preview
+import androidx.compose.ui.semantics.Role
+import androidx.compose.ui.semantics.role
+import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import com.android.settingslib.spa.framework.theme.SettingsDimension
import com.android.settingslib.spa.framework.theme.SettingsTheme
@@ -68,6 +71,7 @@ fun Spinner(options: List<SpinnerOption>, selectedId: Int?, setId: (id: Int) ->
) {
val contentPadding = PaddingValues(horizontal = SettingsDimension.itemPaddingEnd)
Button(
+ modifier = Modifier.semantics { role = Role.DropdownList },
onClick = { expanded = true },
colors = ButtonDefaults.buttonColors(
containerColor = SettingsTheme.colorScheme.spinnerHeaderContainer,
diff --git a/packages/SettingsLib/Tile/lint-baseline.xml b/packages/SettingsLib/Tile/lint-baseline.xml
index 326ec0dbaa72..56b1bcafbae2 100644
--- a/packages/SettingsLib/Tile/lint-baseline.xml
+++ b/packages/SettingsLib/Tile/lint-baseline.xml
@@ -1,55 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 24 (current min is 21): `java.lang.Iterable#forEach`"
- errorLine1=" controllers.forEach(controller -&gt; {"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/SwitchesProvider.java"
- line="79"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#createWithResource`">
+ message="Call requires API level 29 (current min is 21): `android.os.Parcel#writeBoolean`"
+ errorLine1=" dest.writeBoolean(this instanceof ProviderTile);"
+ errorLine2=" ~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java"
- line="312"/>
+ line="114"
+ column="14"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#setTint`">
+ message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#createWithResource`"
+ errorLine1=" final Icon icon = Icon.createWithResource(componentInfo.packageName, iconResId);"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java"
- line="318"/>
+ line="326"
+ column="36"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 29 (current min is 21): `android.os.Parcel#readBoolean`">
+ message="Call requires API level 23 (current min is 21): `android.graphics.drawable.Icon#setTint`"
+ errorLine1=" icon.setTint(tintColor);"
+ errorLine2=" ~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java"
- line="373"/>
+ line="332"
+ column="22"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 29 (current min is 21): `android.os.Parcel#writeBoolean`">
+ message="Call requires API level 29 (current min is 21): `android.os.Parcel#readBoolean`"
+ errorLine1=" final boolean isProviderTile = source.readBoolean();"
+ errorLine2=" ~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/Tile.java"
- line="108"/>
+ line="387"
+ column="51"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 31 (current min is 21): `android.content.Context#getAttributionSource`">
+ message="Call requires API level 31 (current min is 21): `android.content.Context#getAttributionSource`"
+ errorLine1=" return provider.call(context.getAttributionSource(),"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Tile/src/com/android/settingslib/drawer/TileUtils.java"
- line="565"/>
+ line="601"
+ column="42"/>
</issue>
</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/Utils/lint-baseline.xml b/packages/SettingsLib/Utils/lint-baseline.xml
index 3fcd56c557e8..2f6cc3ae8719 100644
--- a/packages/SettingsLib/Utils/lint-baseline.xml
+++ b/packages/SettingsLib/Utils/lint-baseline.xml
@@ -1,26 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`"
- errorLine1=" mContext.getPackageName(), 0, UserHandle.of(managedUserId)"
- errorLine2=" ~~">
- <location
- file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="119"
- column="70"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`"
- errorLine1=" intent, 0, UserHandle.of(managedUserId));"
- errorLine2=" ~~">
+ message="Call requires API level 24 (current min is 23): `android.os.UserManager#isManagedProfile`"
+ errorLine1=" return context.getSystemService(UserManager.class).isManagedProfile(userId)"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
<location
- file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="150"
- column="47"/>
+ file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java"
+ line="62"
+ column="60"/>
</issue>
<issue
@@ -36,68 +25,68 @@
<issue
id="NewApi"
- message="Call requires API level 24 (current min is 21): `android.os.UserManager#isManagedProfile`"
- errorLine1=" if (mUserManager.isManagedProfile(id)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~">
+ message="Call requires API level 29 (current min is 21): `android.content.Context#startActivityAsUser`"
+ errorLine1=" activityContext.startActivityAsUser(intent, UserHandle.of(userId));"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="173"
- column="30"/>
+ line="80"
+ column="29"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 24 (current min is 23): `android.os.UserManager#isManagedProfile`"
- errorLine1=" return context.getSystemService(UserManager.class).isManagedProfile(userId)"
- errorLine2=" ~~~~~~~~~~~~~~~~">
+ message="Call requires API level 28 (current min is 21): `android.content.Context#createPackageContextAsUser`"
+ errorLine1=" mContext.createPackageContextAsUser("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
- file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java"
- line="62"
- column="60"/>
+ file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
+ line="118"
+ column="30"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 26 (current min is 21): `android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser`"
- errorLine1=" return mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`"
+ errorLine1=" mContext.getPackageName(), 0, UserHandle.of(managedUserId)"
+ errorLine2=" ~~">
<location
file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="163"
- column="37"/>
+ line="119"
+ column="70"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 28 (current min is 21): `android.content.Context#createPackageContextAsUser`"
- errorLine1=" mContext.createPackageContextAsUser("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 29 (current min is 21): `android.content.pm.PackageManager#queryIntentActivitiesAsUser`"
+ errorLine1=" mPackageManager.queryIntentActivitiesAsUser("
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="118"
- column="30"/>
+ line="149"
+ column="33"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 29 (current min is 21): `android.content.Context#startActivityAsUser`"
- errorLine1=" activityContext.startActivityAsUser(intent, UserHandle.of(userId));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 24 (current min is 21): `android.os.UserHandle#of`"
+ errorLine1=" intent, 0, UserHandle.of(managedUserId));"
+ errorLine2=" ~~">
<location
file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="80"
- column="29"/>
+ line="150"
+ column="47"/>
</issue>
<issue
id="NewApi"
- message="Call requires API level 29 (current min is 21): `android.content.pm.PackageManager#queryIntentActivitiesAsUser`"
- errorLine1=" mPackageManager.queryIntentActivitiesAsUser("
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 26 (current min is 21): `android.app.admin.DevicePolicyManager#getDeviceOwnerComponentOnAnyUser`"
+ errorLine1=" return mDevicePolicyManager.getDeviceOwnerComponentOnAnyUser();"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
- line="149"
- column="33"/>
+ line="163"
+ column="37"/>
</issue>
<issue
@@ -111,4 +100,15 @@
column="53"/>
</issue>
+ <issue
+ id="NewApi"
+ message="Call requires API level 24 (current min is 21): `android.os.UserManager#isManagedProfile`"
+ errorLine1=" if (mUserManager.isManagedProfile(id)) {"
+ errorLine2=" ~~~~~~~~~~~~~~~~">
+ <location
+ file="frameworks/base/packages/SettingsLib/Utils/src/com/android/settingslib/utils/WorkPolicyUtils.java"
+ line="173"
+ column="30"/>
+ </issue>
+
</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/lint-baseline.xml b/packages/SettingsLib/lint-baseline.xml
deleted file mode 100644
index d6a23fd827d9..000000000000
--- a/packages/SettingsLib/lint-baseline.xml
+++ /dev/null
@@ -1,204 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 4.1.0" client="cli" variant="all" version="4.1.0">
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.bluetooth.BluetoothDevice#setAlias`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java"
- line="584"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiInfo#getSubscriptionId`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java"
- line="248"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiInfo#getSubscriptionId`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStatusTracker.java"
- line="278"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiManager#registerSubsystemRestartTrackingCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java"
- line="201"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.net.wifi.WifiManager#unregisterSubsystemRestartTrackingCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java"
- line="208"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.os.UserManager#isUserForeground`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/enterprise/ManagedDeviceActionDisabledByAdminController.java"
- line="78"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#isDataCapable`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/Utils.java"
- line="498"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#isDataCapable`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/net/DataUsageController.java"
- line="225"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#registerTelephonyCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java"
- line="215"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#registerTelephonyCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="86"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#unregisterTelephonyCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java"
- line="222"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 30): `android.telephony.TelephonyManager#unregisterTelephonyCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="88"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 34 (current min is 30): `android.os.UserManager#isAdminUser`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java"
- line="66"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 34 (current min is 30): `android.os.UserManager#isAdminUser`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/development/DevelopmentSettingsEnabler.java"
- line="49"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 34 (current min is 30): `android.os.UserManager#isAdminUser`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractSimStatusImeiInfoPreferenceController.java"
- line="33"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.net.wifi.WifiManager.SubsystemRestartTrackingCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java"
- line="64"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="125"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.CarrierNetworkListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="124"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.DataActivityListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="123"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.DataConnectionStateListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="122"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.DisplayInfoListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="126"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.ServiceStateListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="120"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback.SignalStrengthsListener`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="121"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/connectivity/ConnectivitySubsystemsRecoveryManager.java"
- line="79"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Class requires API level 31 (current min is 30): `android.telephony.TelephonyCallback`">
- <location
- file="frameworks/base/packages/SettingsLib/src/com/android/settingslib/mobile/MobileStatusTracker.java"
- line="119"/>
- </issue>
-
-</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/search/Android.bp b/packages/SettingsLib/search/Android.bp
index 3b14712cc87e..390c9d2e98de 100644
--- a/packages/SettingsLib/search/Android.bp
+++ b/packages/SettingsLib/search/Android.bp
@@ -12,9 +12,6 @@ java_library {
visibility: ["//visibility:private"],
srcs: ["interface-src/**/*.java"],
host_supported: true,
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
android_library {
diff --git a/packages/SettingsLib/search/lint-baseline.xml b/packages/SettingsLib/search/lint-baseline.xml
index 7ec512b617d7..61cdb051feeb 100644
--- a/packages/SettingsLib/search/lint-baseline.xml
+++ b/packages/SettingsLib/search/lint-baseline.xml
@@ -1,26 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.0.0-dev" type="baseline" dependencies="true" variant="all" version="8.0.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
- message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableData`"
- errorLine1=" super(context);"
- errorLine2=" ~~~~~">
+ message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableData`"
+ errorLine1="public class SearchIndexableRaw extends SearchIndexableData {"
+ errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="frameworks/base/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableRaw.java"
- line="62"
- column="9"/>
+ line="29"
+ column="41"/>
</issue>
<issue
id="NewApi"
- message="Class requires API level 23 (current min is 21): `android.provider.SearchIndexableData`"
- errorLine1="public class SearchIndexableRaw extends SearchIndexableData {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~">
+ message="Call requires API level 23 (current min is 21): `new android.provider.SearchIndexableData`"
+ errorLine1=" super(context);"
+ errorLine2=" ~~~~~">
<location
file="frameworks/base/packages/SettingsLib/search/src/com/android/settingslib/search/SearchIndexableRaw.java"
- line="29"
- column="41"/>
+ line="62"
+ column="9"/>
</issue>
</issues> \ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
index 5bc271954b25..943e3fc27ebb 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/AbstractWifiMacAddressPreferenceController.java
@@ -70,10 +70,8 @@ public abstract class AbstractWifiMacAddressPreferenceController
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
- if (isAvailable()) {
- mWifiMacAddress = screen.findPreference(KEY_WIFI_MAC_ADDRESS);
- updateConnectivity();
- }
+ mWifiMacAddress = screen.findPreference(KEY_WIFI_MAC_ADDRESS);
+ updateConnectivity();
}
@Override
@@ -84,16 +82,16 @@ public abstract class AbstractWifiMacAddressPreferenceController
@SuppressLint("HardwareIds")
@Override
protected void updateConnectivity() {
+ if (mWifiManager == null || mWifiMacAddress == null) {
+ return;
+ }
+
final String[] macAddresses = mWifiManager.getFactoryMacAddresses();
String macAddress = null;
if (macAddresses != null && macAddresses.length > 0) {
macAddress = macAddresses[0];
}
- if (mWifiMacAddress == null) {
- return;
- }
-
if (TextUtils.isEmpty(macAddress) || macAddress.equals(WifiInfo.DEFAULT_MAC_ADDRESS)) {
mWifiMacAddress.setSummary(R.string.status_unavailable);
} else {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
index 24fd06e51418..e7487e857464 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/HearingAidDeviceManagerTest.java
@@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
@@ -73,13 +74,13 @@ public class HearingAidDeviceManagerTest {
private final static String DEVICE_ADDRESS_2 = "AA:BB:CC:DD:EE:22";
private final BluetoothClass DEVICE_CLASS =
createBtClass(BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE);
+ private final Context mContext = ApplicationProvider.getApplicationContext();
private CachedBluetoothDevice mCachedDevice1;
private CachedBluetoothDevice mCachedDevice2;
private CachedBluetoothDeviceManager mCachedDeviceManager;
private HearingAidDeviceManager mHearingAidDeviceManager;
private AudioDeviceAttributes mHearingDeviceAttribute;
- private final Context mContext = ApplicationProvider.getApplicationContext();
@Spy
private HearingAidAudioRoutingHelper mHelper = new HearingAidAudioRoutingHelper(mContext);
@Mock
@@ -517,6 +518,8 @@ public class HearingAidDeviceManagerTest {
when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
mHearingDeviceAttribute);
when(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(true);
+ doReturn(true).when(mHelper).setPreferredDeviceRoutingStrategies(anyList(),
+ eq(mHearingDeviceAttribute), anyInt());
mHearingAidDeviceManager.onActiveDeviceChanged(mCachedDevice1);
@@ -529,6 +532,8 @@ public class HearingAidDeviceManagerTest {
when(mHelper.getMatchedHearingDeviceAttributes(mCachedDevice1)).thenReturn(
mHearingDeviceAttribute);
when(mCachedDevice1.isActiveDevice(BluetoothProfile.HEARING_AID)).thenReturn(false);
+ doReturn(true).when(mHelper).setPreferredDeviceRoutingStrategies(anyList(), any(),
+ anyInt());
mHearingAidDeviceManager.onActiveDeviceChanged(mCachedDevice1);
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
index d47527a0a191..2fea6a56daaf 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalContainer.kt
@@ -7,7 +7,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Close
@@ -21,10 +20,8 @@ import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
-import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.pointer.pointerInteropFilter
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.ElementKey
@@ -41,7 +38,6 @@ import com.android.compose.animation.scene.updateSceneTransitionLayoutState
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.communal.ui.viewmodel.BaseCommunalViewModel
-import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.transform
@@ -66,7 +62,6 @@ val sceneTransitions = transitions {
* This is a temporary container to allow the communal UI to use [SceneTransitionLayout] for gesture
* handling and transitions before the full Flexiglass layout is ready.
*/
-@OptIn(ExperimentalComposeUiApi::class, ExperimentalCoroutinesApi::class)
@Composable
fun CommunalContainer(
modifier: Modifier = Modifier,
@@ -83,8 +78,8 @@ fun CommunalContainer(
transitions = sceneTransitions,
)
- // Don't show hub mode UI if keyguard is present. This is important since we're in the shade,
- // which can be opened from many locations.
+ // Don't show hub mode UI if keyguard is not present. This is important since we're in the
+ // shade, which can be opened from many locations.
val isKeyguardShowing by viewModel.isKeyguardVisible.collectAsState(initial = false)
// Failsafe to hide the whole SceneTransitionLayout in case of bugginess.
@@ -102,56 +97,30 @@ fun CommunalContainer(
onDispose { viewModel.setTransitionState(null) }
}
- Box(modifier = modifier.fillMaxSize()) {
- SceneTransitionLayout(
- state = sceneTransitionLayoutState,
- modifier = Modifier.fillMaxSize(),
- edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
+ SceneTransitionLayout(
+ state = sceneTransitionLayoutState,
+ modifier = modifier.fillMaxSize(),
+ edgeDetector = FixedSizeEdgeDetector(ContainerDimensions.EdgeSwipeSize),
+ ) {
+ scene(
+ TransitionSceneKey.Blank,
+ userActions =
+ mapOf(
+ Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to TransitionSceneKey.Communal
+ )
) {
- scene(
- TransitionSceneKey.Blank,
- userActions =
- mapOf(
- Swipe(SwipeDirection.Left, fromEdge = Edge.Right) to
- TransitionSceneKey.Communal
- )
- ) {
- BlankScene { showSceneTransitionLayout = false }
- }
-
- scene(
- TransitionSceneKey.Communal,
- userActions =
- mapOf(
- Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to
- TransitionSceneKey.Blank
- ),
- ) {
- CommunalScene(viewModel, modifier = modifier)
- }
+ BlankScene { showSceneTransitionLayout = false }
}
- // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't
- // block touches anymore.
- Box(
- modifier =
- Modifier.fillMaxSize()
- // Offsetting to the left so that edge swipe to open the hub still works. This
- // does mean that the very right edge of the hub won't refresh the screen
- // timeout, but should be good enough for a temporary solution.
- .offset(x = -ContainerDimensions.EdgeSwipeSize)
- .pointerInteropFilter {
- viewModel.onUserActivity()
- if (
- sceneTransitionLayoutState.transitionState.currentScene ==
- TransitionSceneKey.Blank
- ) {
- viewModel.onOuterTouch(it)
- return@pointerInteropFilter true
- }
- false
- }
- )
+ scene(
+ TransitionSceneKey.Communal,
+ userActions =
+ mapOf(
+ Swipe(SwipeDirection.Right, fromEdge = Edge.Left) to TransitionSceneKey.Blank
+ ),
+ ) {
+ CommunalScene(viewModel, modifier = modifier)
+ }
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt
index 0acc76f8d4ef..b346a70e61f9 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/PunchHole.kt
@@ -20,24 +20,26 @@ import androidx.compose.runtime.Stable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
-import androidx.compose.ui.geometry.toRect
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.CompositingStrategy
import androidx.compose.ui.graphics.Outline
-import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.drawOutline
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
import androidx.compose.ui.graphics.drawscope.DrawScope
-import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.translate
-import androidx.compose.ui.graphics.withSaveLayer
import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
import androidx.compose.ui.node.DelegatingNode
import androidx.compose.ui.node.DrawModifierNode
import androidx.compose.ui.node.GlobalPositionAwareModifierNode
+import androidx.compose.ui.node.LayoutModifierNode
import androidx.compose.ui.node.ModifierNodeElement
+import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.toSize
@@ -88,25 +90,29 @@ private class PunchHoleNode(
var size: () -> Size,
var offset: () -> Offset,
var shape: () -> Shape,
-) : Modifier.Node(), DrawModifierNode {
+) : Modifier.Node(), DrawModifierNode, LayoutModifierNode {
private var lastSize: Size = Size.Unspecified
private var lastLayoutDirection: LayoutDirection = LayoutDirection.Ltr
private var lastOutline: Outline? = null
- override fun ContentDrawScope.draw() {
- val holeSize = size()
- if (holeSize == Size.Zero) {
- drawContent()
- return
+ override fun MeasureScope.measure(
+ measurable: Measurable,
+ constraints: Constraints
+ ): MeasureResult {
+ return measurable.measure(constraints).run {
+ layout(width, height) {
+ placeWithLayer(0, 0) { compositingStrategy = CompositingStrategy.Offscreen }
+ }
}
+ }
- drawIntoCanvas { canvas ->
- canvas.withSaveLayer(size.toRect(), Paint()) {
- drawContent()
+ override fun ContentDrawScope.draw() {
+ drawContent()
- val offset = offset()
- translate(offset.x, offset.y) { drawHole(holeSize) }
- }
+ val holeSize = size()
+ if (holeSize != Size.Zero) {
+ val offset = offset()
+ translate(offset.x, offset.y) { drawHole(holeSize) }
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
index c05591900aa0..64388b7653e0 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneGestureHandler.kt
@@ -315,10 +315,13 @@ internal class SceneGestureHandler(
with(layoutImpl.state) { coroutineScope.onChangeScene(targetScene.key) }
}
- animateOffset(
+ swipeTransition.animateOffset(
+ coroutineScope = coroutineScope,
initialVelocity = velocity,
targetOffset = targetOffset,
- targetScene = targetScene.key
+ onAnimationCompleted = {
+ layoutState.finishTransition(swipeTransition, idleScene = targetScene.key)
+ }
)
}
@@ -410,34 +413,6 @@ internal class SceneGestureHandler(
}
}
- private fun animateOffset(
- initialVelocity: Float,
- targetOffset: Float,
- targetScene: SceneKey,
- ) {
- swipeTransition.startOffsetAnimation {
- coroutineScope.launch {
- if (!swipeTransition.isAnimatingOffset) {
- swipeTransition.offsetAnimatable.snapTo(swipeTransition.dragOffset)
- }
- swipeTransition.isAnimatingOffset = true
-
- swipeTransition.offsetAnimatable.animateTo(
- targetOffset,
- // TODO(b/290184746): Make this spring spec configurable.
- spring(
- stiffness = Spring.StiffnessMediumLow,
- visibilityThreshold = OffsetVisibilityThreshold
- ),
- initialVelocity = initialVelocity,
- )
-
- swipeTransition.finishOffsetAnimation()
- layoutState.finishTransition(swipeTransition, targetScene)
- }
- }
- }
-
internal class SwipeTransition(
val _fromScene: Scene,
val _toScene: Scene,
@@ -479,12 +454,14 @@ internal class SceneGestureHandler(
private var offsetAnimationJob: Job? = null
/** Ends any previous [offsetAnimationJob] and runs the new [job]. */
- fun startOffsetAnimation(job: () -> Job) {
+ private fun startOffsetAnimation(job: () -> Job) {
cancelOffsetAnimation()
offsetAnimationJob = job()
}
/** Cancel any ongoing offset animation. */
+ // TODO(b/317063114) This should be a suspended function to avoid multiple jobs running at
+ // the same time.
fun cancelOffsetAnimation() {
offsetAnimationJob?.cancel()
finishOffsetAnimation()
@@ -496,6 +473,43 @@ internal class SceneGestureHandler(
dragOffset = offsetAnimatable.value
}
}
+
+ // TODO(b/290184746): Make this spring spec configurable.
+ private val animationSpec =
+ spring(
+ stiffness = Spring.StiffnessMediumLow,
+ visibilityThreshold = OffsetVisibilityThreshold
+ )
+
+ fun animateOffset(
+ // TODO(b/317063114) The CoroutineScope should be removed.
+ coroutineScope: CoroutineScope,
+ initialVelocity: Float,
+ targetOffset: Float,
+ onAnimationCompleted: () -> Unit,
+ ) {
+ startOffsetAnimation {
+ coroutineScope.launch {
+ animateOffset(targetOffset, initialVelocity)
+ onAnimationCompleted()
+ }
+ }
+ }
+
+ private suspend fun animateOffset(targetOffset: Float, initialVelocity: Float) {
+ if (!isAnimatingOffset) {
+ offsetAnimatable.snapTo(dragOffset)
+ }
+ isAnimatingOffset = true
+
+ offsetAnimatable.animateTo(
+ targetValue = targetOffset,
+ animationSpec = animationSpec,
+ initialVelocity = initialVelocity,
+ )
+
+ finishOffsetAnimation()
+ }
}
companion object {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
index c8461d2c5415..02d30c5ea20a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.kt
@@ -197,7 +197,6 @@ class KeyguardSecurityContainerControllerTest : SysuiTestCase() {
whenever(deviceProvisionedController.isUserSetup(anyInt())).thenReturn(true)
featureFlags = FakeFeatureFlags()
- featureFlags.set(Flags.BOUNCER_USER_SWITCHER, false)
featureFlags.set(Flags.KEYGUARD_WM_STATE_REFACTOR, false)
featureFlags.set(Flags.REFACTOR_KEYGUARD_DISMISS_INTENT, false)
featureFlags.set(Flags.LOCKSCREEN_ENABLE_LANDSCAPE, false)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 1c1335f0db4d..343280de17b8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -801,6 +801,20 @@ public class AuthControllerTest extends SysuiTestCase {
}
@Test
+ public void testOnBiometricPromptDismissedCallback_hideAuthenticationDialog() {
+ // GIVEN a callback is registered
+ AuthController.Callback callback = mock(AuthController.Callback.class);
+ mAuthController.addCallback(callback);
+
+ // WHEN dialog is shown and then dismissed
+ showDialog(new int[]{1} /* sensorIds */, false /* credentialAllowed */);
+ mAuthController.hideAuthenticationDialog(mAuthController.mCurrentDialog.getRequestId());
+
+ // THEN callback should be received
+ verify(callback).onBiometricPromptDismissed();
+ }
+
+ @Test
public void testSubscribesToLogContext() {
mAuthController.setBiometricContextListener(mContextListener);
verify(mLogContextInteractor).addBiometricContextListener(same(mContextListener));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index cec2d7459817..a59a4b864ac4 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1219,6 +1219,40 @@ public class UdfpsControllerTest extends SysuiTestCase {
}
@Test
+ public void onDownTouchReceivedWithoutPreviousUp() throws RemoteException {
+ final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+ 0L);
+ final TouchProcessorResult processorResultDown =
+ new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
+ -1 /* pointerId */, touchData);
+
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricRequestConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+ // WHEN ACTION_DOWN is received and touch is within sensor
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultDown);
+ MotionEvent firstDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, firstDownEvent);
+ mBiometricExecutor.runAllReady();
+ firstDownEvent.recycle();
+
+ // And another ACTION_DOWN is received without an ACTION_UP before
+ MotionEvent secondDownEvent = MotionEvent.obtain(0, 0, ACTION_DOWN, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, secondDownEvent);
+ mBiometricExecutor.runAllReady();
+ secondDownEvent.recycle();
+
+ // THEN the touch is still processed
+ verify(mFingerprintManager, times(2)).onPointerDown(anyLong(), anyInt(), anyInt(),
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
+ anyBoolean());
+ }
+
+ @Test
public void onTouch_pilferPointerWhenAltBouncerShowing()
throws RemoteException {
final Pair<TouchProcessorResult, TouchProcessorResult> touchProcessorResult =
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
index ff6fd43745df..54510a82201a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalEditModeViewModelTest.kt
@@ -21,7 +21,6 @@ import android.app.Activity.RESULT_OK
import android.app.smartspace.SmartspaceTarget
import android.appwidget.AppWidgetHost
import android.content.ComponentName
-import android.os.PowerManager
import android.provider.Settings
import android.widget.RemoteViews
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -41,13 +40,11 @@ import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.kosmos.testScope
import com.android.systemui.media.controls.ui.MediaHost
-import com.android.systemui.shade.ShadeViewController
import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
@@ -64,8 +61,6 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidJUnit4::class)
class CommunalEditModeViewModelTest : SysuiTestCase() {
@Mock private lateinit var mediaHost: MediaHost
- @Mock private lateinit var shadeViewController: ShadeViewController
- @Mock private lateinit var powerManager: PowerManager
@Mock private lateinit var appWidgetHost: AppWidgetHost
@Mock private lateinit var uiEventLogger: UiEventLogger
@@ -97,8 +92,6 @@ class CommunalEditModeViewModelTest : SysuiTestCase() {
CommunalEditModeViewModel(
withDeps.communalInteractor,
appWidgetHost,
- Provider { shadeViewController },
- powerManager,
mediaHost,
uiEventLogger,
)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index 8e3f66464de6..a7760621e97c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -17,7 +17,6 @@
package com.android.systemui.communal.view.viewmodel
import android.app.smartspace.SmartspaceTarget
-import android.os.PowerManager
import android.provider.Settings
import android.widget.RemoteViews
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -36,12 +35,10 @@ import com.android.systemui.communal.widgets.WidgetInteractionHandler
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
import com.android.systemui.media.controls.ui.MediaHost
-import com.android.systemui.shade.ShadeViewController
import com.android.systemui.smartspace.data.repository.FakeSmartspaceRepository
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
-import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceTimeBy
@@ -58,8 +55,6 @@ import org.mockito.MockitoAnnotations
@RunWith(AndroidJUnit4::class)
class CommunalViewModelTest : SysuiTestCase() {
@Mock private lateinit var mediaHost: MediaHost
- @Mock private lateinit var shadeViewController: ShadeViewController
- @Mock private lateinit var powerManager: PowerManager
private lateinit var testScope: TestScope
@@ -92,8 +87,6 @@ class CommunalViewModelTest : SysuiTestCase() {
withDeps.communalInteractor,
WidgetInteractionHandler(mock()),
withDeps.tutorialInteractor,
- Provider { shadeViewController },
- powerManager,
mediaHost,
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
index bd1c310ab8de..c1049773cabf 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandlerTest.kt
@@ -16,32 +16,45 @@
package com.android.systemui.qs.tiles.base.actions
+import android.app.PendingIntent
+import android.content.ComponentName
import android.content.Intent
+import android.content.pm.ActivityInfo
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.ResolveInfoFlags
+import android.content.pm.ResolveInfo
+import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.util.mockito.argThat
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentMatcher
import org.mockito.Mock
import org.mockito.Mockito.any
import org.mockito.Mockito.eq
+import org.mockito.Mockito.never
import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidJUnit4::class)
class QSTileIntentUserInputHandlerTest : SysuiTestCase() {
-
- @Mock private lateinit var activityStarted: ActivityStarter
+ @Mock private lateinit var packageManager: PackageManager
+ @Mock private lateinit var activityStarter: ActivityStarter
lateinit var underTest: QSTileIntentUserInputHandler
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
- underTest = QSTileIntentUserInputHandlerImpl(activityStarted)
+ underTest = QSTileIntentUserInputHandlerImpl(activityStarter, packageManager, user)
}
@Test
@@ -50,6 +63,103 @@ class QSTileIntentUserInputHandlerTest : SysuiTestCase() {
underTest.handle(null, intent)
- verify(activityStarted).postStartActivityDismissingKeyguard(eq(intent), eq(0), any())
+ verify(activityStarter).postStartActivityDismissingKeyguard(eq(intent), eq(0), any())
+ }
+
+ @Test
+ fun testPassesActivityPendingIntentToStarterAsPendingIntent() {
+ val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) }
+
+ underTest.handle(null, pendingIntent, true)
+
+ verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any())
+ }
+
+ @Test
+ fun testPassesActivityPendingIntentToStarterAsPendingIntentWhenNotRequestingActivityStart() {
+ val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(true) }
+
+ underTest.handle(null, pendingIntent, false)
+
+ verify(activityStarter).postStartActivityDismissingKeyguard(eq(pendingIntent), any())
+ }
+
+ @Test
+ fun testPassNonActivityPendingIntentAndRequestStartingActivity_findsIntentAndStarts() {
+ val pendingIntent =
+ mock<PendingIntent> {
+ whenever(isActivity).thenReturn(false)
+ whenever(creatorPackage).thenReturn(ORIGINAL_PACKAGE)
+ }
+ setUpQueryResult(listOf(createActivityInfo(testResolvedComponent, exported = true)))
+
+ underTest.handle(null, pendingIntent, true)
+
+ val expectedIntent =
+ Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(null)
+ .addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ )
+ .setComponent(testResolvedComponent)
+
+ verify(activityStarter)
+ .postStartActivityDismissingKeyguard(
+ argThat(IntentMatcher(expectedIntent)),
+ eq(0),
+ any()
+ )
+ }
+
+ @Test
+ fun testPassNonActivityPendingIntentAndDoNotRequestStartingActivity_doesNotStartActivity() {
+ val pendingIntent = mock<PendingIntent> { whenever(isActivity).thenReturn(false) }
+
+ underTest.handle(null, pendingIntent, false)
+
+ verify(activityStarter, never())
+ .postStartActivityDismissingKeyguard(any(Intent::class.java), eq(0), any())
+ }
+
+ private fun createActivityInfo(
+ componentName: ComponentName,
+ exported: Boolean = false,
+ ): ActivityInfo {
+ return ActivityInfo().apply {
+ packageName = componentName.packageName
+ name = componentName.className
+ this.exported = exported
+ }
+ }
+
+ private fun setUpQueryResult(infos: List<ActivityInfo>) {
+ `when`(
+ packageManager.queryIntentActivitiesAsUser(
+ any(Intent::class.java),
+ any(ResolveInfoFlags::class.java),
+ eq(user.identifier)
+ )
+ )
+ .thenReturn(infos.map { ResolveInfo().apply { activityInfo = it } })
+ }
+
+ private class IntentMatcher(intent: Intent) : ArgumentMatcher<Intent> {
+ private val expectedIntent = intent
+ override fun matches(argument: Intent?): Boolean {
+ return argument?.action.equals(expectedIntent.action) &&
+ argument?.`package`.equals(expectedIntent.`package`) &&
+ argument?.component?.equals(expectedIntent.component)!! &&
+ argument?.categories?.equals(expectedIntent.categories)!! &&
+ argument?.flags?.equals(expectedIntent.flags)!!
+ }
+ }
+
+ companion object {
+ private const val ORIGINAL_PACKAGE = "original_pkg"
+ private const val TEST_PACKAGE = "test_pkg"
+ private const val TEST_COMPONENT_CLASS_NAME = "test_component_class_name"
+ private val testResolvedComponent = ComponentName(TEST_PACKAGE, TEST_COMPONENT_CLASS_NAME)
+ private val user = UserHandle.of(0)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt
index e44c8493244c..be2da174250b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractorTest.kt
@@ -18,42 +18,25 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor
import android.app.AlarmManager.AlarmClockInfo
import android.app.PendingIntent
-import android.content.Intent
import android.provider.AlarmClock
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
-import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.tiles.base.actions.FakeQSTileIntentUserInputHandler
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandlerSubject
import com.android.systemui.qs.tiles.base.interactor.QSTileInputTestKtx.click
import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel
-import com.android.systemui.util.mockito.capture
-import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.nullable
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.test.runTest
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
-import org.mockito.ArgumentCaptor
-import org.mockito.Mockito.verify
@SmallTest
@RunWith(AndroidJUnit4::class)
class AlarmTileUserActionInteractorTest : SysuiTestCase() {
- private lateinit var activityStarter: ActivityStarter
- private lateinit var intentCaptor: ArgumentCaptor<Intent>
- private lateinit var pendingIntentCaptor: ArgumentCaptor<PendingIntent>
-
- lateinit var underTest: AlarmTileUserActionInteractor
-
- @Before
- fun setup() {
- activityStarter = mock<ActivityStarter>()
- intentCaptor = ArgumentCaptor.forClass(Intent::class.java)
- pendingIntentCaptor = ArgumentCaptor.forClass(PendingIntent::class.java)
- underTest = AlarmTileUserActionInteractor(activityStarter)
- }
+ private val inputHandler = FakeQSTileIntentUserInputHandler()
+ private val underTest = AlarmTileUserActionInteractor(inputHandler)
@Test
fun handleClickWithDefaultIntent() = runTest {
@@ -62,21 +45,21 @@ class AlarmTileUserActionInteractorTest : SysuiTestCase() {
underTest.handleInput(click(inputModel))
- verify(activityStarter)
- .postStartActivityDismissingKeyguard(capture(intentCaptor), eq(0), nullable())
- assertThat(intentCaptor.value.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS)
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOneIntentInput {
+ assertThat(it.intent.action).isEqualTo(AlarmClock.ACTION_SHOW_ALARMS)
+ }
}
@Test
fun handleClickWithPendingIntent() = runTest {
- val expectedIntent: PendingIntent = mock<PendingIntent>()
+ val expectedIntent = mock<PendingIntent>()
val alarmInfo = AlarmClockInfo(1L, expectedIntent)
val inputModel = AlarmTileModel.NextAlarmSet(true, alarmInfo)
underTest.handleInput(click(inputModel))
- verify(activityStarter)
- .postStartActivityDismissingKeyguard(capture(pendingIntentCaptor), nullable())
- assertThat(pendingIntentCaptor.value).isEqualTo(expectedIntent)
+ QSTileIntentUserInputHandlerSubject.assertThat(inputHandler).handledOnePendingIntentInput {
+ assertThat(it.pendingIntent).isEqualTo(expectedIntent)
+ }
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt
new file mode 100644
index 000000000000..8a0400d092c3
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryImplTest.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.statusbar.NotificationRemoteInputManager
+import com.android.systemui.util.mockito.withArgCaptor
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class RemoteInputRepositoryImplTest : SysuiTestCase() {
+ @Mock private lateinit var remoteInputManager: NotificationRemoteInputManager
+
+ private lateinit var testScope: TestScope
+ private lateinit var underTest: RemoteInputRepositoryImpl
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ testScope = TestScope()
+ underTest = RemoteInputRepositoryImpl(remoteInputManager)
+ }
+
+ @Test
+ fun isRemoteInputActive_updatesOnChange() =
+ testScope.runTest {
+ val active by collectLastValue(underTest.isRemoteInputActive)
+ runCurrent()
+ assertThat(active).isFalse()
+
+ val callback = withArgCaptor {
+ verify(remoteInputManager).addControllerCallback(capture())
+ }
+
+ callback.onRemoteInputActive(true)
+ runCurrent()
+ assertThat(active).isTrue()
+
+ callback.onRemoteInputActive(false)
+ runCurrent()
+ assertThat(active).isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt
new file mode 100644
index 000000000000..12469ddcafc2
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorTest.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.data.repository.fakeRemoteInputRepository
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class RemoteInputInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val fakeRemoteInputRepository = kosmos.fakeRemoteInputRepository
+ private val underTest = kosmos.remoteInputInteractor
+
+ @Test
+ fun isRemoteInputActive_true() =
+ testScope.runTest {
+ val active by collectLastValue(underTest.isRemoteInputActive)
+
+ fakeRemoteInputRepository.isRemoteInputActive.value = true
+ runCurrent()
+
+ assertThat(active).isTrue()
+ }
+
+ @Test
+ fun isRemoteInputActive_false() =
+ testScope.runTest {
+ val active by collectLastValue(underTest.isRemoteInputActive)
+
+ fakeRemoteInputRepository.isRemoteInputActive.value = false
+ runCurrent()
+
+ assertThat(active).isFalse()
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt
new file mode 100644
index 000000000000..ebc81be6d4b6
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.statusbar.policy.data.repository
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener
+import com.android.systemui.statusbar.policy.deviceProvisionedController
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.argumentCaptor
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UserSetupRepositoryTest : SysuiTestCase() {
+
+ private val kosmos = testKosmos()
+
+ private val testScope = kosmos.testScope
+ private val deviceProvisionedController : DeviceProvisionedController = mock()
+
+ private val underTest = UserSetupRepositoryImpl(
+ deviceProvisionedController,
+ kosmos.testDispatcher,
+ kosmos.applicationCoroutineScope,
+ )
+
+ @Test
+ fun userSetup_defaultFalse() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isUserSetUp)
+
+ assertThat(latest).isFalse()
+ }
+
+ @Test
+ fun userSetup_updatesOnChange() =
+ testScope.runTest {
+ val latest by collectLastValue(underTest.isUserSetUp)
+ runCurrent()
+
+ whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
+ val callback = getDeviceProvisionedListener()
+ callback.onUserSetupChanged()
+
+ assertThat(latest).isTrue()
+ }
+
+ private fun getDeviceProvisionedListener(): DeviceProvisionedListener {
+ val captor = argumentCaptor<DeviceProvisionedListener>()
+ verify(deviceProvisionedController).addCallback(captor.capture())
+ return captor.value!!
+ }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt
new file mode 100644
index 000000000000..26c0f80c53de
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorTest.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.policy.data.repository.fakeUserSetupRepository
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class UserSetupInteractorTest : SysuiTestCase() {
+ private val kosmos = testKosmos()
+ private val testScope = kosmos.testScope
+ private val fakeUserSetupRepository = kosmos.fakeUserSetupRepository
+ private val underTest = kosmos.userSetupInteractor
+
+ @Test
+ fun isUserSetup_false() =
+ testScope.runTest {
+ val setup by collectLastValue(underTest.isUserSetUp)
+
+ fakeUserSetupRepository.setUserSetUp(false)
+
+ assertThat(setup).isFalse()
+ }
+
+ @Test
+ fun isUserSetup_true() =
+ testScope.runTest {
+ val setup by collectLastValue(underTest.isUserSetUp)
+
+ fakeUserSetupRepository.setUserSetUp(true)
+
+ assertThat(setup).isTrue()
+ }
+}
diff --git a/packages/SystemUI/res/layout/power_notification_controls_settings.xml b/packages/SystemUI/res/layout/power_notification_controls_settings.xml
deleted file mode 100644
index 83c8a51f6330..000000000000
--- a/packages/SystemUI/res/layout/power_notification_controls_settings.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical">
-
- <include layout="@layout/switch_bar" />
-
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:padding="16dp"
- android:text="@string/power_notification_controls_description"/>
-
-</LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 921be0502c40..19895897ef31 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -449,11 +449,11 @@
<!-- Content description after successful auth when confirmation required -->
<string name="fingerprint_dialog_authenticated_confirmation">Press the unlock icon to continue</string>
<!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
- <string name="fingerprint_dialog_use_fingerprint_instead">Can\u2019t recognize face. Use fingerprint instead.</string>
+ <string name="fingerprint_dialog_use_fingerprint_instead">Face not recognized. Use fingerprint instead.</string>
<!-- Message shown to inform the user a face cannot be recognized and fingerprint should instead be used.[CHAR LIMIT=50] -->
<string name="keyguard_face_failed_use_fp">@string/fingerprint_dialog_use_fingerprint_instead</string>
<!-- Message shown to inform the user a face cannot be recognized. [CHAR LIMIT=25] -->
- <string name="keyguard_face_failed">Can\u2019t recognize face</string>
+ <string name="keyguard_face_failed">Face not recognized</string>
<!-- Message shown to suggest using fingerprint sensor to authenticate after another biometric failed. [CHAR LIMIT=25] -->
<string name="keyguard_suggest_fingerprint">Use fingerprint instead</string>
<!-- Message shown to inform the user that face unlock is not available. [CHAR LIMIT=59] -->
@@ -1612,37 +1612,9 @@
<!-- Bluetooth enablement ok text [CHAR LIMIT=40] -->
<string name="enable_bluetooth_confirmation_ok">Turn on</string>
- <!-- [CHAR LIMIT=NONE] Importance Tuner setting title -->
- <string name="tuner_full_importance_settings">Power notification controls</string>
-
<!-- [CHAR LIMIT=NONE] Notification camera based rotation enabled description -->
<string name="rotation_lock_camera_rotation_on">On - Face-based</string>
- <string name="power_notification_controls_description">With power notification controls, you can set an importance level from 0 to 5 for an app\'s notifications.
- \n\n<b>Level 5</b>
- \n- Show at the top of the notification list
- \n- Allow full screen interruption
- \n- Always peek
- \n\n<b>Level 4</b>
- \n- Prevent full screen interruption
- \n- Always peek
- \n\n<b>Level 3</b>
- \n- Prevent full screen interruption
- \n- Never peek
- \n\n<b>Level 2</b>
- \n- Prevent full screen interruption
- \n- Never peek
- \n- Never make sound and vibration
- \n\n<b>Level 1</b>
- \n- Prevent full screen interruption
- \n- Never peek
- \n- Never make sound or vibrate
- \n- Hide from lock screen and status bar
- \n- Show at the bottom of the notification list
- \n\n<b>Level 0</b>
- \n- Block all notifications from the app
- </string>
-
<!-- Notification Inline controls: button to dismiss the blocking helper [CHAR_LIMIT=20] -->
<string name="inline_done_button">Done</string>
diff --git a/packages/SystemUI/res/xml/other_settings.xml b/packages/SystemUI/res/xml/other_settings.xml
deleted file mode 100644
index 7719d5e03df0..000000000000
--- a/packages/SystemUI/res/xml/other_settings.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-
-<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:sysui="http://schemas.android.com/apk/res-auto"
- android:title="@string/other">
-
- <!-- importance -->
- <Preference
- android:key="power_notification_controls"
- android:title="@string/tuner_full_importance_settings"
- android:fragment="com.android.systemui.tuner.PowerNotificationControlsFragment"/>
-
-</PreferenceScreen>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index 05106c904d3d..326c7ef52fce 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -34,9 +34,6 @@ java_library {
srcs: [
":statslog-SystemUI-java-gen",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
android_library {
@@ -74,9 +71,6 @@ android_library {
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
kotlincflags: ["-Xjvm-default=all"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -88,9 +82,6 @@ java_library {
static_kotlin_stdlib: false,
java_version: "1.8",
min_sdk_version: "current",
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library {
@@ -110,7 +101,4 @@ java_library {
},
java_version: "1.8",
min_sdk_version: "current",
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
diff --git a/packages/SystemUI/shared/lint-baseline.xml b/packages/SystemUI/shared/lint-baseline.xml
deleted file mode 100644
index 4bd6729227e8..000000000000
--- a/packages/SystemUI/shared/lint-baseline.xml
+++ /dev/null
@@ -1,708 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev">
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.os.RemoteException#rethrowFromSystemServer`"
- errorLine1=" throw e.rethrowFromSystemServer();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java"
- line="90"
- column="21"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.graphics.Bitmap#getHardwareBuffer`"
- errorLine1=" mBuffer != null ? mBuffer.getHardwareBuffer() : null, mRect);"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecCompat.java"
- line="39"
- column="43"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `new android.graphics.ParcelableColorSpace`"
- errorLine1=" ? new ParcelableColorSpace(ColorSpace.get(ColorSpace.Named.SRGB))"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java"
- line="57"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `new android.graphics.ParcelableColorSpace`"
- errorLine1=" : new ParcelableColorSpace(bitmap.getColorSpace());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java"
- line="58"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.graphics.Bitmap#getHardwareBuffer`"
- errorLine1=" bundle.putParcelable(KEY_BUFFER, bitmap.getHardwareBuffer());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java"
- line="61"
- column="49"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Cast from `ParcelableColorSpace` to `Parcelable` requires API level 31 (current min is 26)"
- errorLine1=" bundle.putParcelable(KEY_COLOR_SPACE, colorSpace);"
- errorLine2=" ~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java"
- line="62"
- column="47"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.graphics.Bitmap#wrapHardwareBuffer`"
- errorLine1=" return Bitmap.wrapHardwareBuffer(Objects.requireNonNull(buffer),"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java"
- line="84"
- column="23"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.graphics.ParcelableColorSpace#getColorSpace`"
- errorLine1=" colorSpace.getColorSpace());"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/utilities/BitmapUtil.java"
- line="85"
- column="28"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`"
- errorLine1=" final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/pip/PipSurfaceTransactionHelper.java"
- line="122"
- column="47"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.util.ArraySet`"
- errorLine1=" mPluginActions = new ArraySet&lt;>(mSharedPrefs.getStringSet(PLUGIN_ACTIONS, null));"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginPrefs.java"
- line="41"
- column="26"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.util.ArraySet`"
- errorLine1=" return new ArraySet&lt;>(mPluginActions);"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/plugins/PluginPrefs.java"
- line="45"
- column="16"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 28 (current min is 26): `android.graphics.Bitmap#createBitmap`"
- errorLine1=" return Bitmap.createBitmap(picture);"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java"
- line="113"
- column="23"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Builder`"
- errorLine1=" mSurface = new SurfaceControl.Builder()"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="116"
- column="24"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Builder#setName`"
- errorLine1=" .setName(&quot;Transition Unrotate&quot;)"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="117"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Builder#setParent`"
- errorLine1=" .setParent(parent)"
- errorLine2=" ~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="119"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Builder#build`"
- errorLine1=" .build();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="120"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#reparent`"
- errorLine1=" t.reparent(child, mSurface);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="137"
- column="15"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`"
- errorLine1=" SurfaceControl.Transaction t = new SurfaceControl.Transaction();"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="143"
- column="44"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#reparent`"
- errorLine1=" t.reparent(mRotateChildren.get(i), rootLeash);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="145"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`"
- errorLine1=" t.apply();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="148"
- column="15"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" t.setLayer(counterLauncher.mSurface, launcherLayer);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="200"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" t.setLayer(counterLauncher.mSurface, info.getChanges().size() * 3);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="206"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" t.setLayer(leash, info.getChanges().size() * 3 - i);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="216"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`"
- errorLine1=" t.setAlpha(wallpapersCompat[i].leash.getSurfaceControl(), 1.f);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="223"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" t.setLayer(counterWallpaper.mSurface, -1);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="233"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`"
- errorLine1=" t.apply();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java"
- line="238"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#taskId`"
- errorLine1=" taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
- line="101"
- column="49"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`"
- errorLine1=" taskId = change.getTaskInfo() != null ? change.getTaskInfo().taskId : -1;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
- line="192"
- column="49"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#isRunning`"
- errorLine1=" isNotInRecents = !change.getTaskInfo().isRunning;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
- line="116"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#isRunning`"
- errorLine1=" isNotInRecents = !change.getTaskInfo().isRunning;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
- line="210"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#release`"
- errorLine1=" leash.mSurfaceControl.release();"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
- line="159"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#release`"
- errorLine1=" mStartLeash.release();"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java"
- line="161"
- column="25"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" t.setLayer(change.getLeash(), info.getChanges().size() * 3 - i);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java"
- line="97"
- column="27"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`"
- errorLine1=" t.setAlpha(wallpapers[i].leash.mSurfaceControl, 1);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java"
- line="105"
- column="23"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`"
- errorLine1=" t.apply();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java"
- line="107"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#isValid`"
- errorLine1=" return mSurfaceControl != null &amp;&amp; mSurfaceControl.isValid();"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceControlCompat.java"
- line="41"
- column="59"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.SurfaceControlViewHost#release`"
- errorLine1=" mSurfaceControlViewHost.release();"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestReceiver.java"
- line="61"
- column="37"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level R (current min is 26): `android.view.SurfaceView#getHostToken`"
- errorLine1=" bundle.putBinder(KEY_HOST_TOKEN, surfaceView.getHostToken());"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java"
- line="34"
- column="54"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceView#getSurfaceControl`"
- errorLine1=" bundle.putParcelable(KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl());"
- errorLine2=" ~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java"
- line="35"
- column="63"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Cast from `SurfaceControl` to `Parcelable` requires API level 29 (current min is 26)"
- errorLine1=" bundle.putParcelable(KEY_SURFACE_CONTROL, surfaceView.getSurfaceControl());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SurfaceViewRequestUtils.java"
- line="35"
- column="51"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl#isValid`"
- errorLine1=" if (mBarrierSurfaceControl == null || !mBarrierSurfaceControl.isValid()) {"
- errorLine2=" ~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java"
- line="107"
- column="79"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`"
- errorLine1=" Transaction t = new Transaction();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java"
- line="113"
- column="33"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`"
- errorLine1=" t.apply();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java"
- line="122"
- column="23"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`"
- errorLine1=" t.setAlpha(surface, alpha);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java"
- line="361"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" t.setLayer(surface, layer);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/SyncRtSurfaceTransactionApplierCompat.java"
- line="364"
- column="19"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#origActivity`"
- errorLine1=" ComponentName sourceComponent = t.origActivity != null"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java"
- line="73"
- column="45"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#origActivity`"
- errorLine1=" ? t.origActivity"
- errorLine2=" ~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java"
- line="75"
- column="23"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`"
- errorLine1=" this.id = t.taskId;"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java"
- line="78"
- column="23"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#baseIntent`"
- errorLine1=" this.baseIntent = t.baseIntent;"
- errorLine2=" ~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java"
- line="80"
- column="31"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskDescription`"
- errorLine1=" ActivityManager.TaskDescription td = taskInfo.taskDescription;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java"
- line="242"
- column="46"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#topActivity`"
- errorLine1=" taskInfo.supportsSplitScreenMultiWindow, isLocked, td, taskInfo.topActivity);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/Task.java"
- line="246"
- column="72"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#topActivity`"
- errorLine1=" return info.topActivity;"
- errorLine2=" ~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java"
- line="49"
- column="16"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskDescription`"
- errorLine1=" return info.taskDescription;"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskInfoCompat.java"
- line="53"
- column="16"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.ActivityManager.RunningTaskInfo#taskId`"
- errorLine1=" onTaskMovedToFront(taskInfo.taskId);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java"
- line="70"
- column="28"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Field requires API level 29 (current min is 26): `android.app.TaskInfo#taskId`"
- errorLine1=" onTaskMovedToFront(taskInfo.taskId);"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java"
- line="70"
- column="28"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.graphics.Bitmap#wrapHardwareBuffer`"
- errorLine1=" thumbnail = Bitmap.wrapHardwareBuffer(buffer, snapshot.getColorSpace());"
- errorLine2=" ~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/ThumbnailData.java"
- line="69"
- column="36"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 31 (current min is 26): `android.app.WallpaperColors#getColorHints`"
- errorLine1=" (colors.getColorHints() &amp; WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TonalCompat.java"
- line="42"
- column="29"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `new android.view.SurfaceControl.Transaction`"
- errorLine1=" mTransaction = new Transaction();"
- errorLine2=" ~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java"
- line="31"
- column="24"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`"
- errorLine1=" mTransaction.apply();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java"
- line="35"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setBufferSize`"
- errorLine1=" mTransaction.setBufferSize(surfaceControl.mSurfaceControl, w, h);"
- errorLine2=" ~~~~~~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java"
- line="54"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setLayer`"
- errorLine1=" mTransaction.setLayer(surfaceControl.mSurfaceControl, z);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java"
- line="59"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#setAlpha`"
- errorLine1=" mTransaction.setAlpha(surfaceControl.mSurfaceControl, alpha);"
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java"
- line="64"
- column="22"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.view.SurfaceControl.Transaction#apply`"
- errorLine1=" t.apply();"
- errorLine2=" ~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/ViewRootImplCompat.java"
- line="64"
- column="15"/>
- </issue>
-
- <issue
- id="NewApi"
- message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
- errorLine1=" .getFloat(Resources.getSystem().getIdentifier("
- errorLine2=" ~~~~~~~~">
- <location
- file="frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/WallpaperManagerCompat.java"
- line="46"
- column="18"/>
- </issue>
-
-</issues>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
index e457ca18d071..8e5d0dac7bef 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainerController.java
@@ -1111,7 +1111,7 @@ public class KeyguardSecurityContainerController extends ViewController<Keyguard
}
private boolean canDisplayUserSwitcher() {
- return mFeatureFlags.isEnabled(Flags.BOUNCER_USER_SWITCHER);
+ return getContext().getResources().getBoolean(R.bool.config_enableBouncerUserSwitcher);
}
private void configureMode() {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 093a1ffb4635..26f76469d0db 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -1127,6 +1127,9 @@ public class AuthController implements
}
mCurrentDialog.dismissFromSystemServer();
+ for (Callback cb : mCallbacks) {
+ cb.onBiometricPromptDismissed();
+ }
// BiometricService will have already sent the callback to the client in this case.
// This avoids a round trip to SystemUI. So, just dismiss the dialog and we're done.
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index d6646378681a..81de0a283e88 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -187,7 +187,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
@Nullable private UdfpsDisplayModeProvider mUdfpsDisplayMode;
// The ID of the pointer for which ACTION_DOWN has occurred. -1 means no pointer is active.
- private int mActivePointerId = -1;
+ private int mActivePointerId = MotionEvent.INVALID_POINTER_ID;
// Whether a pointer has been pilfered for current gesture
private boolean mPointerPilfered = false;
// The timestamp of the most recent touch log.
@@ -510,7 +510,16 @@ public class UdfpsController implements DozeReceiver, Dumpable {
+ mOverlay.getRequestId());
return false;
}
- if (!DeviceEntryUdfpsRefactor.isEnabled()) {
+ if (event.getAction() == MotionEvent.ACTION_DOWN
+ || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
+ // Reset on ACTION_DOWN, start of new gesture
+ mPointerPilfered = false;
+ if (mActivePointerId != MotionEvent.INVALID_POINTER_ID) {
+ Log.w(TAG, "onTouch down received without a preceding up");
+ }
+ mActivePointerId = MotionEvent.INVALID_POINTER_ID;
+ mOnFingerDown = false;
+ } else if (!DeviceEntryUdfpsRefactor.isEnabled()) {
if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f
&& !mAlternateBouncerInteractor.isVisibleState())
|| mPrimaryBouncerInteractor.isInTransit()) {
@@ -518,11 +527,6 @@ public class UdfpsController implements DozeReceiver, Dumpable {
return false;
}
}
- if (event.getAction() == MotionEvent.ACTION_DOWN
- || event.getAction() == MotionEvent.ACTION_HOVER_ENTER) {
- // Reset on ACTION_DOWN, start of new gesture
- mPointerPilfered = false;
- }
final TouchProcessorResult result = mTouchProcessor.processTouch(event, mActivePointerId,
mOverlayParams);
@@ -1080,7 +1084,7 @@ public class UdfpsController implements DozeReceiver, Dumpable {
long gestureStart,
boolean isAod) {
mExecution.assertIsMainThread();
- mActivePointerId = -1;
+ mActivePointerId = MotionEvent.INVALID_POINTER_ID;
mAcquiredReceived = false;
if (mOnFingerDown) {
mFingerprintManager.onPointerUp(requestId, mSensorProps.sensorId, pointerId, x,
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
index 28f48ce1e647..84708a49f469 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/BaseCommunalViewModel.kt
@@ -17,17 +17,12 @@
package com.android.systemui.communal.ui.viewmodel
import android.content.ComponentName
-import android.os.PowerManager
-import android.os.SystemClock
-import android.view.MotionEvent
import android.widget.RemoteViews
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.model.CommunalContentModel
import com.android.systemui.communal.shared.model.CommunalSceneKey
import com.android.systemui.communal.shared.model.ObservableCommunalTransitionState
import com.android.systemui.media.controls.ui.MediaHost
-import com.android.systemui.shade.ShadeViewController
-import javax.inject.Provider
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOf
@@ -35,8 +30,6 @@ import kotlinx.coroutines.flow.flowOf
/** The base view model for the communal hub. */
abstract class BaseCommunalViewModel(
private val communalInteractor: CommunalInteractor,
- private val shadeViewController: Provider<ShadeViewController>,
- private val powerManager: PowerManager,
val mediaHost: MediaHost,
) {
val isKeyguardVisible: Flow<Boolean> = communalInteractor.isKeyguardVisible
@@ -71,26 +64,6 @@ abstract class BaseCommunalViewModel(
return true
}
- // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block
- // touches anymore.
- /** Called when a touch is received outside the edge swipe area when hub mode is closed. */
- fun onOuterTouch(motionEvent: MotionEvent) {
- // Forward the touch to the shade so that basic gestures like swipe up/down for
- // shade/bouncer work.
- shadeViewController.get().handleExternalTouch(motionEvent)
- }
-
- // TODO(b/308813166): remove once CommunalContainer is moved lower in z-order and doesn't block
- // touches anymore.
- /** Called to refresh the screen timeout when a user touch is received. */
- fun onUserActivity() {
- powerManager.userActivity(
- SystemClock.uptimeMillis(),
- PowerManager.USER_ACTIVITY_EVENT_TOUCH,
- 0
- )
- }
-
/** A list of all the communal content to be displayed in the communal hub. */
abstract val communalContent: Flow<List<CommunalContentModel>>
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
index 0cbf3f1312e2..7faf653cc177 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalEditModeViewModel.kt
@@ -23,7 +23,6 @@ import android.app.ActivityOptions
import android.appwidget.AppWidgetHost
import android.content.ActivityNotFoundException
import android.content.ComponentName
-import android.os.PowerManager
import android.widget.RemoteViews
import com.android.internal.logging.UiEventLogger
import com.android.systemui.communal.domain.interactor.CommunalInteractor
@@ -32,11 +31,9 @@ import com.android.systemui.communal.shared.log.CommunalUiEvent
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.media.controls.ui.MediaHost
import com.android.systemui.media.dagger.MediaModule
-import com.android.systemui.shade.ShadeViewController
import com.android.systemui.util.nullableAtomicReference
import javax.inject.Inject
import javax.inject.Named
-import javax.inject.Provider
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -49,11 +46,9 @@ class CommunalEditModeViewModel
constructor(
private val communalInteractor: CommunalInteractor,
private val appWidgetHost: AppWidgetHost,
- shadeViewController: Provider<ShadeViewController>,
- powerManager: PowerManager,
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
private val uiEventLogger: UiEventLogger,
-) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
+) : BaseCommunalViewModel(communalInteractor, mediaHost) {
private companion object {
private const val KEY_SPLASH_SCREEN_STYLE = "android.activity.splashScreenStyle"
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index 1c696851bb70..7a96fabd2433 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -16,7 +16,6 @@
package com.android.systemui.communal.ui.viewmodel
-import android.os.PowerManager
import android.widget.RemoteViews
import com.android.systemui.communal.domain.interactor.CommunalInteractor
import com.android.systemui.communal.domain.interactor.CommunalTutorialInteractor
@@ -26,10 +25,8 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.media.controls.ui.MediaHost
import com.android.systemui.media.dagger.MediaModule
-import com.android.systemui.shade.ShadeViewController
import javax.inject.Inject
import javax.inject.Named
-import javax.inject.Provider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
@@ -51,10 +48,8 @@ constructor(
private val communalInteractor: CommunalInteractor,
private val interactionHandler: WidgetInteractionHandler,
tutorialInteractor: CommunalTutorialInteractor,
- shadeViewController: Provider<ShadeViewController>,
- powerManager: PowerManager,
@Named(MediaModule.COMMUNAL_HUB) mediaHost: MediaHost,
-) : BaseCommunalViewModel(communalInteractor, shadeViewController, powerManager, mediaHost) {
+) : BaseCommunalViewModel(communalInteractor, mediaHost) {
@OptIn(ExperimentalCoroutinesApi::class)
override val communalContent: Flow<List<CommunalContentModel>> =
tutorialInteractor.isTutorialAvailable.flatMapLatest { isTutorialMode ->
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index 699532cbfca3..7876a6f74293 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -122,11 +122,6 @@ object Flags {
val NEW_UNLOCK_SWIPE_ANIMATION = releasedFlag("new_unlock_swipe_animation")
val CHARGING_RIPPLE = resourceBooleanFlag(R.bool.flag_charging_ripple, "charging_ripple")
- // TODO(b/254512281): Tracking Bug
- @JvmField
- val BOUNCER_USER_SWITCHER =
- resourceBooleanFlag(R.bool.config_enableBouncerUserSwitcher, "bouncer_user_switcher")
-
// TODO(b/254512676): Tracking Bug
@JvmField
val LOCKSCREEN_CUSTOM_CLOCKS =
@@ -353,12 +348,6 @@ object Flags {
// TODO(b/254512673): Tracking Bug
@JvmField val DREAM_MEDIA_TAP_TO_OPEN = unreleasedFlag("dream_media_tap_to_open")
- // TODO(b/254513168): Tracking Bug
- @JvmField val UMO_SURFACE_RIPPLE = releasedFlag("umo_surface_ripple")
-
- // TODO(b/261734857): Tracking Bug
- @JvmField val UMO_TURBULENCE_NOISE = releasedFlag("umo_turbulence_noise")
-
// TODO(b/263272731): Tracking Bug
val MEDIA_TTT_RECEIVER_SUCCESS_RIPPLE = releasedFlag("media_ttt_receiver_success_ripple")
@@ -377,9 +366,6 @@ object Flags {
// 1000 - dock
val SIMULATE_DOCK_THROUGH_CHARGING = releasedFlag("simulate_dock_through_charging")
- // TODO(b/254512758): Tracking Bug
- @JvmField val ROUNDED_BOX_RIPPLE = releasedFlag("rounded_box_ripple")
-
// TODO(b/273509374): Tracking Bug
@JvmField
val ALWAYS_SHOW_HOME_CONTROLS_ON_DREAMS =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
index ecf78d550a3f..b1a2297526ce 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractor.kt
@@ -30,6 +30,7 @@ import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterNotNull
import kotlinx.coroutines.flow.map
@@ -82,10 +83,11 @@ constructor(
*/
val showIndicatorForDeviceEntry: Flow<Boolean> =
combine(showIndicatorForPrimaryBouncer, showIndicatorForAlternateBouncer) {
- showForPrimaryBouncer,
- showForAlternateBouncer ->
- showForPrimaryBouncer || showForAlternateBouncer
- }
+ showForPrimaryBouncer,
+ showForAlternateBouncer ->
+ showForPrimaryBouncer || showForAlternateBouncer
+ }
+ .distinctUntilChanged()
private fun shouldShowIndicatorForPrimaryBouncer(): Boolean {
val sfpsEnabled: Boolean =
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
index 52f2759fe63d..d7a2aa041ffc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAlternateBouncerTransitionInteractor.kt
@@ -18,7 +18,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.sample
import com.android.wm.shell.animation.Interpolators
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
@@ -39,13 +41,18 @@ class FromAlternateBouncerTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
private val powerInteractor: PowerInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.ALTERNATE_BOUNCER,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -65,7 +72,7 @@ constructor(
.sample(
combine(
keyguardInteractor.primaryBouncerShowing,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
powerInteractor.isAwake,
keyguardInteractor.isAodAvailable,
::toQuad
@@ -102,20 +109,19 @@ constructor(
private fun listenForAlternateBouncerToGone() {
scope.launch {
- keyguardInteractor.isKeyguardGoingAway
- .sample(transitionInteractor.finishedKeyguardState, ::Pair)
- .collect { (isKeyguardGoingAway, keyguardState) ->
- if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) {
- startTransitionTo(KeyguardState.GONE)
- }
+ keyguardInteractor.isKeyguardGoingAway.sample(finishedKeyguardState, ::Pair).collect {
+ (isKeyguardGoingAway, keyguardState) ->
+ if (isKeyguardGoingAway && keyguardState == KeyguardState.ALTERNATE_BOUNCER) {
+ startTransitionTo(KeyguardState.GONE)
}
+ }
}
}
private fun listenForAlternateBouncerToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isPrimaryBouncerShowing, startedKeyguardState) ->
if (
isPrimaryBouncerShowing &&
@@ -139,6 +145,7 @@ constructor(
}
companion object {
+ const val TAG = "FromAlternateBouncerTransitionInteractor"
val TRANSITION_DURATION_MS = 300.milliseconds
val TO_GONE_DURATION = 500.milliseconds
val TO_AOD_DURATION = TRANSITION_DURATION_MS
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
index 858440185568..fedd63be1454 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromAodTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.DozeStateModel
@@ -29,6 +30,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -38,12 +40,17 @@ class FromAodTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.AOD,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -58,7 +65,7 @@ constructor(
.dozeTransitionTo(DozeStateModel.FINISH)
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
::Pair
),
@@ -77,7 +84,6 @@ constructor(
} else {
TransitionModeOnCanceled.LAST_VALUE
}
-
startTransitionTo(
toState = toState,
modeOnCanceled = modeOnCanceled,
@@ -89,16 +95,13 @@ constructor(
private fun listenForAodToGone() {
scope.launch {
- keyguardInteractor.biometricUnlockState
- .sample(transitionInteractor.finishedKeyguardState, ::Pair)
- .collect { pair ->
- val (biometricUnlockState, keyguardState) = pair
- if (
- keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)
- ) {
- startTransitionTo(KeyguardState.GONE)
- }
+ keyguardInteractor.biometricUnlockState.sample(finishedKeyguardState, ::Pair).collect {
+ pair ->
+ val (biometricUnlockState, keyguardState) = pair
+ if (keyguardState == KeyguardState.AOD && isWakeAndUnlock(biometricUnlockState)) {
+ startTransitionTo(KeyguardState.GONE)
}
+ }
}
}
override fun getDefaultAnimatorForTransitionsToState(toState: KeyguardState): ValueAnimator {
@@ -113,6 +116,7 @@ constructor(
}
companion object {
+ const val TAG = "FromAodTransitionInteractor"
private val DEFAULT_DURATION = 500.milliseconds
val TO_LOCKSCREEN_DURATION = 500.milliseconds
val TO_GONE_DURATION = DEFAULT_DURATION
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
index eca7088c079a..fcb7698c9bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDozingTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel.Companion.isWakeAndUnlock
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -37,13 +39,18 @@ class FromDozingTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
private val powerInteractor: PowerInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.DOZING,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -57,7 +64,7 @@ constructor(
powerInteractor.isAwake
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
::Pair
),
@@ -76,7 +83,7 @@ constructor(
private fun listenForDozingToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (biometricUnlockState, lastStartedTransition) ->
if (
lastStartedTransition.to == KeyguardState.DOZING &&
@@ -96,6 +103,7 @@ constructor(
}
companion object {
+ const val TAG = "FromDozingTransitionInteractor"
private val DEFAULT_DURATION = 500.milliseconds
val TO_LOCKSCREEN_DURATION = DEFAULT_DURATION
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
index dac6ef5e6082..a6cdaa8c6761 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingLockscreenHostedTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
@@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
@@ -39,12 +41,17 @@ class FromDreamingLockscreenHostedTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.DREAMING_LOCKSCREEN_HOSTED,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -64,7 +71,7 @@ constructor(
.sample(
combine(
keyguardInteractor.dozeTransitionModel,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -88,7 +95,7 @@ constructor(
.sample(
combine(
keyguardInteractor.isKeyguardOccluded,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair,
),
::toTriple
@@ -108,7 +115,7 @@ constructor(
private fun listenForDreamingLockscreenHostedToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isBouncerShowing, lastStartedTransitionStep) ->
if (
isBouncerShowing &&
@@ -123,7 +130,7 @@ constructor(
private fun listenForDreamingLockscreenHostedToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (biometricUnlockState, lastStartedTransitionStep) ->
if (
lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED &&
@@ -137,11 +144,7 @@ constructor(
private fun listenForDreamingLockscreenHostedToDozing() {
scope.launch {
- combine(
- keyguardInteractor.dozeTransitionModel,
- transitionInteractor.startedKeyguardTransitionStep,
- ::Pair
- )
+ combine(keyguardInteractor.dozeTransitionModel, startedKeyguardTransitionStep, ::Pair)
.collect { (dozeTransitionModel, lastStartedTransitionStep) ->
if (
dozeTransitionModel.to == DozeStateModel.DOZE &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
index 7fdcf2f09bc1..13ffd6396cda 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromDreamingTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
@@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -37,12 +39,17 @@ class FromDreamingTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.DREAMING,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -66,7 +73,7 @@ constructor(
private fun listenForDreamingToOccluded() {
scope.launch {
combine(keyguardInteractor.isKeyguardOccluded, keyguardInteractor.isDreaming, ::Pair)
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::toTriple)
+ .sample(startedKeyguardTransitionStep, ::toTriple)
.collect { (isOccluded, isDreaming, lastStartedTransition) ->
if (
isOccluded &&
@@ -82,7 +89,7 @@ constructor(
private fun listenForDreamingToGone() {
scope.launch {
keyguardInteractor.biometricUnlockState
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (biometricUnlockState, lastStartedTransitionStep) ->
if (
lastStartedTransitionStep.to == KeyguardState.DREAMING &&
@@ -96,11 +103,7 @@ constructor(
private fun listenForDreamingToAodOrDozing() {
scope.launch {
- combine(
- keyguardInteractor.dozeTransitionModel,
- transitionInteractor.finishedKeyguardState,
- ::Pair
- )
+ combine(keyguardInteractor.dozeTransitionModel, finishedKeyguardState, ::Pair)
.collect { (dozeTransitionModel, keyguardState) ->
if (keyguardState == KeyguardState.DREAMING) {
if (dozeTransitionModel.to == DozeStateModel.DOZE) {
@@ -123,6 +126,7 @@ constructor(
}
companion object {
+ const val TAG = "FromDreamingTransitionInteractor"
private val DEFAULT_DURATION = 500.milliseconds
val TO_LOCKSCREEN_DURATION = 1167.milliseconds
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
index 70c2e6d56ca3..19fd7f9168e7 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGlanceableHubTransitionInteractor.kt
@@ -20,18 +20,29 @@ import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
@SysUISingleton
class FromGlanceableHubTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
-) : TransitionInteractor(fromState = KeyguardState.GLANCEABLE_HUB) {
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Main mainDispatcher: CoroutineDispatcher,
+ @Background bgDispatcher: CoroutineDispatcher,
+) :
+ TransitionInteractor(
+ fromState = KeyguardState.GLANCEABLE_HUB,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
+ ) {
override fun start() {
if (!Flags.communalHub()) {
return
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
index 62a0b0ebc08c..742790eeaedb 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromGoneTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
@@ -28,6 +29,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -37,13 +39,18 @@ class FromGoneTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
private val powerInteractor: PowerInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.GONE,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -57,7 +64,7 @@ constructor(
private fun listenForGoneToLockscreen() {
scope.launch {
keyguardInteractor.isKeyguardShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isKeyguardShowing, lastStartedStep) ->
if (isKeyguardShowing && lastStartedStep.to == KeyguardState.GONE) {
startTransitionTo(KeyguardState.LOCKSCREEN)
@@ -69,7 +76,7 @@ constructor(
private fun listenForGoneToDreamingLockscreenHosted() {
scope.launch {
keyguardInteractor.isActiveDreamLockscreenHosted
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isActiveDreamLockscreenHosted, lastStartedStep) ->
if (isActiveDreamLockscreenHosted && lastStartedStep.to == KeyguardState.GONE) {
startTransitionTo(KeyguardState.DREAMING_LOCKSCREEN_HOSTED)
@@ -83,7 +90,7 @@ constructor(
keyguardInteractor.isAbleToDream
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isActiveDreamLockscreenHosted,
::Pair
),
@@ -106,7 +113,7 @@ constructor(
powerInteractor.isAsleep
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index cecc6537e16e..2d0baa8be1b4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -18,9 +18,9 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
-import com.android.app.tracing.coroutines.launch
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
@@ -39,20 +39,25 @@ import dagger.Lazy
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
@SysUISingleton
class FromLockscreenTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
private val flags: FeatureFlags,
private val shadeRepository: ShadeRepository,
@@ -61,6 +66,9 @@ constructor(
) :
TransitionInteractor(
fromState = KeyguardState.LOCKSCREEN,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -147,12 +155,12 @@ constructor(
private fun listenForLockscreenToDreaming() {
val invalidFromStates = setOf(KeyguardState.AOD, KeyguardState.DOZING)
- scope.launch("$TAG#listenForLockscreenToDreaming") {
+ scope.launch {
keyguardInteractor.isAbleToDream
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
- transitionInteractor.finishedKeyguardState,
+ startedKeyguardTransitionStep,
+ finishedKeyguardState,
keyguardInteractor.isActiveDreamLockscreenHosted,
::Triple
),
@@ -180,9 +188,9 @@ constructor(
}
private fun listenForLockscreenToPrimaryBouncer() {
- scope.launch("$TAG#listenForLockscreenToPrimaryBouncer") {
+ scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isBouncerShowing, lastStartedTransitionStep) = pair
if (
@@ -195,9 +203,9 @@ constructor(
}
private fun listenForLockscreenToAlternateBouncer() {
- scope.launch("$TAG#listenForLockscreenToAlternateBouncer") {
+ scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isAlternateBouncerShowing, lastStartedTransitionStep) = pair
if (
@@ -213,11 +221,11 @@ constructor(
/* Starts transitions when manually dragging up the bouncer from the lockscreen. */
private fun listenForLockscreenToPrimaryBouncerDragging() {
var transitionId: UUID? = null
- scope.launch("$TAG#listenForLockscreenToPrimaryBouncerDragging") {
+ scope.launch {
shadeRepository.legacyShadeExpansion
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.statusBarState,
keyguardInteractor.isKeyguardUnlocked,
::Triple
@@ -225,72 +233,74 @@ constructor(
::toQuad
)
.collect { (shadeExpansion, keyguardState, statusBarState, isKeyguardUnlocked) ->
- val id = transitionId
- if (id != null) {
- if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
- // An existing `id` means a transition is started, and calls to
- // `updateTransition` will control it until FINISHED or CANCELED
- var nextState =
- if (shadeExpansion == 0f) {
- TransitionState.FINISHED
- } else if (shadeExpansion == 1f) {
- TransitionState.CANCELED
- } else {
- TransitionState.RUNNING
+ withContext(mainDispatcher) {
+ val id = transitionId
+ if (id != null) {
+ if (keyguardState.to == KeyguardState.PRIMARY_BOUNCER) {
+ // An existing `id` means a transition is started, and calls to
+ // `updateTransition` will control it until FINISHED or CANCELED
+ var nextState =
+ if (shadeExpansion == 0f) {
+ TransitionState.FINISHED
+ } else if (shadeExpansion == 1f) {
+ TransitionState.CANCELED
+ } else {
+ TransitionState.RUNNING
+ }
+ transitionRepository.updateTransition(
+ id,
+ 1f - shadeExpansion,
+ nextState,
+ )
+
+ if (
+ nextState == TransitionState.CANCELED ||
+ nextState == TransitionState.FINISHED
+ ) {
+ transitionId = null
}
- transitionRepository.updateTransition(
- id,
- 1f - shadeExpansion,
- nextState,
- )
+ // If canceled, just put the state back
+ // TODO(b/278086361): This logic should happen in
+ // FromPrimaryBouncerInteractor.
+ if (nextState == TransitionState.CANCELED) {
+ transitionRepository.startTransition(
+ TransitionInfo(
+ ownerName = name,
+ from = KeyguardState.PRIMARY_BOUNCER,
+ to = KeyguardState.LOCKSCREEN,
+ animator =
+ getDefaultAnimatorForTransitionsToState(
+ KeyguardState.LOCKSCREEN
+ )
+ .apply { duration = 0 }
+ )
+ )
+ }
+ }
+ } else {
+ // TODO (b/251849525): Remove statusbarstate check when that state is
+ // integrated into KeyguardTransitionRepository
if (
- nextState == TransitionState.CANCELED ||
- nextState == TransitionState.FINISHED
+ keyguardState.to == KeyguardState.LOCKSCREEN &&
+ shadeRepository.legacyShadeTracking.value &&
+ !isKeyguardUnlocked &&
+ statusBarState == KEYGUARD
) {
- transitionId = null
- }
-
- // If canceled, just put the state back
- // TODO(b/278086361): This logic should happen in
- // FromPrimaryBouncerInteractor.
- if (nextState == TransitionState.CANCELED) {
- transitionRepository.startTransition(
- TransitionInfo(
- ownerName = name,
- from = KeyguardState.PRIMARY_BOUNCER,
- to = KeyguardState.LOCKSCREEN,
- animator =
- getDefaultAnimatorForTransitionsToState(
- KeyguardState.LOCKSCREEN
- )
- .apply { duration = 0 }
+ transitionId =
+ startTransitionTo(
+ toState = KeyguardState.PRIMARY_BOUNCER,
+ animator = null, // transition will be manually controlled
)
- )
}
}
- } else {
- // TODO (b/251849525): Remove statusbarstate check when that state is
- // integrated into KeyguardTransitionRepository
- if (
- keyguardState.to == KeyguardState.LOCKSCREEN &&
- shadeRepository.legacyShadeTracking.value &&
- !isKeyguardUnlocked &&
- statusBarState == KEYGUARD
- ) {
- transitionId =
- startTransitionTo(
- toState = KeyguardState.PRIMARY_BOUNCER,
- animator = null, // transition will be manually controlled
- )
- }
}
}
}
}
fun dismissKeyguard() {
- startTransitionTo(KeyguardState.GONE)
+ scope.launch { startTransitionTo(KeyguardState.GONE) }
}
private fun listenForLockscreenToGone() {
@@ -298,9 +308,9 @@ constructor(
return
}
- scope.launch("$TAG#listenForLockscreenToGone") {
+ scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
@@ -315,9 +325,9 @@ constructor(
return
}
- scope.launch("$TAG#listenForLockscreenToGoneDragging") {
+ scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { pair ->
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
@@ -328,23 +338,22 @@ constructor(
}
private fun listenForLockscreenToOccluded() {
- scope.launch("$TAG#listenForLockscreenToOccluded") {
- keyguardInteractor.isKeyguardOccluded
- .sample(transitionInteractor.startedKeyguardState, ::Pair)
- .collect { (isOccluded, keyguardState) ->
- if (isOccluded && keyguardState == KeyguardState.LOCKSCREEN) {
- startTransitionTo(KeyguardState.OCCLUDED)
- }
+ scope.launch {
+ keyguardInteractor.isKeyguardOccluded.sample(startedKeyguardState, ::Pair).collect {
+ (isOccluded, keyguardState) ->
+ if (isOccluded && keyguardState == KeyguardState.LOCKSCREEN) {
+ startTransitionTo(KeyguardState.OCCLUDED)
}
+ }
}
}
private fun listenForLockscreenToAodOrDozing() {
- scope.launch("$TAG#listenForLockscreenToAodOrDozing") {
+ scope.launch {
powerInteractor.isAsleep
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
index 6a8555cb7f6b..40061f410456 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromOccludedTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.app.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
@@ -27,6 +28,7 @@ import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
@@ -36,13 +38,18 @@ class FromOccludedTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
private val powerInteractor: PowerInteractor,
) :
TransitionInteractor(
fromState = KeyguardState.OCCLUDED,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -57,7 +64,7 @@ constructor(
private fun listenForOccludedToPrimaryBouncer() {
scope.launch {
keyguardInteractor.primaryBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isBouncerShowing, lastStartedTransitionStep) ->
if (
isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.OCCLUDED
@@ -70,13 +77,12 @@ constructor(
private fun listenForOccludedToDreaming() {
scope.launch {
- keyguardInteractor.isAbleToDream
- .sample(transitionInteractor.finishedKeyguardState, ::Pair)
- .collect { (isAbleToDream, keyguardState) ->
- if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) {
- startTransitionTo(KeyguardState.DREAMING)
- }
+ keyguardInteractor.isAbleToDream.sample(finishedKeyguardState, ::Pair).collect {
+ (isAbleToDream, keyguardState) ->
+ if (isAbleToDream && keyguardState == KeyguardState.OCCLUDED) {
+ startTransitionTo(KeyguardState.DREAMING)
}
+ }
}
}
@@ -86,7 +92,7 @@ constructor(
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -111,7 +117,7 @@ constructor(
.sample(
combine(
keyguardInteractor.isKeyguardShowing,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -135,7 +141,7 @@ constructor(
powerInteractor.isAsleep
.sample(
combine(
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Pair
),
@@ -154,7 +160,7 @@ constructor(
private fun listenForOccludedToAlternateBouncer() {
scope.launch {
keyguardInteractor.alternateBouncerShowing
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isAlternateBouncerShowing, lastStartedTransitionStep) ->
if (
isAlternateBouncerShowing &&
@@ -183,6 +189,7 @@ constructor(
}
companion object {
+ const val TAG = "FromOccludedTransitionInteractor"
private val DEFAULT_DURATION = 500.milliseconds
val TO_LOCKSCREEN_DURATION = 933.milliseconds
val TO_AOD_DURATION = DEFAULT_DURATION
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
index 5f246e181c26..c62055f83517 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractor.kt
@@ -19,7 +19,8 @@ package com.android.systemui.keyguard.domain.interactor
import android.animation.ValueAnimator
import com.android.keyguard.KeyguardSecurityModel
import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.flags.FeatureFlags
import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
@@ -35,6 +36,7 @@ import com.android.systemui.util.kotlin.sample
import com.android.wm.shell.animation.Interpolators
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
@@ -47,8 +49,10 @@ class FromPrimaryBouncerTransitionInteractor
@Inject
constructor(
override val transitionRepository: KeyguardTransitionRepository,
- override val transitionInteractor: KeyguardTransitionInteractor,
- @Application private val scope: CoroutineScope,
+ transitionInteractor: KeyguardTransitionInteractor,
+ @Background private val scope: CoroutineScope,
+ @Background bgDispatcher: CoroutineDispatcher,
+ @Main mainDispatcher: CoroutineDispatcher,
private val keyguardInteractor: KeyguardInteractor,
private val flags: FeatureFlags,
private val keyguardSecurityModel: KeyguardSecurityModel,
@@ -57,6 +61,9 @@ constructor(
) :
TransitionInteractor(
fromState = KeyguardState.PRIMARY_BOUNCER,
+ transitionInteractor = transitionInteractor,
+ mainDispatcher = mainDispatcher,
+ bgDispatcher = bgDispatcher,
) {
override fun start() {
@@ -115,7 +122,7 @@ constructor(
.distinctUntilChanged()
fun dismissPrimaryBouncer() {
- startTransitionTo(KeyguardState.GONE)
+ scope.launch { startTransitionTo(KeyguardState.GONE) }
}
private fun listenForPrimaryBouncerToLockscreenOrOccluded() {
@@ -124,7 +131,7 @@ constructor(
.sample(
combine(
powerInteractor.isAwake,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isKeyguardOccluded,
keyguardInteractor.isActiveDreamLockscreenHosted,
::toQuad
@@ -158,7 +165,7 @@ constructor(
.sample(
combine(
powerInteractor.isAsleep,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
keyguardInteractor.isAodAvailable,
::Triple
),
@@ -185,7 +192,7 @@ constructor(
.sample(
combine(
keyguardInteractor.isActiveDreamLockscreenHosted,
- transitionInteractor.startedKeyguardTransitionStep,
+ startedKeyguardTransitionStep,
::Pair
),
::toTriple
@@ -213,7 +220,7 @@ constructor(
scope.launch {
keyguardInteractor.isKeyguardGoingAway
- .sample(transitionInteractor.startedKeyguardTransitionStep, ::Pair)
+ .sample(startedKeyguardTransitionStep, ::Pair)
.collect { (isKeyguardGoingAway, lastStartedTransitionStep) ->
if (
isKeyguardGoingAway &&
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
index d5ac2838a2f1..5c2df4581ff0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/TransitionInteractor.kt
@@ -24,8 +24,11 @@ import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.util.kotlin.sample
import java.util.UUID
+import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
/**
* Each TransitionInteractor is responsible for determining under which conditions to notify
@@ -40,14 +43,25 @@ import kotlinx.coroutines.launch
*/
sealed class TransitionInteractor(
val fromState: KeyguardState,
+ val transitionInteractor: KeyguardTransitionInteractor,
+ val mainDispatcher: CoroutineDispatcher,
+ val bgDispatcher: CoroutineDispatcher,
) {
val name = this::class.simpleName ?: "UnknownTransitionInteractor"
-
abstract val transitionRepository: KeyguardTransitionRepository
- abstract val transitionInteractor: KeyguardTransitionInteractor
abstract fun start()
- fun startTransitionTo(
+ /* Use background dispatcher for all [KeyguardTransitionInteractor] flows. Necessary because
+ * the [sample] utility internally runs a collect on the Unconfined dispatcher, resulting
+ * in continuations on the main thread. We don't want that for classes that inherit from this.
+ */
+ val startedKeyguardTransitionStep =
+ transitionInteractor.startedKeyguardTransitionStep.flowOn(bgDispatcher)
+ // The following are MutableSharedFlows, and do not require flowOn
+ val startedKeyguardState = transitionInteractor.startedKeyguardState
+ val finishedKeyguardState = transitionInteractor.finishedKeyguardState
+
+ suspend fun startTransitionTo(
toState: KeyguardState,
animator: ValueAnimator? = getDefaultAnimatorForTransitionsToState(toState),
modeOnCanceled: TransitionModeOnCanceled = TransitionModeOnCanceled.LAST_VALUE
@@ -67,16 +81,17 @@ sealed class TransitionInteractor(
)
return null
}
-
- return transitionRepository.startTransition(
- TransitionInfo(
- name,
- fromState,
- toState,
- animator,
- modeOnCanceled,
+ return withContext(mainDispatcher) {
+ transitionRepository.startTransition(
+ TransitionInfo(
+ name,
+ fromState,
+ toState,
+ animator,
+ modeOnCanceled,
+ )
)
- )
+ }
}
/** This signal may come in before the occlusion signal, and can provide a custom transition */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
index 9b404338b9e5..d118d4d11948 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/ShortcutsBesideUdfpsKeyguardBlueprint.kt
@@ -17,12 +17,14 @@
package com.android.systemui.keyguard.ui.view.layout.blueprints
+import com.android.systemui.communal.ui.view.layout.sections.CommunalTutorialIndicatorSection
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.KeyguardBlueprint
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.keyguard.ui.view.layout.sections.AlignShortcutsToUdfpsSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodBurnInSection
import com.android.systemui.keyguard.ui.view.layout.sections.AodNotificationIconsSection
+import com.android.systemui.keyguard.ui.view.layout.sections.ClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultDeviceEntrySection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultIndicationAreaSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultNotificationStackScrollLayoutSection
@@ -31,7 +33,7 @@ import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusBarSec
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultStatusViewSection
import com.android.systemui.keyguard.ui.view.layout.sections.DefaultUdfpsAccessibilityOverlaySection
import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsModule
-import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
+import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.util.kotlin.getOrNull
import java.util.Optional
import javax.inject.Inject
@@ -44,18 +46,20 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
class ShortcutsBesideUdfpsKeyguardBlueprint
@Inject
constructor(
+ alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection,
defaultIndicationAreaSection: DefaultIndicationAreaSection,
defaultDeviceEntrySection: DefaultDeviceEntrySection,
@Named(KeyguardSectionsModule.KEYGUARD_AMBIENT_INDICATION_AREA_SECTION)
defaultAmbientIndicationAreaSection: Optional<KeyguardSection>,
defaultSettingsPopupMenuSection: DefaultSettingsPopupMenuSection,
- alignShortcutsToUdfpsSection: AlignShortcutsToUdfpsSection,
defaultStatusViewSection: DefaultStatusViewSection,
defaultStatusBarSection: DefaultStatusBarSection,
- splitShadeGuidelines: SplitShadeGuidelines,
defaultNotificationStackScrollLayoutSection: DefaultNotificationStackScrollLayoutSection,
aodNotificationIconsSection: AodNotificationIconsSection,
aodBurnInSection: AodBurnInSection,
+ communalTutorialIndicatorSection: CommunalTutorialIndicatorSection,
+ clockSection: ClockSection,
+ smartspaceSection: SmartspaceSection,
udfpsAccessibilityOverlaySection: DefaultUdfpsAccessibilityOverlaySection,
) : KeyguardBlueprint {
override val id: String = SHORTCUTS_BESIDE_UDFPS
@@ -63,15 +67,17 @@ constructor(
override val sections =
listOfNotNull(
defaultIndicationAreaSection,
+ alignShortcutsToUdfpsSection,
defaultAmbientIndicationAreaSection.getOrNull(),
defaultSettingsPopupMenuSection,
- alignShortcutsToUdfpsSection,
defaultStatusViewSection,
defaultStatusBarSection,
defaultNotificationStackScrollLayoutSection,
- splitShadeGuidelines,
aodNotificationIconsSection,
+ smartspaceSection,
aodBurnInSection,
+ communalTutorialIndicatorSection,
+ clockSection,
defaultDeviceEntrySection,
udfpsAccessibilityOverlaySection, // Add LAST: Intentionally has z-order above others
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
index fe0b3656c3d7..310ec95a22df 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryForegroundViewModel.kt
@@ -20,7 +20,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.content.Context
import com.android.settingslib.Utils
import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
-import com.android.systemui.common.ui.data.repository.ConfigurationRepository
+import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -41,7 +41,7 @@ class DeviceEntryForegroundViewModel
@Inject
constructor(
val context: Context,
- configurationRepository: ConfigurationRepository, // TODO (b/309655554): create & use interactor
+ configurationInteractor: ConfigurationInteractor,
deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
transitionInteractor: KeyguardTransitionInteractor,
deviceEntryIconViewModel: DeviceEntryIconViewModel,
@@ -62,7 +62,7 @@ constructor(
private val color: Flow<Int> =
deviceEntryIconViewModel.useBackgroundProtection.flatMapLatest { useBgProtection ->
- configurationRepository.onAnyConfigurationChange
+ configurationInteractor.onAnyConfigurationChange
.map { getColor(useBgProtection) }
.onStart { emit(getColor(useBgProtection)) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index 2551da8e7795..5720cc74002b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -87,8 +87,6 @@ import com.android.systemui.bluetooth.BroadcastDialogController;
import com.android.systemui.broadcast.BroadcastSender;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
-import com.android.systemui.flags.FeatureFlags;
-import com.android.systemui.flags.Flags;
import com.android.systemui.media.controls.models.GutsViewHolder;
import com.android.systemui.media.controls.models.player.MediaAction;
import com.android.systemui.media.controls.models.player.MediaButton;
@@ -247,7 +245,6 @@ public class MediaControlPanel {
private String mCurrentBroadcastApp;
private MultiRippleController mMultiRippleController;
private TurbulenceNoiseController mTurbulenceNoiseController;
- private final FeatureFlags mFeatureFlags;
private final GlobalSettings mGlobalSettings;
private TurbulenceNoiseAnimationConfig mTurbulenceNoiseAnimationConfig;
@@ -281,7 +278,6 @@ public class MediaControlPanel {
ActivityIntentHelper activityIntentHelper,
NotificationLockscreenUserManager lockscreenUserManager,
BroadcastDialogController broadcastDialogController,
- FeatureFlags featureFlags,
GlobalSettings globalSettings,
MediaFlags mediaFlags
) {
@@ -312,8 +308,6 @@ public class MediaControlPanel {
return Unit.INSTANCE;
});
- mFeatureFlags = featureFlags;
-
mGlobalSettings = globalSettings;
updateAnimatorDurationScale();
}
@@ -1187,9 +1181,7 @@ public class MediaControlPanel {
action.run();
- if (mFeatureFlags.isEnabled(Flags.UMO_SURFACE_RIPPLE)) {
- mMultiRippleController.play(createTouchRippleAnimation(button));
- }
+ mMultiRippleController.play(createTouchRippleAnimation(button));
if (icon instanceof Animatable) {
((Animatable) icon).start();
@@ -1228,8 +1220,7 @@ public class MediaControlPanel {
}
private boolean shouldPlayTurbulenceNoise() {
- return mFeatureFlags.isEnabled(Flags.UMO_TURBULENCE_NOISE) && mButtonClicked && !mWasPlaying
- && isPlaying();
+ return mButtonClicked && !mWasPlaying && isPlaying();
}
private TurbulenceNoiseAnimationConfig createTurbulenceNoiseAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
index 0385aeba32b7..523414cfddbf 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaHierarchyManager.kt
@@ -1153,7 +1153,7 @@ constructor(
qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
onLockscreen && isSplitShadeExpanding() -> LOCATION_QS
onLockscreen && isTransformingToFullShadeAndInQQS() -> LOCATION_QQS
- // TODO(b/308813166): revisit logic once interactions between the hub and
+ // TODO(b/311234666): revisit logic once interactions between the hub and
// shade/keyguard state are finalized
isCommunalShowing && communalInteractor.isCommunalEnabled -> LOCATION_COMMUNAL_HUB
onLockscreen && allowMediaPlayerOnLockScreen -> LOCATION_LOCKSCREEN
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
index fc06090750ec..fe10eaaec793 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/base/actions/QSTileIntentUserInputHandler.kt
@@ -18,6 +18,8 @@ package com.android.systemui.qs.tiles.base.actions
import android.app.PendingIntent
import android.content.Intent
+import android.content.pm.PackageManager
+import android.os.UserHandle
import android.view.View
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.ActivityLaunchAnimator
@@ -32,13 +34,23 @@ import javax.inject.Inject
interface QSTileIntentUserInputHandler {
fun handle(view: View?, intent: Intent)
- fun handle(view: View?, pendingIntent: PendingIntent)
+
+ /** @param requestLaunchingDefaultActivity used in case !pendingIndent.isActivity */
+ fun handle(
+ view: View?,
+ pendingIntent: PendingIntent,
+ requestLaunchingDefaultActivity: Boolean = false
+ )
}
@SysUISingleton
class QSTileIntentUserInputHandlerImpl
@Inject
-constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInputHandler {
+constructor(
+ private val activityStarter: ActivityStarter,
+ private val packageManager: PackageManager,
+ private val userHandle: UserHandle,
+) : QSTileIntentUserInputHandler {
override fun handle(view: View?, intent: Intent) {
val animationController: ActivityLaunchAnimator.Controller? =
@@ -52,21 +64,41 @@ constructor(private val activityStarter: ActivityStarter) : QSTileIntentUserInpu
}
// TODO(b/249804373): make sure to allow showing activities over the lockscreen. See b/292112939
- override fun handle(view: View?, pendingIntent: PendingIntent) {
- if (!pendingIntent.isActivity) {
- return
- }
- val animationController: ActivityLaunchAnimator.Controller? =
- view?.let {
- ActivityLaunchAnimator.Controller.fromView(
- it,
- InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE,
+ override fun handle(
+ view: View?,
+ pendingIntent: PendingIntent,
+ requestLaunchingDefaultActivity: Boolean
+ ) {
+ if (pendingIntent.isActivity) {
+ val animationController: ActivityLaunchAnimator.Controller? =
+ view?.let {
+ ActivityLaunchAnimator.Controller.fromView(
+ it,
+ InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE,
+ )
+ }
+ activityStarter.postStartActivityDismissingKeyguard(pendingIntent, animationController)
+ } else if (requestLaunchingDefaultActivity) {
+ val intent =
+ Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setPackage(pendingIntent.creatorPackage)
+ .addFlags(
+ Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+ )
+ val intents =
+ packageManager.queryIntentActivitiesAsUser(
+ intent,
+ PackageManager.ResolveInfoFlags.of(0L),
+ userHandle.identifier
)
- }
- activityStarter.startPendingIntentMaybeDismissingKeyguard(
- pendingIntent,
- null,
- animationController
- )
+ intents
+ .firstOrNull { it.activityInfo.exported }
+ ?.let { resolved ->
+ intent.setPackage(null)
+ intent.setComponent(resolved.activityInfo.componentName)
+ handle(view, intent)
+ }
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt
index afca57c75788..0ad520bd31ee 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/alarm/domain/interactor/AlarmTileUserActionInteractor.kt
@@ -18,9 +18,7 @@ package com.android.systemui.qs.tiles.impl.alarm.domain.interactor
import android.content.Intent
import android.provider.AlarmClock
-import com.android.internal.jank.InteractionJankMonitor
-import com.android.systemui.animation.ActivityLaunchAnimator
-import com.android.systemui.plugins.ActivityStarter
+import com.android.systemui.qs.tiles.base.actions.QSTileIntentUserInputHandler
import com.android.systemui.qs.tiles.base.interactor.QSTileInput
import com.android.systemui.qs.tiles.base.interactor.QSTileUserActionInteractor
import com.android.systemui.qs.tiles.impl.alarm.domain.model.AlarmTileModel
@@ -31,34 +29,20 @@ import javax.inject.Inject
class AlarmTileUserActionInteractor
@Inject
constructor(
- private val activityStarter: ActivityStarter,
+ private val inputHandler: QSTileIntentUserInputHandler,
) : QSTileUserActionInteractor<AlarmTileModel> {
override suspend fun handleInput(input: QSTileInput<AlarmTileModel>): Unit =
with(input) {
when (action) {
is QSTileUserAction.Click -> {
- val animationController =
- action.view?.let {
- ActivityLaunchAnimator.Controller.fromView(
- it,
- InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_QS_TILE
- )
- }
if (
data is AlarmTileModel.NextAlarmSet &&
data.alarmClockInfo.showIntent != null
) {
val pendingIndent = data.alarmClockInfo.showIntent
- activityStarter.postStartActivityDismissingKeyguard(
- pendingIndent,
- animationController
- )
+ inputHandler.handle(action.view, pendingIndent, true)
} else {
- activityStarter.postStartActivityDismissingKeyguard(
- Intent(AlarmClock.ACTION_SHOW_ALARMS),
- 0,
- animationController
- )
+ inputHandler.handle(action.view, Intent(AlarmClock.ACTION_SHOW_ALARMS))
}
}
is QSTileUserAction.LongClick -> {}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index bd43307dba5a..7aa0dadba16c 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -32,6 +32,7 @@ import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
@@ -143,6 +144,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
channel.enableVibration(true);
mNotificationManager.createNotificationChannel(channel);
+ int currentUid = Process.myUid();
int currentUserId = mUserContextTracker.getUserContext().getUserId();
UserHandle currentUser = new UserHandle(currentUserId);
switch (action) {
@@ -166,7 +168,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
mRecorder = new ScreenMediaRecorder(
mUserContextTracker.getUserContext(),
mMainHandler,
- currentUserId,
+ currentUid,
mAudioSource,
captureTarget,
this
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 3aab3bf62809..a170d0dac100 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -83,7 +83,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
private Surface mInputSurface;
private VirtualDisplay mVirtualDisplay;
private MediaRecorder mMediaRecorder;
- private int mUser;
+ private int mUid;
private ScreenRecordingMuxer mMuxer;
private ScreenInternalAudioRecorder mAudio;
private ScreenRecordingAudioSource mAudioSource;
@@ -94,12 +94,12 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
ScreenMediaRecorderListener mListener;
public ScreenMediaRecorder(Context context, Handler handler,
- int user, ScreenRecordingAudioSource audioSource,
+ int uid, ScreenRecordingAudioSource audioSource,
MediaProjectionCaptureTarget captureRegion,
ScreenMediaRecorderListener listener) {
mContext = context;
mHandler = handler;
- mUser = user;
+ mUid = uid;
mCaptureRegion = captureRegion;
mListener = listener;
mAudioSource = audioSource;
@@ -111,7 +111,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
IMediaProjectionManager mediaService =
IMediaProjectionManager.Stub.asInterface(b);
IMediaProjection proj = null;
- proj = mediaService.createProjection(mUser, mContext.getPackageName(),
+ proj = mediaService.createProjection(mUid, mContext.getPackageName(),
MediaProjectionManager.TYPE_SCREEN_CAPTURE, false);
IMediaProjection projection = IMediaProjection.Stub.asInterface(proj.asBinder());
if (mCaptureRegion != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
index 3be60b74af21..782d6519468c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/GlanceableHubContainerController.kt
@@ -17,6 +17,8 @@
package com.android.systemui.shade
import android.content.Context
+import android.os.PowerManager
+import android.os.SystemClock
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
@@ -44,6 +46,7 @@ constructor(
private val communalViewModel: CommunalViewModel,
private val keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val shadeInteractor: ShadeInteractor,
+ private val powerManager: PowerManager,
) {
/** The container view for the hub. This will not be initialized until [initView] is called. */
private lateinit var communalContainerView: View
@@ -157,7 +160,7 @@ constructor(
// If the hub is fully visible, send all touch events to it.
val communalVisible = hubShowing && !hubOccluded
if (communalVisible) {
- communalContainerView.dispatchTouchEvent(ev)
+ dispatchTouchEvent(ev)
// Return true regardless of dispatch result as some touches at the start of a gesture
// may return false from dispatchTouchEvent.
return true
@@ -175,7 +178,7 @@ constructor(
x >= communalContainerView.width - edgeSwipeRegionWidth
if (inOpeningSwipeRegion && !hubOccluded) {
isTrackingOpenGesture = true
- communalContainerView.dispatchTouchEvent(ev)
+ dispatchTouchEvent(ev)
// Return true regardless of dispatch result as some touches at the start of a
// gesture may return false from dispatchTouchEvent.
return true
@@ -184,7 +187,7 @@ constructor(
if (isUp || isCancel) {
isTrackingOpenGesture = false
}
- communalContainerView.dispatchTouchEvent(ev)
+ dispatchTouchEvent(ev)
// Return true regardless of dispatch result as some touches at the start of a gesture
// may return false from dispatchTouchEvent.
return true
@@ -192,4 +195,17 @@ constructor(
return false
}
+
+ /**
+ * Dispatches the touch event to the communal container and sends a user activity event to reset
+ * the screen timeout.
+ */
+ private fun dispatchTouchEvent(ev: MotionEvent) {
+ communalContainerView.dispatchTouchEvent(ev)
+ powerManager.userActivity(
+ SystemClock.uptimeMillis(),
+ PowerManager.USER_ACTIVITY_EVENT_TOUCH,
+ 0
+ )
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 7a340d2f0268..6407b5a4d16c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -25,8 +25,8 @@ import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
import com.android.systemui.statusbar.policy.data.repository.DeviceProvisioningRepository
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
@@ -94,7 +94,7 @@ constructor(
disableFlagsRepository.disableFlags,
isShadeEnabled,
keyguardRepository.isDozing,
- userSetupRepository.isUserSetupFlow,
+ userSetupRepository.isUserSetUp,
deviceProvisioningRepository.isDeviceProvisioned,
) { disableFlags, isShadeEnabled, isDozing, isUserSetup, isDeviceProvisioned ->
isDeviceProvisioned &&
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index 2438298f6a6e..7f8be1cc7e55 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -22,6 +22,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dump.DumpManager
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.domain.interactor.NaturalScrollingSettingObserver
+import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.media.controls.ui.MediaHierarchyManager
import com.android.systemui.navigationbar.gestural.Utilities.isTrackpadScroll
import com.android.systemui.plugins.ActivityStarter
@@ -888,6 +889,9 @@ class DragDownHelper(
isDraggingDown = false
isTrackpadReverseScroll = false
shadeRepository.setLegacyLockscreenShadeTracking(false)
+ if (KeyguardShadeMigrationNssl.isEnabled) {
+ return true
+ }
} else {
stopDragging()
return false
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
index 29d53fc15e8b..9f878b241d73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.data
import com.android.systemui.statusbar.data.repository.KeyguardStatusBarRepositoryModule
+import com.android.systemui.statusbar.data.repository.RemoteInputRepositoryModule
import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryModule
import com.android.systemui.statusbar.phone.data.StatusBarPhoneDataLayerModule
import dagger.Module
@@ -24,6 +25,7 @@ import dagger.Module
includes =
[
KeyguardStatusBarRepositoryModule::class,
+ RemoteInputRepositoryModule::class,
StatusBarModeRepositoryModule::class,
StatusBarPhoneDataLayerModule::class
]
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt
new file mode 100644
index 000000000000..c0302bc348b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/RemoteInputRepository.kt
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.data.repository
+
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.NotificationRemoteInputManager
+import com.android.systemui.statusbar.RemoteInputController
+import dagger.Binds
+import dagger.Module
+import javax.inject.Inject
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Repository used for tracking the state of notification remote input (e.g. when the user presses
+ * "reply" on a notification and the keyboard opens).
+ */
+interface RemoteInputRepository {
+ /** Whether remote input is currently active for any notification. */
+ val isRemoteInputActive: Flow<Boolean>
+}
+
+@SysUISingleton
+class RemoteInputRepositoryImpl
+@Inject
+constructor(
+ private val notificationRemoteInputManager: NotificationRemoteInputManager,
+) : RemoteInputRepository {
+ override val isRemoteInputActive: Flow<Boolean> = conflatedCallbackFlow {
+ trySend(false) // initial value is false
+ val callback =
+ object : RemoteInputController.Callback {
+ override fun onRemoteInputActive(active: Boolean) {
+ trySend(active)
+ }
+ }
+ notificationRemoteInputManager.addControllerCallback(callback)
+ awaitClose { notificationRemoteInputManager.removeControllerCallback(callback) }
+ }
+}
+
+@Module
+interface RemoteInputRepositoryModule {
+ @Binds fun bindImpl(impl: RemoteInputRepositoryImpl): RemoteInputRepository
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt
new file mode 100644
index 000000000000..68f727b046c0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractor.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.domain.interactor
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.data.repository.RemoteInputRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/**
+ * Interactor used for business logic pertaining to the notification remote input (e.g. when the
+ * user presses "reply" on a notification and the keyboard opens).
+ */
+@SysUISingleton
+class RemoteInputInteractor @Inject constructor(remoteInputRepository: RemoteInputRepository) {
+ /** Is remote input currently active for a notification? */
+ val isRemoteInputActive: Flow<Boolean> = remoteInputRepository.isRemoteInputActive
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 31ca106d2bc9..e200e65a9f4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -273,12 +273,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
private final RefactorFlag mInlineReplyAnimation =
RefactorFlag.forView(Flags.NOTIFICATION_INLINE_REPLY_ANIMATION);
- private static final boolean mSimulateSlowMeasure = Compile.IS_DEBUG && RefactorFlag.forView(
- Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled();
+ private static boolean shouldSimulateSlowMeasure() {
+ return Compile.IS_DEBUG && RefactorFlag.forView(
+ Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE).isEnabled();
+ }
+
private static final String SLOW_MEASURE_SIMULATE_DELAY_PROPERTY =
"persist.notifications.extra_measure_delay_ms";
- private static final int SLOW_MEASURE_SIMULATE_DELAY_MS = mSimulateSlowMeasure ?
- SystemProperties.getInt(SLOW_MEASURE_SIMULATE_DELAY_PROPERTY, 150) : 0;
+ private static final int SLOW_MEASURE_SIMULATE_DELAY_MS =
+ SystemProperties.getInt(SLOW_MEASURE_SIMULATE_DELAY_PROPERTY, 150);
// Listener will be called when receiving a long click event.
// Use #setLongPressPosition to optionally assign positional data with the long press.
@@ -1886,7 +1889,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- if (Compile.IS_DEBUG && mSimulateSlowMeasure) {
+ if (shouldSimulateSlowMeasure()) {
simulateExtraMeasureDelay();
}
Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index abc04b87f831..a30c29456b3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -69,6 +69,7 @@ import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlagsClassic;
import com.android.systemui.flags.Flags;
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository;
+import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl;
import com.android.systemui.keyguard.shared.model.KeyguardState;
import com.android.systemui.keyguard.shared.model.TransitionStep;
import com.android.systemui.media.controls.ui.KeyguardMediaController;
@@ -1957,18 +1958,34 @@ public class NotificationStackScrollLayoutController implements Dumpable {
mView.dispatchDownEventToScroller(ev);
}
}
- boolean scrollerWantsIt = false;
- if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
- && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
- scrollerWantsIt = mView.onScrollTouch(ev);
- }
boolean horizontalSwipeWantsIt = false;
- if (mLongPressedView == null && !mView.isBeingDragged()
- && !expandingNotification
- && !mView.getExpandedInThisMotion()
- && !onlyScrollingInThisMotion
- && !mView.getDisallowDismissInThisMotion()) {
- horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ boolean scrollerWantsIt = false;
+ if (KeyguardShadeMigrationNssl.isEnabled()) {
+ // Reverse the order relative to the else statement. onScrollTouch will reset on an
+ // UP event, causing horizontalSwipeWantsIt to be set to true on vertical swipes.
+ if (mLongPressedView == null && !mView.isBeingDragged()
+ && !expandingNotification
+ && !mView.getExpandedInThisMotion()
+ && !onlyScrollingInThisMotion
+ && !mView.getDisallowDismissInThisMotion()) {
+ horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
+ if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
+ && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
+ scrollerWantsIt = mView.onScrollTouch(ev);
+ }
+ } else {
+ if (mLongPressedView == null && mView.isExpanded() && !mSwipeHelper.isSwiping()
+ && !expandingNotification && !mView.getDisallowScrollingInThisMotion()) {
+ scrollerWantsIt = mView.onScrollTouch(ev);
+ }
+ if (mLongPressedView == null && !mView.isBeingDragged()
+ && !expandingNotification
+ && !mView.getExpandedInThisMotion()
+ && !onlyScrollingInThisMotion
+ && !mView.getDisallowDismissInThisMotion()) {
+ horizontalSwipeWantsIt = mSwipeHelper.onTouchEvent(ev);
+ }
}
// Check if we need to clear any snooze leavebehinds
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index 89a2fb78635b..e309c32df64e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -34,8 +34,6 @@ import com.android.systemui.statusbar.pipeline.icons.shared.BindableIconsRegistr
import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigCoreStartable
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepositoryImpl
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
@@ -62,6 +60,8 @@ import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRep
import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryViaTrackerLib
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepositoryImpl
import dagger.Binds
import dagger.Module
import dagger.Provides
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
index 39135c70788d..d555c47f4da2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractor.kt
@@ -32,9 +32,9 @@ import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
import com.android.systemui.util.CarrierConfigTracker
import java.lang.ref.WeakReference
import javax.inject.Inject
@@ -105,7 +105,7 @@ interface MobileIconsInteractor {
val isDefaultConnectionFailed: StateFlow<Boolean>
/** True once the user has been set up */
- val isUserSetup: StateFlow<Boolean>
+ val isUserSetUp: StateFlow<Boolean>
/** True if we're configured to force-hide the mobile icons and false otherwise. */
val isForceHidden: Flow<Boolean>
@@ -362,7 +362,7 @@ constructor(
)
.stateIn(scope, SharingStarted.WhileSubscribed(), false)
- override val isUserSetup: StateFlow<Boolean> = userSetupRepo.isUserSetupFlow
+ override val isUserSetUp: StateFlow<Boolean> = userSetupRepo.isUserSetUp
override val isForceHidden: Flow<Boolean> =
connectivityRepository.forceHiddenSlots
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepository.kt
index 91886bb121d5..2a0812b8ec8d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepository.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.policy.data.repository
import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
import com.android.systemui.dagger.SysUISingleton
@@ -34,15 +34,14 @@ import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.withContext
/**
- * Repository to observe the state of [DeviceProvisionedController.isUserSetup]. This information
- * can change some policy related to display
+ * Repository to observe whether the user has completed the setup steps. This information can change
+ * some policy related to display.
*/
interface UserSetupRepository {
- /** Observable tracking [DeviceProvisionedController.isUserSetup] */
- val isUserSetupFlow: StateFlow<Boolean>
+ /** Whether the user has completed the setup steps. */
+ val isUserSetUp: StateFlow<Boolean>
}
-@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
class UserSetupRepositoryImpl
@@ -52,8 +51,7 @@ constructor(
@Background private val bgDispatcher: CoroutineDispatcher,
@Application scope: CoroutineScope,
) : UserSetupRepository {
- /** State flow that tracks [DeviceProvisionedController.isUserSetup] */
- override val isUserSetupFlow: StateFlow<Boolean> =
+ override val isUserSetUp: StateFlow<Boolean> =
conflatedCallbackFlow {
val callback =
object : DeviceProvisionedController.DeviceProvisionedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt
new file mode 100644
index 000000000000..ca36e392b563
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractor.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy.domain.interactor
+
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+class UserSetupInteractor @Inject constructor(repository: UserSetupRepository) {
+ /** Whether the user has completed the setup steps. */
+ val isUserSetUp: Flow<Boolean> = repository.isUserSetUp
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java b/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
deleted file mode 100644
index 8d8599900530..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/OtherPrefs.java
+++ /dev/null
@@ -1,33 +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.tuner;
-
-import android.os.Bundle;
-
-import androidx.preference.PreferenceFragment;
-
-import com.android.systemui.res.R;
-import com.android.tools.r8.keepanno.annotations.KeepTarget;
-import com.android.tools.r8.keepanno.annotations.UsesReflection;
-
-public class OtherPrefs extends PreferenceFragment {
- // aapt doesn't generate keep rules for android:fragment references in <Preference> tags, so
- // explicitly declare references per usage in `R.xml.other_settings`. See b/120445169.
- @UsesReflection(@KeepTarget(classConstant = PowerNotificationControlsFragment.class))
- @Override
- public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
- addPreferencesFromResource(R.xml.other_settings);
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
deleted file mode 100644
index ce1a2e9b329c..000000000000
--- a/packages/SystemUI/src/com/android/systemui/tuner/PowerNotificationControlsFragment.java
+++ /dev/null
@@ -1,93 +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.tuner;
-
-import android.annotation.Nullable;
-import android.app.Fragment;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
-import com.android.systemui.res.R;
-
-public class PowerNotificationControlsFragment extends Fragment {
-
- private static final String KEY_SHOW_PNC = "show_importance_slider";
-
- @Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- }
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.power_notification_controls_settings, container, false);
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
- final View switchBar = view.findViewById(R.id.switch_bar);
- final Switch switchWidget = (Switch) switchBar.findViewById(android.R.id.switch_widget);
- final TextView switchText = (TextView) switchBar.findViewById(R.id.switch_text);
- switchWidget.setChecked(isEnabled());
- switchText.setText(isEnabled()
- ? getString(R.string.switch_bar_on)
- : getString(R.string.switch_bar_off));
-
- switchWidget.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- boolean newState = !isEnabled();
- MetricsLogger.action(getContext(),
- MetricsEvent.ACTION_TUNER_POWER_NOTIFICATION_CONTROLS, newState);
- Settings.Secure.putInt(getContext().getContentResolver(),
- KEY_SHOW_PNC, newState ? 1 : 0);
- switchWidget.setChecked(newState);
- switchText.setText(newState
- ? getString(R.string.switch_bar_on)
- : getString(R.string.switch_bar_off));
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- MetricsLogger.visibility(
- getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, true);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- MetricsLogger.visibility(
- getContext(), MetricsEvent.TUNER_POWER_NOTIFICATION_CONTROLS, false);
- }
-
- private boolean isEnabled() {
- int setting = Settings.Secure.getInt(getContext().getContentResolver(), KEY_SHOW_PNC, 0);
- return setting == 1;
- }
-
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
index c4df27c2ccb2..cb8c40c333b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/DeviceEntrySideFpsOverlayInteractorTest.kt
@@ -29,6 +29,7 @@ import com.android.systemui.bouncer.domain.interactor.PrimaryBouncerInteractor
import com.android.systemui.bouncer.ui.BouncerView
import com.android.systemui.classifier.FalsingCollector
import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.coroutines.collectValues
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor
import com.android.systemui.keyguard.DismissCallbackRegistry
import com.android.systemui.keyguard.data.repository.FakeBiometricSettingsRepository
@@ -69,6 +70,7 @@ class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() {
private val bouncerRepository = FakeKeyguardBouncerRepository()
private val biometricSettingsRepository = FakeBiometricSettingsRepository()
+ private val deviceEntryFingerprintAuthRepository = FakeDeviceEntryFingerprintAuthRepository()
private lateinit var primaryBouncerInteractor: PrimaryBouncerInteractor
private lateinit var alternateBouncerInteractor: AlternateBouncerInteractor
@@ -112,7 +114,7 @@ class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() {
DeviceEntrySideFpsOverlayInteractor(
testScope.backgroundScope,
mContext,
- FakeDeviceEntryFingerprintAuthRepository(),
+ deviceEntryFingerprintAuthRepository,
primaryBouncerInteractor,
alternateBouncerInteractor,
keyguardUpdateMonitor
@@ -216,6 +218,30 @@ class DeviceEntrySideFpsOverlayInteractorTest : SysuiTestCase() {
assertThat(showIndicatorForDeviceEntry).isEqualTo(false)
}
+ @Test
+ fun ignoresDuplicateRequestsToShowIndicatorForDeviceEntry() =
+ testScope.runTest {
+ val showIndicatorForDeviceEntry by collectValues(underTest.showIndicatorForDeviceEntry)
+ runCurrent()
+
+ // Request to show indicator for primary bouncer showing
+ updatePrimaryBouncer(
+ isShowing = true,
+ isAnimatingAway = false,
+ fpsDetectionRunning = true,
+ isUnlockingWithFpAllowed = true
+ )
+
+ // Another request to show indicator for deviceEntryFingerprintAuthRepository update
+ deviceEntryFingerprintAuthRepository.setShouldUpdateIndicatorVisibility(true)
+
+ // Request to show indicator for alternate bouncer showing
+ bouncerRepository.setAlternateVisible(true)
+
+ // Ensure only one show request is sent
+ assertThat(showIndicatorForDeviceEntry).containsExactly(false, true)
+ }
+
private fun updatePrimaryBouncer(
isShowing: Boolean,
isAnimatingAway: Boolean,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
index 8e81185d6dcf..809947d2fec7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorTest.kt
@@ -63,6 +63,8 @@ class FromPrimaryBouncerTransitionInteractorTest : KeyguardTransitionInteractorT
transitionRepository = super.transitionRepository,
transitionInteractor = super.transitionInteractor,
scope = super.testScope.backgroundScope,
+ bgDispatcher = super.testDispatcher,
+ mainDispatcher = super.testDispatcher,
keyguardInteractor = super.keyguardInteractor,
flags = FakeFeatureFlags(),
keyguardSecurityModel = mock(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
index b8a8bdf06954..e531d44d5fdd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionScenariosTest.kt
@@ -20,7 +20,6 @@ import android.app.StatusBarManager
import androidx.test.filters.SmallTest
import com.android.keyguard.KeyguardSecurityModel
import com.android.keyguard.KeyguardSecurityModel.SecurityMode.PIN
-import com.android.keyguard.TestScopeProvider
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.flags.FakeFeatureFlags
@@ -51,6 +50,7 @@ import com.android.systemui.util.mockito.withArgCaptor
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.cancelChildren
+import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runCurrent
@@ -109,7 +109,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- testScope = TestScopeProvider.getTestScope()
+ val testDispatcher = StandardTestDispatcher()
+ testScope = TestScope(testDispatcher)
keyguardRepository = FakeKeyguardRepository()
bouncerRepository = FakeKeyguardBouncerRepository()
@@ -139,6 +140,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromLockscreenTransitionInteractor =
FromLockscreenTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -160,6 +163,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromPrimaryBouncerTransitionInteractor =
FromPrimaryBouncerTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -173,6 +178,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromDreamingTransitionInteractor =
FromDreamingTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -182,6 +189,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromDreamingLockscreenHostedTransitionInteractor =
FromDreamingLockscreenHostedTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -191,6 +200,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromAodTransitionInteractor =
FromAodTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -200,6 +211,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromGoneTransitionInteractor =
FromGoneTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -210,6 +223,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromDozingTransitionInteractor =
FromDozingTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -220,6 +235,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromOccludedTransitionInteractor =
FromOccludedTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
@@ -230,6 +247,8 @@ class KeyguardTransitionScenariosTest : SysuiTestCase() {
fromAlternateBouncerTransitionInteractor =
FromAlternateBouncerTransitionInteractor(
scope = testScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
transitionRepository = transitionRepository,
transitionInteractor = transitionInteractor,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index 2f35380e562b..59965022d7cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -64,8 +64,6 @@ import com.android.systemui.ActivityIntentHelper
import com.android.systemui.SysuiTestCase
import com.android.systemui.bluetooth.BroadcastDialogController
import com.android.systemui.broadcast.BroadcastSender
-import com.android.systemui.flags.FakeFeatureFlags
-import com.android.systemui.flags.Flags
import com.android.systemui.media.controls.MediaTestUtils
import com.android.systemui.media.controls.models.GutsViewHolder
import com.android.systemui.media.controls.models.player.MediaAction
@@ -227,11 +225,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Mock private lateinit var recProgressBar2: SeekBar
@Mock private lateinit var recProgressBar3: SeekBar
private var shouldShowBroadcastButton: Boolean = false
- private val fakeFeatureFlag =
- FakeFeatureFlags().apply {
- this.set(Flags.UMO_SURFACE_RIPPLE, false)
- this.set(Flags.UMO_TURBULENCE_NOISE, false)
- }
@Mock private lateinit var globalSettings: GlobalSettings
@Mock private lateinit var mediaFlags: MediaFlags
@@ -275,7 +268,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
activityIntentHelper,
lockscreenUserManager,
broadcastDialogController,
- fakeFeatureFlag,
globalSettings,
mediaFlags,
) {
@@ -2397,8 +2389,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
@Test
- fun onButtonClick_touchRippleFlagEnabled_playsTouchRipple() {
- fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, true)
+ fun onButtonClick_playsTouchRipple() {
val semanticActions =
MediaButton(
playOrPause =
@@ -2419,31 +2410,7 @@ public class MediaControlPanelTest : SysuiTestCase() {
}
@Test
- fun onButtonClick_touchRippleFlagDisabled_doesNotPlayTouchRipple() {
- fakeFeatureFlag.set(Flags.UMO_SURFACE_RIPPLE, false)
- val semanticActions =
- MediaButton(
- playOrPause =
- MediaAction(
- icon = null,
- action = {},
- contentDescription = "play",
- background = null
- )
- )
- val data = mediaData.copy(semanticActions = semanticActions)
- player.attachPlayer(viewHolder)
- player.bindPlayer(data, KEY)
-
- viewHolder.actionPlayPause.callOnClick()
-
- assertThat(viewHolder.multiRippleView.ripples.size).isEqualTo(0)
- }
-
- @Test
fun playTurbulenceNoise_finishesAfterDuration() {
- fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true)
-
val semanticActions =
MediaButton(
playOrPause =
@@ -2474,8 +2441,6 @@ public class MediaControlPanelTest : SysuiTestCase() {
@Test
fun playTurbulenceNoise_whenPlaybackStateIsNotPlaying_doesNotPlayTurbulence() {
- fakeFeatureFlag.set(Flags.UMO_TURBULENCE_NOISE, true)
-
val semanticActions =
MediaButton(
custom0 =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
index 5569ca9520e9..b7a9ea751438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/GlanceableHubContainerControllerTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.shade
+import android.os.PowerManager
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.testing.ViewUtils
@@ -43,6 +44,8 @@ import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@RunWith(AndroidTestingRunner::class)
@@ -52,6 +55,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
@Mock private lateinit var communalViewModel: CommunalViewModel
@Mock private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
@Mock private lateinit var shadeInteractor: ShadeInteractor
+ @Mock private lateinit var powerManager: PowerManager
private lateinit var containerView: View
private lateinit var testableLooper: TestableLooper
@@ -76,7 +80,8 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
communalInteractor,
communalViewModel,
keyguardTransitionInteractor,
- shadeInteractor
+ shadeInteractor,
+ powerManager
)
testableLooper = TestableLooper.get(this)
@@ -90,14 +95,14 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
}
@Test
- fun isEnabled_interactorEnabled_returnsTrue() {
+ fun isEnabled_interactorEnabled_interceptsTouches() {
communalRepository.setIsCommunalEnabled(true)
assertThat(underTest.isEnabled()).isTrue()
}
@Test
- fun isEnabled_interactorDisabled_returnsFalse() {
+ fun isEnabled_interactorDisabled_doesNotIntercept() {
communalRepository.setIsCommunalEnabled(false)
assertThat(underTest.isEnabled()).isFalse()
@@ -120,7 +125,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
}
@Test
- fun onTouchEvent_touchInsideGestureRegion_returnsTrue() {
+ fun onTouchEvent_touchInsideGestureRegion_interceptsTouches() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -131,7 +136,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
}
@Test
- fun onTouchEvent_subsequentTouchesAfterGestureStart_returnsTrue() {
+ fun onTouchEvent_subsequentTouchesAfterGestureStart_interceptsTouches() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -146,7 +151,7 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
}
@Test
- fun onTouchEvent_communalOpen_returnsTrue() {
+ fun onTouchEvent_communalOpen_interceptsTouches() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -155,10 +160,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
// Touch events are intercepted.
assertThat(underTest.onTouchEvent(DOWN_EVENT)).isTrue()
+ // User activity sent to PowerManager.
+ verify(powerManager).userActivity(any(), any(), any())
}
@Test
- fun onTouchEvent_communalAndBouncerShowing_returnsFalse() {
+ fun onTouchEvent_communalAndBouncerShowing_doesNotIntercept() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
@@ -170,10 +177,12 @@ class GlanceableHubContainerControllerTest : SysuiTestCase() {
// Touch events are not intercepted.
assertThat(underTest.onTouchEvent(DOWN_EVENT)).isFalse()
+ // User activity is not sent to PowerManager.
+ verify(powerManager, times(0)).userActivity(any(), any(), any())
}
@Test
- fun onTouchEvent_communalAndShadeShowing_returnsFalse() {
+ fun onTouchEvent_communalAndShadeShowing_doesNotIntercept() {
// Communal is open.
communalRepository.setDesiredScene(CommunalSceneKey.Communal)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index b2394820b2af..49579f6f46b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -181,7 +181,6 @@ import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
import com.android.systemui.statusbar.phone.TapAgainViewController;
import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -191,6 +190,7 @@ import com.android.systemui.statusbar.policy.KeyguardUserSwitcherController;
import com.android.systemui.statusbar.policy.KeyguardUserSwitcherView;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository;
import com.android.systemui.statusbar.window.StatusBarWindowStateController;
import com.android.systemui.unfold.SysUIUnfoldComponent;
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
index 437d00ac8723..1c98567592e8 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowControllerImplTest.java
@@ -23,8 +23,6 @@ import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
import static com.google.common.truth.Truth.assertThat;
-import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
-
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
@@ -38,6 +36,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import static kotlinx.coroutines.flow.FlowKt.emptyFlow;
+
import android.app.IActivityManager;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
@@ -94,11 +94,11 @@ import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;
@@ -216,6 +216,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
shadeRepository,
@@ -234,6 +236,8 @@ public class NotificationShadeWindowControllerImplTest extends SysuiTestCase {
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mKeyguardSecurityModel,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index 39051eba3ad9..f0a230379d27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -100,11 +100,11 @@ import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.phone.StatusBarTouchableRegionManager;
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
import com.android.systemui.statusbar.policy.CastController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;
import com.android.systemui.util.kotlin.JavaAdapter;
@@ -251,6 +251,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mShadeRepository,
@@ -269,6 +271,8 @@ public class QuickSettingsControllerBaseTest extends SysuiTestCase {
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mock(KeyguardSecurityModel.class),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
index 65e0fa146fe3..71a7420636cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImplTest.kt
@@ -50,8 +50,8 @@ import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
import com.android.systemui.statusbar.phone.DozeParameters
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.user.data.model.UserSwitcherSettingsModel
import com.android.systemui.user.data.repository.FakeUserRepository
import com.android.systemui.user.domain.UserDomainLayerModule
@@ -163,7 +163,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
- userSetupRepository.setUserSetup(false)
+ userSetupRepository.setUserSetUp(false)
userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true))
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -175,7 +175,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
fun isExpandToQsEnabled_shadeNotEnabled_false() =
testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
disableFlagsRepository.disableFlags.value =
DisableFlagsModel(
@@ -191,7 +191,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
fun isExpandToQsEnabled_quickSettingsNotEnabled_false() =
testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
disableFlagsRepository.disableFlags.value =
DisableFlagsModel(
@@ -206,7 +206,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
fun isExpandToQsEnabled_dozing_false() =
testComponent.runTest {
deviceProvisioningRepository.setDeviceProvisioned(true)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
disableFlagsRepository.disableFlags.value =
DisableFlagsModel(
disable2 = DISABLE2_NONE,
@@ -229,7 +229,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -262,7 +262,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
DisableFlagsModel(
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -290,7 +290,7 @@ class ShadeInteractorImplTest : SysuiTestCase() {
DisableFlagsModel(
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
@@ -322,21 +322,21 @@ class ShadeInteractorImplTest : SysuiTestCase() {
DisableFlagsModel(
disable2 = DISABLE2_NONE,
)
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
val actual by collectLastValue(underTest.isExpandToQsEnabled)
assertThat(actual).isTrue()
// WHEN the user is no longer setup
- userSetupRepository.setUserSetup(false)
+ userSetupRepository.setUserSetUp(false)
userRepository.setSettings(UserSwitcherSettingsModel(isSimpleUserSwitcher = true))
// THEN expand is disabled
assertThat(actual).isFalse()
// WHEN the user is setup again
- userSetupRepository.setUserSetup(true)
+ userSetupRepository.setUserSetUp(true)
// THEN expand is enabled
assertThat(actual).isTrue()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
index aed616349eb3..1a6a06742f9e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarStateControllerImplTest.kt
@@ -51,9 +51,9 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeInteractorLegacyImpl
import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.util.mockito.mock
import kotlinx.coroutines.flow.emptyFlow
import org.junit.Assert.assertEquals
@@ -69,8 +69,8 @@ import org.mockito.ArgumentMatchers.eq
import org.mockito.Mockito
import org.mockito.Mockito.mock
import org.mockito.Mockito.verify
-import org.mockito.Mockito.`when` as whenever
import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.`when` as whenever
@SmallTest
@RunWith(AndroidTestingRunner::class)
@@ -79,6 +79,7 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
private val utils = SceneTestUtils(this)
private val testScope = utils.testScope
+ private val testDispatcher = utils.testDispatcher
private lateinit var shadeInteractor: ShadeInteractor
private lateinit var fromLockscreenTransitionInteractor: FromLockscreenTransitionInteractor
private lateinit var fromPrimaryBouncerTransitionInteractor:
@@ -143,6 +144,8 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
keyguardTransitionRepository,
keyguardTransitionInteractor,
testScope.backgroundScope,
+ testDispatcher,
+ testDispatcher,
keyguardInteractor,
featureFlags,
shadeRepository,
@@ -162,6 +165,8 @@ class StatusBarStateControllerImplTest : SysuiTestCase() {
keyguardTransitionRepository,
keyguardTransitionInteractor,
testScope.backgroundScope,
+ testDispatcher,
+ testDispatcher,
keyguardInteractor,
featureFlags,
mock(),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 83ba68460aa5..a1721208b2f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -626,8 +626,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testClearNotifications_clearAllInProgress() {
- mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false);
-
ExpandableNotificationRow row = createClearableRow();
when(row.getEntry().hasFinishedInitialization()).thenReturn(true);
doReturn(true).when(mStackScroller).isVisible(row);
@@ -672,8 +670,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testAddNotificationUpdatesSpeedBumpIndex() {
- mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false);
-
// initial state calculated == 0
assertEquals(0, mStackScroller.getSpeedBumpIndex());
@@ -690,8 +686,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testAddAmbientNotificationNoSpeedBumpUpdate() {
- mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false);
-
// initial state calculated == 0
assertEquals(0, mStackScroller.getSpeedBumpIndex());
@@ -708,8 +702,6 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase {
@Test
public void testRemoveNotificationUpdatesSpeedBump() {
- mFeatureFlags.set(Flags.ENABLE_NOTIFICATIONS_SIMULATE_SLOW_MEASURE, false);
-
// initial state calculated == 0
assertEquals(0, mStackScroller.getSpeedBumpIndex());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt
deleted file mode 100644
index 91c233a4177d..000000000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryTest.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.policy.DeviceProvisionedController
-import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener
-import com.android.systemui.util.mockito.argumentCaptor
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.flow.launchIn
-import kotlinx.coroutines.flow.onEach
-import kotlinx.coroutines.runBlocking
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-class UserSetupRepositoryTest : SysuiTestCase() {
- private lateinit var underTest: UserSetupRepository
- @Mock private lateinit var deviceProvisionedController: DeviceProvisionedController
- private val scope = CoroutineScope(IMMEDIATE)
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- underTest =
- UserSetupRepositoryImpl(
- deviceProvisionedController,
- IMMEDIATE,
- scope,
- )
- }
-
- @After
- fun tearDown() {
- scope.cancel()
- }
-
- @Test
- fun testUserSetup_defaultFalse() =
- runBlocking(IMMEDIATE) {
- var latest: Boolean? = null
-
- val job = underTest.isUserSetupFlow.onEach { latest = it }.launchIn(this)
-
- assertThat(latest).isFalse()
-
- job.cancel()
- }
-
- @Test
- fun testUserSetup_updatesOnChange() =
- runBlocking(IMMEDIATE) {
- var latest: Boolean? = null
-
- val job = underTest.isUserSetupFlow.onEach { latest = it }.launchIn(this)
-
- whenever(deviceProvisionedController.isCurrentUserSetup).thenReturn(true)
- val callback = getDeviceProvisionedListener()
- callback.onUserSetupChanged()
-
- assertThat(latest).isTrue()
-
- job.cancel()
- }
-
- private fun getDeviceProvisionedListener(): DeviceProvisionedListener {
- val captor = argumentCaptor<DeviceProvisionedListener>()
- verify(deviceProvisionedController).addCallback(captor.capture())
- return captor.value!!
- }
-
- companion object {
- private val IMMEDIATE = Dispatchers.Main.immediate
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
index 2060288c28a4..0b14be1eefbd 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorTest.kt
@@ -31,10 +31,10 @@ import com.android.systemui.log.table.TableLogBuffer
import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.mock
import com.android.systemui.util.mockito.whenever
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
index 52fc2589a3f9..889130f47820 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/LocationBasedMobileIconViewModelTest.kt
@@ -30,7 +30,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionS
import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
@@ -39,6 +38,7 @@ import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconMod
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
index 44fa13283991..147efcbd67c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/ui/viewmodel/MobileIconViewModelTest.kt
@@ -42,7 +42,6 @@ import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.Airpla
import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconInteractorImpl
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
@@ -51,6 +50,7 @@ import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants
import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.whenever
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
index 1bdf64434fcb..0cb3329dcb4d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/InternetTileViewModelTest.kt
@@ -35,7 +35,6 @@ import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionS
import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
@@ -48,6 +47,7 @@ import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiIntera
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiScanEntry
import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
import com.android.systemui.util.CarrierConfigTracker
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index b7529a82dd3d..30434c84c692 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -160,7 +160,6 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.Share
import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.ScreenOffAnimationController;
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
@@ -169,6 +168,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.ResourcesSplitShadeStateController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.statusbar.policy.data.repository.FakeDeviceProvisioningRepository;
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository;
import com.android.systemui.user.domain.interactor.SelectedUserInteractor;
import com.android.systemui.user.domain.interactor.UserSwitcherInteractor;
import com.android.systemui.util.FakeEventLog;
@@ -444,6 +444,8 @@ public class BubblesTest extends SysuiTestCase {
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
shadeRepository,
@@ -462,6 +464,8 @@ public class BubblesTest extends SysuiTestCase {
keyguardTransitionRepository,
keyguardTransitionInteractor,
mTestScope.getBackgroundScope(),
+ mUtils.getTestDispatcher(),
+ mUtils.getTestDispatcher(),
keyguardInteractor,
featureFlags,
mock(KeyguardSecurityModel.class),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt
index e24ba265e260..c2dc67319fff 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/CoroutineTestScopeModule.kt
@@ -48,6 +48,9 @@ private constructor(
@get:[Provides Application]
val appScope: CoroutineScope = scope.backgroundScope
+ @get:[Provides Background]
+ val bgScope: CoroutineScope = scope.backgroundScope
+
@Module
interface Bindings {
@Binds @Main fun bindMainContext(dispatcher: TestDispatcher): CoroutineContext
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
index 1d44929a20f0..93e0b418d076 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeDeviceEntryFingerprintAuthRepository.kt
@@ -62,6 +62,10 @@ class FakeDeviceEntryFingerprintAuthRepository @Inject constructor() :
fun setAuthenticationStatus(status: FingerprintAuthenticationStatus) {
_authenticationStatus.value = status
}
+
+ fun setShouldUpdateIndicatorVisibility(shouldUpdateIndicatorVisibility: Boolean) {
+ _shouldUpdateIndicatorVisibility.value = shouldUpdateIndicatorVisibility
+ }
}
@Module
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
index b03d0b822161..b1a0b67d6648 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractorKosmos.kt
@@ -20,6 +20,7 @@ import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.shade.data.repository.shadeRepository
import dagger.Lazy
@@ -30,6 +31,8 @@ val Kosmos.fromLockscreenTransitionInteractor by
transitionRepository = keyguardTransitionRepository,
transitionInteractor = keyguardTransitionInteractor,
scope = applicationCoroutineScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
flags = featureFlagsClassic,
shadeRepository = shadeRepository,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
index ade3e1a82297..97536e20cb0a 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/domain/interactor/FromPrimaryBouncerTransitionInteractorKosmos.kt
@@ -21,6 +21,7 @@ import com.android.systemui.flags.featureFlagsClassic
import com.android.systemui.keyguard.data.repository.keyguardTransitionRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.user.domain.interactor.selectedUserInteractor
@@ -30,6 +31,8 @@ val Kosmos.fromPrimaryBouncerTransitionInteractor by
transitionRepository = keyguardTransitionRepository,
transitionInteractor = keyguardTransitionInteractor,
scope = applicationCoroutineScope,
+ bgDispatcher = testDispatcher,
+ mainDispatcher = testDispatcher,
keyguardInteractor = keyguardInteractor,
flags = featureFlagsClassic,
keyguardSecurityModel = keyguardSecurityModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt
index 4bfe4f571b05..4f638d0e4a38 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/viewmodel/DeviceEntryFgIconViewModelKosmos.kt
@@ -18,7 +18,7 @@ package com.android.systemui.keyguard.ui.viewmodel
import android.content.applicationContext
import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
-import com.android.systemui.common.ui.data.repository.configurationRepository
+import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.deviceentry.domain.interactor.deviceEntryUdfpsInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardTransitionInteractor
import com.android.systemui.kosmos.Kosmos
@@ -29,7 +29,7 @@ import kotlinx.coroutines.ExperimentalCoroutinesApi
val Kosmos.deviceEntryForegroundIconViewModel by Fixture {
DeviceEntryForegroundViewModel(
context = applicationContext,
- configurationRepository = configurationRepository,
+ configurationInteractor = configurationInteractor,
deviceEntryUdfpsInteractor = deviceEntryUdfpsInteractor,
transitionInteractor = keyguardTransitionInteractor,
deviceEntryIconViewModel = deviceEntryIconViewModel,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
index 1185f2edef3b..0307c414351f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/tiles/base/actions/FakeQSTileIntentUserInputHandler.kt
@@ -35,14 +35,21 @@ class FakeQSTileIntentUserInputHandler : QSTileIntentUserInputHandler {
mutableInputs.add(Input.Intent(view, intent))
}
- override fun handle(view: View?, pendingIntent: PendingIntent) {
- mutableInputs.add(Input.PendingIntent(view, pendingIntent))
+ override fun handle(
+ view: View?,
+ pendingIntent: PendingIntent,
+ requestLaunchingDefaultActivity: Boolean
+ ) {
+ mutableInputs.add(Input.PendingIntent(view, pendingIntent, requestLaunchingDefaultActivity))
}
sealed interface Input {
data class Intent(val view: View?, val intent: android.content.Intent) : Input
- data class PendingIntent(val view: View?, val pendingIntent: android.app.PendingIntent) :
- Input
+ data class PendingIntent(
+ val view: View?,
+ val pendingIntent: android.app.PendingIntent,
+ val requestLaunchingDefaultActivity: Boolean
+ ) : Input
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 7da57f024ec7..afd37b3f92dc 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -29,8 +29,8 @@ import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.statusbar.disableflags.data.repository.disableFlagsRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.statusbar.phone.dozeParameters
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.userSetupRepository
import com.android.systemui.statusbar.policy.data.repository.deviceProvisioningRepository
+import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
import com.android.systemui.user.domain.interactor.userSwitcherInteractor
var Kosmos.baseShadeInteractor: BaseShadeInteractor by
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt
index f1e6a053643f..f1e6a053643f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeKeyguardStatusBarRepository.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt
new file mode 100644
index 000000000000..c416ea1c1b39
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/FakeRemoteInputRepository.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.data.repository
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+class FakeRemoteInputRepository : RemoteInputRepository {
+ override val isRemoteInputActive = MutableStateFlow(false)
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt
new file mode 100644
index 000000000000..1684efba2ca2
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/RemoteInputRepositoryKosmos.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.data.repository
+
+import com.android.systemui.kosmos.Kosmos
+
+var Kosmos.remoteInputRepository: RemoteInputRepository by
+ Kosmos.Fixture { fakeRemoteInputRepository }
+val Kosmos.fakeRemoteInputRepository by Kosmos.Fixture { FakeRemoteInputRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt
new file mode 100644
index 000000000000..07b39dc87a9a
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/domain/interactor/RemoteInputInteractorKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.data.repository.remoteInputRepository
+
+val Kosmos.remoteInputInteractor by Kosmos.Fixture { RemoteInputInteractor(remoteInputRepository) }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
index 44f31343b06d..f5a4c034d836 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -24,6 +24,7 @@ import com.android.systemui.statusbar.notification.domain.interactor.activeNotif
import com.android.systemui.statusbar.notification.domain.interactor.seenNotificationsInteractor
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.footerViewModel
import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.notificationShelfViewModel
+import com.android.systemui.statusbar.policy.domain.interactor.userSetupInteractor
import com.android.systemui.statusbar.policy.domain.interactor.zenModeInteractor
import java.util.Optional
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt
index 549929c2c04a..6e2d12ac06b6 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/FakeStatusBarPipelineMobileDataLayerModule.kt
@@ -15,7 +15,7 @@
*/
package com.android.systemui.statusbar.pipeline.mobile.data
-import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepositoryModule
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepositoryModule
import dagger.Module
@Module(includes = [FakeUserSetupRepositoryModule::class])
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
index 5f4d7bf6f371..5f4d7bf6f371 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconInteractor.kt
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
index a9ee4055d1a8..de6c87c2b515 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/FakeMobileIconsInteractor.kt
@@ -76,8 +76,8 @@ class FakeMobileIconsInteractor(
private val _defaultMobileIconGroup = MutableStateFlow(DEFAULT_ICON)
override val defaultMobileIconGroup = _defaultMobileIconGroup
- private val _isUserSetup = MutableStateFlow(true)
- override val isUserSetup = _isUserSetup
+ private val _isUserSetUp = MutableStateFlow(true)
+ override val isUserSetUp = _isUserSetUp
override val isForceHidden = MutableStateFlow(false)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeUserSetupRepository.kt
index 55e81bbc77e7..76a9861f5a6f 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeUserSetupRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/FakeUserSetupRepository.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.policy.data.repository
import com.android.systemui.dagger.SysUISingleton
import dagger.Binds
@@ -26,10 +26,10 @@ import kotlinx.coroutines.flow.MutableStateFlow
@SysUISingleton
class FakeUserSetupRepository @Inject constructor() : UserSetupRepository {
private val _isUserSetup: MutableStateFlow<Boolean> = MutableStateFlow(true)
- override val isUserSetupFlow = _isUserSetup
+ override val isUserSetUp = _isUserSetup
- fun setUserSetup(setup: Boolean) {
- _isUserSetup.value = setup
+ fun setUserSetUp(isSetUp: Boolean) {
+ _isUserSetup.value = isSetUp
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryKosmos.kt
index 7b9634a7abb5..a1c5b9aef54e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/UserSetupRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/data/repository/UserSetupRepositoryKosmos.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.statusbar.pipeline.mobile.data.repository
+package com.android.systemui.statusbar.policy.data.repository
import com.android.systemui.kosmos.Kosmos
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt
new file mode 100644
index 000000000000..83f4939cee1f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/domain/interactor/UserSetupInteractorKosmos.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy.domain.interactor
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.policy.data.repository.userSetupRepository
+
+val Kosmos.userSetupInteractor by Kosmos.Fixture { UserSetupInteractor(userSetupRepository) }
diff --git a/packages/SystemUI/unfold/Android.bp b/packages/SystemUI/unfold/Android.bp
index e52cefb2d7e4..81fd8ce12f05 100644
--- a/packages/SystemUI/unfold/Android.bp
+++ b/packages/SystemUI/unfold/Android.bp
@@ -39,7 +39,4 @@ android_library {
sdk_version: "current",
min_sdk_version: "current",
plugins: ["dagger2-compiler"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
diff --git a/packages/SystemUI/unfold/lint-baseline.xml b/packages/SystemUI/unfold/lint-baseline.xml
deleted file mode 100644
index 449ed2e60853..000000000000
--- a/packages/SystemUI/unfold/lint-baseline.xml
+++ /dev/null
@@ -1,3 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" name="" variant="all" version="7.1.0-dev">
-</issues>
diff --git a/services/Android.bp b/services/Android.bp
index 0b484f473d36..7e8333c7ba5f 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -148,9 +148,6 @@ filegroup {
java_library {
name: "Slogf",
srcs: ["core/java/com/android/server/utils/Slogf.java"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
// merge all required services into one jar
diff --git a/services/accessibility/Android.bp b/services/accessibility/Android.bp
index a3546716d5ca..69cc68a55108 100644
--- a/services/accessibility/Android.bp
+++ b/services/accessibility/Android.bp
@@ -22,6 +22,7 @@ java_library_static {
lint: {
error_checks: ["MissingPermissionAnnotation"],
baseline_filename: "lint-baseline.xml",
+
},
srcs: [
":services.accessibility-sources",
@@ -50,9 +51,6 @@ java_library_static {
libs: [
"androidx.annotation_annotation",
],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
aconfig_declarations {
diff --git a/services/accessibility/lint-baseline.xml b/services/accessibility/lint-baseline.xml
index 6bec8cf5f018..b808219ef9c6 100644
--- a/services/accessibility/lint-baseline.xml
+++ b/services/accessibility/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="SimpleManualPermissionEnforcement"
@@ -23,4 +23,4 @@
column="9"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/services/backup/lint-baseline.xml b/services/backup/lint-baseline.xml
index 93c9390feb9c..46de2cdd7a47 100644
--- a/services/backup/lint-baseline.xml
+++ b/services/backup/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NonUserGetterCalled"
@@ -36,4 +36,4 @@
line="207"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
index 4b3772a7a54d..d0eb59d83f5a 100644
--- a/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
+++ b/services/companion/java/com/android/server/companion/AssociationRequestsProcessor.java
@@ -22,6 +22,7 @@ import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.companion.CompanionDeviceManager.REASON_INTERNAL_ERROR;
import static android.companion.CompanionDeviceManager.RESULT_INTERNAL_ERROR;
import static android.content.ComponentName.createRelative;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
import static com.android.server.companion.CompanionDeviceManagerService.DEBUG;
import static com.android.server.companion.MetricUtils.logCreateAssociation;
@@ -169,16 +170,29 @@ class AssociationRequestsProcessor {
enforcePermissionsForAssociation(mContext, request, packageUid);
enforceUsesCompanionDeviceFeature(mContext, userId, packageName);
- // 2. Check if association can be created without launching UI (i.e. CDM needs NEITHER
+ // 2a. Check if association can be created without launching UI (i.e. CDM needs NEITHER
// to perform discovery NOR to collect user consent).
if (request.isSelfManaged() && !request.isForceConfirmation()
&& !willAddRoleHolder(request, packageName, userId)) {
- // 2a. Create association right away.
+ // 2a.1. Create association right away.
createAssociationAndNotifyApplication(request, packageName, userId,
/* macAddress */ null, callback, /* resultReceiver */ null);
return;
}
+ // 2a.2. Report an error if a 3p app tries to create a non-self-managed association and
+ // launch UI on watch.
+ if (mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) {
+ String errorMessage = "3p apps are not allowed to create associations on watch.";
+ Slog.e(TAG, errorMessage);
+ try {
+ callback.onFailure(errorMessage);
+ } catch (RemoteException e) {
+ // ignored
+ }
+ return;
+ }
+
// 2b. Build a PendingIntent for launching the confirmation UI, and send it back to the app:
// 2b.1. Populate the request with required info.
diff --git a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
index 4e471f5b0bc9..260b21f109d0 100644
--- a/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
+++ b/services/companion/java/com/android/server/companion/datatransfer/SystemDataTransferProcessor.java
@@ -21,6 +21,7 @@ import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.app.PendingIntent.FLAG_ONE_SHOT;
import static android.companion.CompanionDeviceManager.MESSAGE_REQUEST_PERMISSION_RESTORE;
import static android.content.ComponentName.createRelative;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
import static com.android.server.companion.Utils.prepareForIpc;
@@ -40,6 +41,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
+import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
@@ -306,6 +308,13 @@ public class SystemDataTransferProcessor {
}
private void onReceivePermissionRestore(byte[] message) {
+ // TODO: Disable Permissions Sync for non-watch devices until we figure out a better UX
+ // model
+ if (!Build.isDebuggable() && !mContext.getPackageManager().hasSystemFeature(
+ FEATURE_WATCH)) {
+ Slog.e(LOG_TAG, "Permissions restore is only available on watch.");
+ return;
+ }
Slog.i(LOG_TAG, "Applying permissions.");
// Start applying permissions
UserHandle user = mContext.getUser();
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index 62c670317f5f..3e45626d9799 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -125,7 +125,7 @@ public class CompanionTransportManager {
* Send a message to remote devices through the transports
*/
public void sendMessage(int message, byte[] data, int[] associationIds) {
- Slog.i(TAG, "Sending message 0x" + Integer.toHexString(message)
+ Slog.d(TAG, "Sending message 0x" + Integer.toHexString(message)
+ " data length " + data.length);
synchronized (mTransports) {
for (int i = 0; i < associationIds.length; i++) {
diff --git a/services/companion/java/com/android/server/companion/transport/Transport.java b/services/companion/java/com/android/server/companion/transport/Transport.java
index 22b18ac9653b..8a5774e55ce2 100644
--- a/services/companion/java/com/android/server/companion/transport/Transport.java
+++ b/services/companion/java/com/android/server/companion/transport/Transport.java
@@ -284,7 +284,7 @@ public abstract class Transport {
if (mListeners.containsKey(message)) {
try {
mListeners.get(message).onMessageReceived(getAssociationId(), data);
- Slog.i(TAG, "Message 0x" + Integer.toHexString(message)
+ Slog.d(TAG, "Message 0x" + Integer.toHexString(message)
+ " is received from associationId " + mAssociationId
+ ", sending data length " + data.length + " to the listener.");
} catch (RemoteException ignored) {
diff --git a/services/companion/lint-baseline.xml b/services/companion/lint-baseline.xml
index 03eae3901e51..020126f75ea0 100644
--- a/services/companion/lint-baseline.xml
+++ b/services/companion/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NonUserGetterCalled"
@@ -12,4 +12,4 @@
column="14"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/services/core/Android.bp b/services/core/Android.bp
index a3fc3bf5ec72..a6ed498e93db 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -234,9 +234,6 @@ java_genrule {
java_library {
name: "services.core",
static_libs: ["services.core.priorityboosted"],
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
}
java_library_host {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 02f4485d5b40..0cff8b7e88ed 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -4464,6 +4464,12 @@ public final class ActiveServices {
}
}
if (userId > 0) {
+ if (mAm.isSystemUserOnly(sInfo.flags)) {
+ Slog.w(TAG_SERVICE, service + " is only available for the SYSTEM user,"
+ + " calling userId is: " + userId);
+ return null;
+ }
+
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)
&& mAm.isValidSingletonCall(callingUid, sInfo.applicationInfo.uid)) {
@@ -5453,7 +5459,7 @@ public final class ActiveServices {
// Force an immediate oomAdjUpdate, so the client app could be in the correct process state
// before doing any service related transactions
mAm.enqueueOomAdjTargetLocked(app);
- mAm.updateOomAdjLocked(app, OOM_ADJ_REASON_START_SERVICE);
+ mAm.updateOomAdjPendingTargetsLocked(OOM_ADJ_REASON_START_SERVICE);
boolean created = false;
try {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f20c2d892879..e583a6cd6b1f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -13747,6 +13747,11 @@ public class ActivityManagerService extends IActivityManager.Stub
return result;
}
+ boolean isSystemUserOnly(int flags) {
+ return android.multiuser.Flags.enableSystemUserOnlyForServicesAndProviders()
+ && (flags & ServiceInfo.FLAG_SYSTEM_USER_ONLY) != 0;
+ }
+
/**
* Checks to see if the caller is in the same app as the singleton
* component, or the component is in a special app. It allows special apps
diff --git a/services/core/java/com/android/server/am/AnrHelper.java b/services/core/java/com/android/server/am/AnrHelper.java
index e0a224629174..9fc0bf920969 100644
--- a/services/core/java/com/android/server/am/AnrHelper.java
+++ b/services/core/java/com/android/server/am/AnrHelper.java
@@ -63,6 +63,11 @@ class AnrHelper {
private static final long CONSECUTIVE_ANR_TIME_MS = TimeUnit.MINUTES.toMillis(2);
/**
+ * Time to wait before taking dumps for other processes to reduce load at boot time.
+ */
+ private static final long SELF_ONLY_AFTER_BOOT_MS = TimeUnit.MINUTES.toMillis(10);
+
+ /**
* The keep alive time for the threads in the helper threadpool executor
*/
private static final int DEFAULT_THREAD_KEEP_ALIVE_SECOND = 10;
@@ -231,7 +236,8 @@ class AnrHelper {
// If there are many ANR at the same time, the latency may be larger.
// If the latency is too large, the stack trace might not be meaningful.
final long reportLatency = startTime - r.mTimestamp;
- final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS;
+ final boolean onlyDumpSelf = reportLatency > EXPIRED_REPORT_TIME_MS
+ || startTime < SELF_ONLY_AFTER_BOOT_MS;
r.appNotResponding(onlyDumpSelf);
final long endTime = SystemClock.uptimeMillis();
Slog.d(TAG, "Completed ANR of " + r.mApp.processName + " in "
diff --git a/services/core/java/com/android/server/am/ContentProviderHelper.java b/services/core/java/com/android/server/am/ContentProviderHelper.java
index 095d907d7df6..30f21a65b5b1 100644
--- a/services/core/java/com/android/server/am/ContentProviderHelper.java
+++ b/services/core/java/com/android/server/am/ContentProviderHelper.java
@@ -1249,9 +1249,9 @@ public class ContentProviderHelper {
ProviderInfo cpi = providers.get(i);
boolean singleton = mService.isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags);
- if (singleton && app.userId != UserHandle.USER_SYSTEM) {
- // This is a singleton provider, but a user besides the
- // default user is asking to initialize a process it runs
+ if (isSingletonOrSystemUserOnly(cpi) && app.userId != UserHandle.USER_SYSTEM) {
+ // This is a singleton or a SYSTEM user only provider, but a user besides the
+ // SYSTEM user is asking to initialize a process it runs
// in... well, no, it doesn't actually run in this process,
// it runs in the process of the default user. Get rid of it.
providers.remove(i);
@@ -1398,8 +1398,7 @@ public class ContentProviderHelper {
final boolean processMatch =
Objects.equals(pi.processName, app.processName)
|| pi.multiprocess;
- final boolean userMatch = !mService.isSingleton(
- pi.processName, pi.applicationInfo, pi.name, pi.flags)
+ final boolean userMatch = !isSingletonOrSystemUserOnly(pi)
|| app.userId == UserHandle.USER_SYSTEM;
final boolean isInstantApp = pi.applicationInfo.isInstantApp();
final boolean splitInstalled = pi.splitName == null
@@ -1985,4 +1984,13 @@ public class ContentProviderHelper {
return isAuthRedirected;
}
}
+
+ /**
+ * Returns true if Provider is either singleUser or systemUserOnly provider.
+ */
+ private boolean isSingletonOrSystemUserOnly(ProviderInfo pi) {
+ return (android.multiuser.Flags.enableSystemUserOnlyForServicesAndProviders()
+ && mService.isSystemUserOnly(pi.flags))
+ || mService.isSingleton(pi.processName, pi.applicationInfo, pi.name, pi.flags);
+ }
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 91d533c73b5d..4cbee2b89bb2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -8835,6 +8835,8 @@ public class AudioService extends IAudioService.Stub
synchronized (VolumeStreamState.class) {
oldIndex = getIndex(device);
index = getValidIndex(index, hasModifyAudioSettings);
+ // for STREAM_SYSTEM_ENFORCED, do not sync aliased streams on the enforced index
+ int aliasIndex = index;
if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
index = mIndexMax;
}
@@ -8853,7 +8855,8 @@ public class AudioService extends IAudioService.Stub
if (streamType != mStreamType &&
mStreamVolumeAlias[streamType] == mStreamType &&
(changed || !aliasStreamState.hasIndexForDevice(device))) {
- final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
+ final int scaledIndex =
+ rescaleIndex(aliasIndex, mStreamType, streamType);
aliasStreamState.setIndex(scaledIndex, device, caller,
hasModifyAudioSettings);
if (isCurrentDevice) {
@@ -9375,6 +9378,14 @@ public class AudioService extends IAudioService.Stub
if (mIsSingleVolume && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
return;
}
+
+ // Persisting STREAM_SYSTEM_ENFORCED index is not needed as its alias (STREAM_RING)
+ // is persisted. This can also be problematic when the enforcement is active as it will
+ // override current SYSTEM_RING persisted value given they share the same settings name
+ // (due to aliasing).
+ if (streamState.mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) {
+ return;
+ }
if (streamState.hasValidSettingsName()) {
mSettings.putSystemIntForUser(mContentResolver,
streamState.getSettingNameForDevice(device),
diff --git a/services/core/java/com/android/server/audio/SoundDoseHelper.java b/services/core/java/com/android/server/audio/SoundDoseHelper.java
index c2bc1e4f6be2..a30cdc47a461 100644
--- a/services/core/java/com/android/server/audio/SoundDoseHelper.java
+++ b/services/core/java/com/android/server/audio/SoundDoseHelper.java
@@ -62,6 +62,7 @@ import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -147,6 +148,15 @@ public class SoundDoseHelper {
private static final int SAFE_MEDIA_VOLUME_UNINITIALIZED = -1;
+ // see {@link #recordToPersistedString(SoundDoseRecord)}
+ // this is computed conservatively to accommodate the legacy persisting of SoundDoseRecords in
+ // which we materialized more decimal values.
+ // TODO: adjust value after soaking in
+ private static final int MAX_RECORDS_STRING_LENGTH = 50;
+ private static final int MAX_SETTINGS_LENGTH = 32768;
+ private static final int MAX_NUMBER_OF_CACHED_RECORDS =
+ MAX_SETTINGS_LENGTH / MAX_RECORDS_STRING_LENGTH;
+
private final EventLogger mLogger = new EventLogger(AudioService.LOG_NB_EVENTS_SOUND_DOSE,
"CSD updates");
@@ -923,7 +933,7 @@ public class SoundDoseHelper {
Log.v(TAG, "Initializing sound dose");
try {
- if (mCachedAudioDeviceCategories.size() > 0) {
+ if (!mCachedAudioDeviceCategories.isEmpty()) {
soundDose.initCachedAudioDeviceCategories(mCachedAudioDeviceCategories.toArray(
new ISoundDose.AudioDeviceCategory[0]));
mCachedAudioDeviceCategories.clear();
@@ -957,6 +967,7 @@ public class SoundDoseHelper {
mGlobalTimeOffsetInSecs);
if (records != null) {
mDoseRecords.addAll(records);
+ sanitizeDoseRecords_l();
}
}
}
@@ -1176,17 +1187,35 @@ public class SoundDoseHelper {
&& r.duration == record.duration)) {
Log.w(TAG, "Could not find cached record to remove: " + record);
}
- } else {
+ } else if (record.value > 0) {
mDoseRecords.add(record);
}
}
+ sanitizeDoseRecords_l();
+
mAudioHandler.sendMessageAtTime(mAudioHandler.obtainMessage(MSG_PERSIST_CSD_VALUES,
/* arg1= */0, /* arg2= */0, /* obj= */null), /* delay= */0);
mLogger.enqueue(SoundDoseEvent.getDoseUpdateEvent(currentCsd, totalDuration));
}
+ @GuardedBy("mCsdStateLock")
+ private void sanitizeDoseRecords_l() {
+ if (mDoseRecords.size() > MAX_NUMBER_OF_CACHED_RECORDS) {
+ int nrToRemove = MAX_NUMBER_OF_CACHED_RECORDS - mDoseRecords.size();
+ Log.w(TAG,
+ "Removing " + nrToRemove + " records from the total of " + mDoseRecords.size());
+ // Remove older elements to fit into persisted settings max length
+ Iterator<SoundDoseRecord> recordIterator = mDoseRecords.iterator();
+ while (recordIterator.hasNext() && nrToRemove > 0) {
+ recordIterator.next();
+ recordIterator.remove();
+ --nrToRemove;
+ }
+ }
+ }
+
@SuppressWarnings("GuardedBy") // avoid limitation with intra-procedural analysis of lambdas
private void onPersistSoundDoseRecords() {
synchronized (mCsdStateLock) {
@@ -1213,8 +1242,8 @@ public class SoundDoseHelper {
long globalTimeOffsetInSecs) {
return convertToGlobalTime(record.timestamp, globalTimeOffsetInSecs)
+ PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.duration
- + PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.value
- + PERSIST_CSD_RECORD_FIELD_SEPARATOR + record.averageMel;
+ + PERSIST_CSD_RECORD_FIELD_SEPARATOR + String.format("%.3f", record.value)
+ + PERSIST_CSD_RECORD_FIELD_SEPARATOR + String.format("%.3f", record.averageMel);
}
private static long convertToGlobalTime(long bootTimeInSecs, long globalTimeOffsetInSecs) {
diff --git a/services/core/java/com/android/server/display/feature/display_flags.aconfig b/services/core/java/com/android/server/display/feature/display_flags.aconfig
index c9569cbf4b9a..a2319a8a7c07 100644
--- a/services/core/java/com/android/server/display/feature/display_flags.aconfig
+++ b/services/core/java/com/android/server/display/feature/display_flags.aconfig
@@ -109,7 +109,7 @@ flag {
name: "back_up_smooth_display_and_force_peak_refresh_rate"
namespace: "display_manager"
description: "Feature flag for backing up Smooth Display and Force Peak Refresh Rate"
- bug: "211737588"
+ bug: "299552529"
is_fixed_read_only: true
}
@@ -125,7 +125,7 @@ flag {
name: "brightness_int_range_user_perception"
namespace: "display_manager"
description: "Feature flag for converting the brightness integer range to the user perception scale"
- bug: "183655602"
+ bug: "319236956"
is_fixed_read_only: true
}
diff --git a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
index 50e953323443..ad3deffb9590 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -22,7 +22,6 @@ import static android.os.PowerManager.BRIGHTNESS_INVALID_FLOAT;
import static android.view.Display.Mode.INVALID_MODE_ID;
import static com.android.server.display.DisplayDeviceConfig.DEFAULT_LOW_REFRESH_RATE;
-import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay;
import android.annotation.IntegerRes;
import android.annotation.NonNull;
@@ -238,8 +237,11 @@ public class DisplayModeDirector {
* is ready.
*/
public void start(SensorManager sensorManager) {
- mSettingsObserver.observe();
+ // This has to be called first to read the supported display modes that will be used by
+ // other observers
mDisplayObserver.observe();
+
+ mSettingsObserver.observe();
mBrightnessObserver.observe(sensorManager);
mSensorObserver.observe();
mHbmObserver.observe();
@@ -620,11 +622,16 @@ public class DisplayModeDirector {
}
@VisibleForTesting
+ DisplayObserver getDisplayObserver() {
+ return mDisplayObserver;
+ }
+
+ @VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
synchronized (mLock) {
- mSettingsObserver.updateRefreshRateSettingLocked(
- minRefreshRate, peakRefreshRate, defaultRefreshRate);
+ mSettingsObserver.updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate,
+ defaultRefreshRate, Display.DEFAULT_DISPLAY);
return getDesiredDisplayModeSpecs(Display.DEFAULT_DISPLAY);
}
}
@@ -897,19 +904,17 @@ public class DisplayModeDirector {
if (defaultPeakRefreshRate == null) {
setDefaultPeakRefreshRate(mDefaultDisplayDeviceConfig,
/* attemptReadFromFeatureParams= */ false);
- updateRefreshRateSettingLocked();
} else if (mDefaultPeakRefreshRate != defaultPeakRefreshRate) {
mDefaultPeakRefreshRate = defaultPeakRefreshRate;
- updateRefreshRateSettingLocked();
}
+ updateRefreshRateSettingLocked();
}
}
@Override
public void onChange(boolean selfChange, Uri uri, int userId) {
synchronized (mLock) {
- if (mPeakRefreshRateSetting.equals(uri)
- || mMinRefreshRateSetting.equals(uri)) {
+ if (mPeakRefreshRateSetting.equals(uri) || mMinRefreshRateSetting.equals(uri)) {
updateRefreshRateSettingLocked();
} else if (mLowPowerModeSetting.equals(uri)) {
updateLowPowerModeSettingLocked();
@@ -969,9 +974,29 @@ public class DisplayModeDirector {
mBrightnessObserver.onLowPowerModeEnabledLocked(inLowPowerMode);
}
+ /**
+ * Update refresh rate settings for all displays
+ */
+ @GuardedBy("mLock")
private void updateRefreshRateSettingLocked() {
+ for (int i = 0; i < mSupportedModesByDisplay.size(); i++) {
+ updateRefreshRateSettingLocked(mSupportedModesByDisplay.keyAt(i));
+ }
+ }
+
+ /**
+ * Update refresh rate settings for a specific display
+ * @param displayId The display ID
+ */
+ @GuardedBy("mLock")
+ private void updateRefreshRateSettingLocked(int displayId) {
final ContentResolver cr = mContext.getContentResolver();
- float highestRefreshRate = findHighestRefreshRateForDefaultDisplay(mContext);
+ if (!mSupportedModesByDisplay.contains(displayId)) {
+ Slog.e(TAG, "Cannot update refresh rate setting: no supported modes for display "
+ + displayId);
+ return;
+ }
+ float highestRefreshRate = getMaxRefreshRateLocked(displayId);
float minRefreshRate = Settings.System.getFloatForUser(cr,
Settings.System.MIN_REFRESH_RATE, 0f, cr.getUserId());
@@ -1009,11 +1034,13 @@ public class DisplayModeDirector {
Float.POSITIVE_INFINITY, cr.getUserId());
}
- updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate);
+ updateRefreshRateSettingLocked(minRefreshRate, peakRefreshRate, mDefaultRefreshRate,
+ displayId);
}
- private void updateRefreshRateSettingLocked(
- float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
+ @GuardedBy("mLock")
+ private void updateRefreshRateSettingLocked(float minRefreshRate, float peakRefreshRate,
+ float defaultRefreshRate, int displayId) {
// TODO(b/156304339): The logic in here, aside from updating the refresh rate votes, is
// used to predict if we're going to be doing frequent refresh rate switching, and if
// so, enable the brightness observer. The logic here is more complicated and fragile
@@ -1021,9 +1048,9 @@ public class DisplayModeDirector {
Vote peakVote = peakRefreshRate == 0f
? null
: Vote.forRenderFrameRates(0f, Math.max(minRefreshRate, peakRefreshRate));
- mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
peakVote);
- mVotesStorage.updateGlobalVote(Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
Vote.forRenderFrameRates(minRefreshRate, Float.POSITIVE_INFINITY));
Vote defaultVote =
defaultRefreshRate == 0f
@@ -1050,6 +1077,14 @@ public class DisplayModeDirector {
mBrightnessObserver.onRefreshRateSettingChangedLocked(minRefreshRate, maxRefreshRate);
}
+ private void removeRefreshRateSetting(int displayId) {
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE,
+ null);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE,
+ null);
+ mVotesStorage.updateVote(displayId, Vote.PRIORITY_DEFAULT_RENDER_FRAME_RATE, null);
+ }
+
private void updateModeSwitchingTypeSettingLocked() {
final ContentResolver cr = mContext.getContentResolver();
int switchingType = Settings.Secure.getIntForUser(
@@ -1180,7 +1215,8 @@ public class DisplayModeDirector {
}
}
- private final class DisplayObserver implements DisplayManager.DisplayListener {
+ @VisibleForTesting
+ public final class DisplayObserver implements DisplayManager.DisplayListener {
// Note that we can never call into DisplayManager or any of the non-POD classes it
// returns, while holding mLock since it may call into DMS, which might be simultaneously
// calling into us already holding its own lock.
@@ -1227,11 +1263,10 @@ public class DisplayModeDirector {
// Populate existing displays
SparseArray<Display.Mode[]> modes = new SparseArray<>();
SparseArray<Display.Mode> defaultModes = new SparseArray<>();
- DisplayInfo info = new DisplayInfo();
Display[] displays = mInjector.getDisplays();
for (Display d : displays) {
final int displayId = d.getDisplayId();
- d.getDisplayInfo(info);
+ DisplayInfo info = getDisplayInfo(displayId);
modes.put(displayId, info.supportedModes);
defaultModes.put(displayId, info.getDefaultMode());
}
@@ -1259,6 +1294,7 @@ public class DisplayModeDirector {
synchronized (mLock) {
mSupportedModesByDisplay.remove(displayId);
mDefaultModeByDisplay.remove(displayId);
+ mSettingsObserver.removeRefreshRateSetting(displayId);
}
updateLayoutLimitedFrameRate(displayId, null);
removeUserSettingDisplayPreferredSize(displayId);
@@ -1409,6 +1445,7 @@ public class DisplayModeDirector {
}
if (changed) {
notifyDesiredDisplayModeSpecsChangedLocked();
+ mSettingsObserver.updateRefreshRateSettingLocked(displayId);
}
}
}
diff --git a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
index d02b6f4cff53..171fbb6f8a16 100644
--- a/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
+++ b/services/core/java/com/android/server/location/gnss/GnssMeasurementsProvider.java
@@ -25,6 +25,7 @@ import static com.android.server.location.gnss.GnssManagerService.TAG;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.location.GnssMeasurement;
import android.location.GnssMeasurementRequest;
import android.location.GnssMeasurementsEvent;
import android.location.IGnssMeasurementsListener;
@@ -33,6 +34,7 @@ import android.os.IBinder;
import android.stats.location.LocationStatsEnums;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.server.location.gnss.GnssConfiguration.HalInterfaceVersion;
import com.android.server.location.gnss.hal.GnssNative;
import com.android.server.location.injector.AppOpsHelper;
@@ -40,6 +42,8 @@ import com.android.server.location.injector.Injector;
import com.android.server.location.injector.LocationUsageLogger;
import com.android.server.location.injector.SettingsHelper;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.Collection;
/**
@@ -91,6 +95,9 @@ public final class GnssMeasurementsProvider extends
private final LocationUsageLogger mLogger;
private final GnssNative mGnssNative;
+ @GuardedBy("mMultiplexerLock")
+ private GnssMeasurementsEvent mLastGnssMeasurementsEvent;
+
public GnssMeasurementsProvider(Injector injector, GnssNative gnssNative) {
super(injector);
mAppOpsHelper = injector.getAppOpsHelper();
@@ -264,5 +271,46 @@ public final class GnssMeasurementsProvider extends
return null;
}
});
+ synchronized (mMultiplexerLock) {
+ mLastGnssMeasurementsEvent = event;
+ }
+ }
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dump(fd, pw, args);
+ pw.print("last measurements=");
+ pw.println(getLastMeasurementEventSummary());
+ }
+
+ /**
+ * Returns a string of GnssMeasurementsEvent summary including received time, satellite count
+ * and average baseband C/No.
+ */
+ private String getLastMeasurementEventSummary() {
+ synchronized (mMultiplexerLock) {
+ if (mLastGnssMeasurementsEvent == null) {
+ return null;
+ }
+ StringBuilder builder = new StringBuilder("[");
+ builder.append("elapsedRealtimeNs=").append(
+ mLastGnssMeasurementsEvent.getClock().getElapsedRealtimeNanos());
+ builder.append(" measurementCount=").append(
+ mLastGnssMeasurementsEvent.getMeasurements().size());
+
+ float sumBasebandCn0 = 0;
+ int countBasebandCn0 = 0;
+ for (GnssMeasurement measurement : mLastGnssMeasurementsEvent.getMeasurements()) {
+ if (measurement.hasBasebandCn0DbHz()) {
+ sumBasebandCn0 += measurement.getBasebandCn0DbHz();
+ countBasebandCn0++;
+ }
+ }
+ if (countBasebandCn0 > 0) {
+ builder.append(" avgBasebandCn0=").append(sumBasebandCn0 / countBasebandCn0);
+ }
+ builder.append("]");
+ return builder.toString();
+ }
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index ad090829a2f6..542b3b06184a 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -52,6 +52,7 @@ import static com.android.server.locksettings.SyntheticPasswordManager.TOKEN_TYP
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.IActivityManager;
@@ -74,6 +75,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
+import android.content.pm.UserProperties;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.database.sqlite.SQLiteDatabase;
@@ -303,7 +305,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private boolean mThirdPartyAppsStarted;
// Current password metrics for all secured users on the device. Updated when user unlocks the
- // device or changes password. Removed when user is stopped.
+ // device or changes password. Removed if user is stopped with its CE key evicted.
@GuardedBy("this")
private final SparseArray<PasswordMetrics> mUserPasswordMetrics = new SparseArray<>();
@VisibleForTesting
@@ -793,13 +795,33 @@ public class LockSettingsService extends ILockSettings.Stub {
}
@VisibleForTesting
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.MANAGE_USERS,
+ android.Manifest.permission.QUERY_USERS,
+ android.Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true)
void onUserStopped(int userId) {
hideEncryptionNotification(new UserHandle(userId));
- // User is stopped with its CE key evicted. Restore strong auth requirement to the default
- // flags after boot since stopping and restarting a user later is equivalent to rebooting
- // the device.
+
+ // Normally, CE storage is locked when a user is stopped, and restarting the user requires
+ // strong auth. Therefore, reset the user's strong auth flags. The exception is users that
+ // allow delayed locking; under some circumstances, biometric authentication is allowed to
+ // restart such users. Don't reset the strong auth flags for such users.
+ //
+ // TODO(b/319142556): It might make more sense to reset the strong auth flags when CE
+ // storage is locked, instead of when the user is stopped. This would ensure the flags get
+ // reset if CE storage is locked later for a user that allows delayed locking.
+ if (android.os.Flags.allowPrivateProfile()
+ && android.multiuser.Flags.enableBiometricsToUnlockPrivateSpace()) {
+ UserProperties userProperties = mUserManager.getUserProperties(UserHandle.of(userId));
+ if (userProperties != null && userProperties.getAllowStoppingUserWithDelayedLocking()) {
+ return;
+ }
+ }
int strongAuthRequired = LockPatternUtils.StrongAuthTracker.getDefaultFlags(mContext);
requireStrongAuth(strongAuthRequired, userId);
+
+ // Don't keep the password metrics in memory for a stopped user that will require strong
+ // auth to start again, since strong auth will make the password metrics available again.
synchronized (this) {
mUserPasswordMetrics.remove(userId);
}
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index 06a8d989b930..e048522eee53 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -774,7 +774,7 @@ class MediaRouter2ServiceImpl {
.generateDeviceRouteSelectedSessionInfo(packageName);
} else {
sessionInfos = userRecord.mHandler.mSystemProvider.getSessionInfos();
- if (sessionInfos != null && !sessionInfos.isEmpty()) {
+ if (!sessionInfos.isEmpty()) {
// Return a copy of the current system session with no modification,
// except setting the client package name.
return new RoutingSessionInfo.Builder(sessionInfos.get(0))
@@ -1158,14 +1158,7 @@ class MediaRouter2ServiceImpl {
} else {
if (route.isSystemRoute()
&& !routerRecord.hasSystemRoutingPermission()
- && !TextUtils.equals(
- route.getId(),
- routerRecord
- .mUserRecord
- .mHandler
- .mSystemProvider
- .getDefaultRoute()
- .getId())) {
+ && !TextUtils.equals(route.getId(), MediaRoute2Info.ROUTE_ID_DEFAULT)) {
Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
+ route);
routerRecord.mUserRecord.mHandler.notifySessionCreationFailedToRouter(
@@ -1252,11 +1245,9 @@ class MediaRouter2ServiceImpl {
"transferToRouteWithRouter2 | router: %s(id: %d), route: %s",
routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
- String defaultRouteId =
- routerRecord.mUserRecord.mHandler.mSystemProvider.getDefaultRoute().getId();
if (route.isSystemRoute()
&& !routerRecord.hasSystemRoutingPermission()
- && !TextUtils.equals(route.getId(), defaultRouteId)) {
+ && !TextUtils.equals(route.getId(), MediaRoute2Info.ROUTE_ID_DEFAULT)) {
routerRecord.mUserRecord.mHandler.sendMessage(
obtainMessage(UserHandler::notifySessionCreationFailedToRouter,
routerRecord.mUserRecord.mHandler,
@@ -2761,11 +2752,10 @@ class MediaRouter2ServiceImpl {
if (manager != null) {
notifyRequestFailedToManager(
manager.mManager, toOriginalRequestId(uniqueRequestId), reason);
- return;
}
- // Currently, only the manager can get notified of failures.
- // TODO: Notify router too when the related callback is introduced.
+ // Currently, only manager records can get notified of failures.
+ // TODO(b/282936553): Notify regular routers of request failures.
}
private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
@@ -2909,11 +2899,9 @@ class MediaRouter2ServiceImpl {
currentSystemSessionInfo = mSystemProvider.getDefaultSessionInfo();
}
- if (currentRoutes.size() == 0) {
- return;
+ if (!currentRoutes.isEmpty()) {
+ routerRecord.notifyRegistered(currentRoutes, currentSystemSessionInfo);
}
-
- routerRecord.notifyRegistered(currentRoutes, currentSystemSessionInfo);
}
private static void notifyRoutesUpdatedToRouterRecords(
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 6deda468f9a2..f6571d94d554 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -653,14 +653,14 @@ public final class MediaProjectionManagerService extends SystemService
}
@Override // Binder call
- public boolean hasProjectionPermission(int uid, String packageName) {
+ public boolean hasProjectionPermission(int processUid, String packageName) {
final long token = Binder.clearCallingIdentity();
boolean hasPermission = false;
try {
hasPermission |= checkPermission(packageName,
android.Manifest.permission.CAPTURE_VIDEO_OUTPUT)
|| mAppOps.noteOpNoThrow(
- AppOpsManager.OP_PROJECT_MEDIA, uid, packageName)
+ AppOpsManager.OP_PROJECT_MEDIA, processUid, packageName)
== AppOpsManager.MODE_ALLOWED;
} finally {
Binder.restoreCallingIdentity(token);
@@ -669,7 +669,7 @@ public final class MediaProjectionManagerService extends SystemService
}
@Override // Binder call
- public IMediaProjection createProjection(int uid, String packageName, int type,
+ public IMediaProjection createProjection(int processUid, String packageName, int type,
boolean isPermanentGrant) {
if (mContext.checkCallingPermission(MANAGE_MEDIA_PROJECTION)
!= PackageManager.PERMISSION_GRANTED) {
@@ -680,13 +680,13 @@ public final class MediaProjectionManagerService extends SystemService
throw new IllegalArgumentException("package name must not be empty");
}
final UserHandle callingUser = Binder.getCallingUserHandle();
- return createProjectionInternal(uid, packageName, type, isPermanentGrant,
+ return createProjectionInternal(processUid, packageName, type, isPermanentGrant,
callingUser);
}
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public IMediaProjection getProjection(int uid, String packageName) {
+ public IMediaProjection getProjection(int processUid, String packageName) {
getProjection_enforcePermission();
if (packageName == null || packageName.isEmpty()) {
throw new IllegalArgumentException("package name must not be empty");
@@ -695,7 +695,7 @@ public final class MediaProjectionManagerService extends SystemService
MediaProjection projection;
final long callingToken = Binder.clearCallingIdentity();
try {
- projection = getProjectionInternal(uid, packageName);
+ projection = getProjectionInternal(processUid, packageName);
} finally {
Binder.restoreCallingIdentity(callingToken);
}
@@ -869,12 +869,13 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void notifyPermissionRequestInitiated(int hostUid, int sessionCreationSource) {
+ public void notifyPermissionRequestInitiated(
+ int hostProcessUid, int sessionCreationSource) {
notifyPermissionRequestInitiated_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
MediaProjectionManagerService.this.notifyPermissionRequestInitiated(
- hostUid, sessionCreationSource);
+ hostProcessUid, sessionCreationSource);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -882,11 +883,11 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void notifyPermissionRequestDisplayed(int hostUid) {
+ public void notifyPermissionRequestDisplayed(int hostProcessUid) {
notifyPermissionRequestDisplayed_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
- MediaProjectionManagerService.this.notifyPermissionRequestDisplayed(hostUid);
+ MediaProjectionManagerService.this.notifyPermissionRequestDisplayed(hostProcessUid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -894,11 +895,11 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void notifyPermissionRequestCancelled(int hostUid) {
+ public void notifyPermissionRequestCancelled(int hostProcessUid) {
notifyPermissionRequestCancelled_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
- MediaProjectionManagerService.this.notifyPermissionRequestCancelled(hostUid);
+ MediaProjectionManagerService.this.notifyPermissionRequestCancelled(hostProcessUid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -906,11 +907,11 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
- public void notifyAppSelectorDisplayed(int hostUid) {
+ public void notifyAppSelectorDisplayed(int hostProcessUid) {
notifyAppSelectorDisplayed_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
- MediaProjectionManagerService.this.notifyAppSelectorDisplayed(hostUid);
+ MediaProjectionManagerService.this.notifyAppSelectorDisplayed(hostProcessUid);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -919,12 +920,12 @@ public final class MediaProjectionManagerService extends SystemService
@Override // Binder call
@EnforcePermission(MANAGE_MEDIA_PROJECTION)
public void notifyWindowingModeChanged(
- int contentToRecord, int targetUid, int windowingMode) {
+ int contentToRecord, int targetProcessUid, int windowingMode) {
notifyWindowingModeChanged_enforcePermission();
final long token = Binder.clearCallingIdentity();
try {
MediaProjectionManagerService.this.notifyWindowingModeChanged(
- contentToRecord, targetUid, windowingMode);
+ contentToRecord, targetProcessUid, windowingMode);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/services/core/java/com/android/server/notification/NotificationHistoryManager.java b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
index e3880c383632..deb95d8a392d 100644
--- a/services/core/java/com/android/server/notification/NotificationHistoryManager.java
+++ b/services/core/java/com/android/server/notification/NotificationHistoryManager.java
@@ -108,7 +108,7 @@ public class NotificationHistoryManager {
for (int i = 0; i < pendingPackageRemovals.size(); i++) {
userHistory.onPackageRemoved(pendingPackageRemovals.get(i));
}
- mUserPendingPackageRemovals.put(userId, null);
+ mUserPendingPackageRemovals.remove(userId);
}
// delete history if it was disabled when the user was locked
@@ -133,7 +133,7 @@ public class NotificationHistoryManager {
synchronized (mLock) {
// Actual data deletion is handled by other parts of the system (the entire directory is
// removed) - we just need clean up our internal state for GC
- mUserPendingPackageRemovals.put(userId, null);
+ mUserPendingPackageRemovals.remove(userId);
mHistoryEnabled.put(userId, false);
mUserPendingHistoryDisables.put(userId, false);
onUserStopped(userId);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7aa7b7e1bfc1..9ddc362769f6 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -215,7 +215,6 @@ import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.LauncherApps;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManagerInternal;
@@ -373,6 +372,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
+import java.time.Clock;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Arrays;
@@ -2466,8 +2466,8 @@ public class NotificationManagerService extends SystemService {
mMetricsLogger = new MetricsLogger();
mRankingHandler = rankingHandler;
mConditionProviders = conditionProviders;
- mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders,
- flagResolver, new ZenModeEventLogger(mPackageManagerClient));
+ mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), Clock.systemUTC(),
+ mConditionProviders, flagResolver, new ZenModeEventLogger(mPackageManagerClient));
mZenModeHelper.addCallback(new ZenModeHelper.Callback() {
@Override
public void onConfigChanged() {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 911643b1a634..afbf08d9b77d 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -117,6 +117,9 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.io.PrintWriter;
+import java.time.Clock;
+import java.time.Duration;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -130,9 +133,12 @@ public class ZenModeHelper {
static final String TAG = "ZenModeHelper";
static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private static final String PACKAGE_ANDROID = "android";
+
// The amount of time rules instances can exist without their owning app being installed.
private static final int RULE_INSTANCE_GRACE_PERIOD = 1000 * 60 * 60 * 72;
static final int RULE_LIMIT_PER_PACKAGE = 100;
+ private static final Duration DELETED_RULE_KEPT_FOR = Duration.ofDays(30);
private static final String IMPLICIT_RULE_ID_PREFIX = "implicit_"; // + pkg_name
@@ -148,6 +154,7 @@ public class ZenModeHelper {
private final Context mContext;
private final H mHandler;
+ private final Clock mClock;
private final SettingsObserver mSettingsObserver;
private final AppOpsManager mAppOps;
private final NotificationManager mNotificationManager;
@@ -189,11 +196,13 @@ public class ZenModeHelper {
private String[] mPriorityOnlyDndExemptPackages;
- public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders,
+ public ZenModeHelper(Context context, Looper looper, Clock clock,
+ ConditionProviders conditionProviders,
SystemUiSystemPropertiesFlags.FlagResolver flagResolver,
ZenModeEventLogger zenModeEventLogger) {
mContext = context;
mHandler = new H(looper);
+ mClock = clock;
addCallback(mMetrics);
mAppOps = context.getSystemService(AppOpsManager.class);
mNotificationManager = context.getSystemService(NotificationManager.class);
@@ -452,6 +461,7 @@ public class ZenModeHelper {
newConfig = mConfig.copy();
ZenRule rule = new ZenRule();
populateZenRule(pkg, automaticZenRule, rule, origin, /* isNew= */ true);
+ rule = maybeRestoreRemovedRule(newConfig, rule, automaticZenRule, origin);
newConfig.automaticRules.put(rule.id, rule);
maybeReplaceDefaultRule(newConfig, automaticZenRule);
@@ -463,6 +473,37 @@ public class ZenModeHelper {
}
}
+ private ZenRule maybeRestoreRemovedRule(ZenModeConfig config, ZenRule ruleToAdd,
+ AutomaticZenRule azrToAdd, @ConfigChangeOrigin int origin) {
+ if (!Flags.modesApi()) {
+ return ruleToAdd;
+ }
+ String deletedKey = ZenModeConfig.deletedRuleKey(ruleToAdd);
+ if (deletedKey == null) {
+ // Couldn't calculate the deletedRuleKey (condition or pkg null?). This should
+ // never happen for an app-provided rule because NMS validates both.
+ return ruleToAdd;
+ }
+ ZenRule ruleToRestore = config.deletedRules.get(deletedKey);
+ if (ruleToRestore == null) {
+ return ruleToAdd; // Cannot restore.
+ }
+
+ // We have found a previous rule to maybe restore. Whether we do that or not, we don't need
+ // to keep it around (if not restored now, it won't be in future calls either).
+ config.deletedRules.remove(deletedKey);
+ ruleToRestore.deletionInstant = null;
+
+ if (origin != UPDATE_ORIGIN_APP) {
+ return ruleToAdd; // Okay to create anew.
+ }
+
+ // "Preserve" the previous rule by considering the azrToAdd an update instead.
+ // Only app-modifiable fields will actually be modified.
+ populateZenRule(ruleToRestore.pkg, azrToAdd, ruleToRestore, origin, /* isNew= */ false);
+ return ruleToRestore;
+ }
+
private static void maybeReplaceDefaultRule(ZenModeConfig config, AutomaticZenRule addedRule) {
if (!Flags.modesApi()) {
return;
@@ -644,7 +685,7 @@ public class ZenModeHelper {
ZenRule rule = new ZenRule();
rule.id = implicitRuleId(pkg);
rule.pkg = pkg;
- rule.creationTime = System.currentTimeMillis();
+ rule.creationTime = mClock.millis();
Binder.withCleanCallingIdentity(() -> {
try {
@@ -664,7 +705,7 @@ public class ZenModeHelper {
rule.condition = null;
rule.conditionId = new Uri.Builder()
.scheme(Condition.SCHEME)
- .authority("android")
+ .authority(PACKAGE_ANDROID)
.appendPath("implicit")
.appendPath(pkg)
.build();
@@ -693,7 +734,9 @@ public class ZenModeHelper {
if (ruleToRemove == null) return false;
if (canManageAutomaticZenRule(ruleToRemove)) {
newConfig.automaticRules.remove(id);
- if (ruleToRemove.getPkg() != null && !"android".equals(ruleToRemove.getPkg())) {
+ maybePreserveRemovedRule(newConfig, ruleToRemove, origin);
+ if (ruleToRemove.getPkg() != null
+ && !PACKAGE_ANDROID.equals(ruleToRemove.getPkg())) {
for (ZenRule currRule : newConfig.automaticRules.values()) {
if (currRule.getPkg() != null
&& currRule.getPkg().equals(ruleToRemove.getPkg())) {
@@ -723,12 +766,44 @@ public class ZenModeHelper {
ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
if (Objects.equals(rule.getPkg(), packageName) && canManageAutomaticZenRule(rule)) {
newConfig.automaticRules.removeAt(i);
+ maybePreserveRemovedRule(newConfig, rule, origin);
+ }
+ }
+ // If the system is clearing all rules this means DND access is revoked or the package
+ // was uninstalled, so also clear the preserved-deleted rules.
+ if (origin == UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI) {
+ for (int i = newConfig.deletedRules.size() - 1; i >= 0; i--) {
+ ZenRule rule = newConfig.deletedRules.get(newConfig.deletedRules.keyAt(i));
+ if (Objects.equals(rule.getPkg(), packageName)) {
+ newConfig.deletedRules.removeAt(i);
+ }
}
}
return setConfigLocked(newConfig, origin, reason, null, true, callingUid);
}
}
+ private void maybePreserveRemovedRule(ZenModeConfig config, ZenRule ruleToRemove,
+ @ConfigChangeOrigin int origin) {
+ if (!Flags.modesApi()) {
+ return;
+ }
+ // If an app deletes a previously customized rule, keep it around to preserve
+ // the user's customization when/if it's recreated later.
+ // We don't try to preserve system-owned rules because their conditionIds (used as
+ // deletedRuleKey) are not stable. This is almost moot anyway because an app cannot
+ // delete a system-owned rule.
+ if (origin == UPDATE_ORIGIN_APP && !ruleToRemove.canBeUpdatedByApp()
+ && !PACKAGE_ANDROID.equals(ruleToRemove.pkg)) {
+ String deletedKey = ZenModeConfig.deletedRuleKey(ruleToRemove);
+ if (deletedKey != null) {
+ ruleToRemove.deletionInstant = Instant.now(mClock);
+ // Overwrites a previously-deleted rule with the same conditionId, but that's okay.
+ config.deletedRules.put(deletedKey, ruleToRemove);
+ }
+ }
+ }
+
void setAutomaticZenRuleState(String id, Condition condition, @ConfigChangeOrigin int origin,
int callingUid) {
ZenModeConfig newConfig;
@@ -919,7 +994,7 @@ public class ZenModeHelper {
// These values can always be edited by the app, so we apply changes immediately.
if (isNew) {
rule.id = ZenModeConfig.newRuleId();
- rule.creationTime = System.currentTimeMillis();
+ rule.creationTime = mClock.millis();
rule.component = automaticZenRule.getOwner();
rule.pkg = pkg;
}
@@ -1379,7 +1454,7 @@ public class ZenModeHelper {
boolean hasDefaultRules = config.automaticRules.containsAll(
ZenModeConfig.DEFAULT_RULE_IDS);
- long time = System.currentTimeMillis();
+ long time = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis();
if (config.automaticRules != null && config.automaticRules.size() > 0) {
for (ZenRule automaticRule : config.automaticRules.values()) {
if (forRestore) {
@@ -1419,6 +1494,12 @@ public class ZenModeHelper {
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId);
}
+
+ if (Flags.modesApi() && forRestore) {
+ // Note: forBackup doesn't write deletedRules, but just in case.
+ config.deletedRules.clear();
+ }
+
if (DEBUG) Log.d(TAG, reason);
synchronized (mConfigLock) {
setConfigLocked(config, null,
@@ -1436,7 +1517,7 @@ public class ZenModeHelper {
if (forBackup && mConfigs.keyAt(i) != userId) {
continue;
}
- mConfigs.valueAt(i).writeXml(out, version);
+ mConfigs.valueAt(i).writeXml(out, version, forBackup);
}
}
}
@@ -1468,28 +1549,51 @@ public class ZenModeHelper {
}
/**
- * Removes old rule instances whose owner is not installed.
+ * Cleans up obsolete rules:
+ * <ul>
+ * <li>Rule instances whose owner is not installed.
+ * <li>Deleted rules that were deleted more than 30 days ago.
+ * </ul>
*/
private void cleanUpZenRules() {
- long currentTime = System.currentTimeMillis();
+ Instant keptRuleThreshold = mClock.instant().minus(DELETED_RULE_KEPT_FOR);
synchronized (mConfigLock) {
final ZenModeConfig newConfig = mConfig.copy();
- if (newConfig.automaticRules != null) {
- for (int i = newConfig.automaticRules.size() - 1; i >= 0; i--) {
- ZenRule rule = newConfig.automaticRules.get(newConfig.automaticRules.keyAt(i));
- if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
- try {
- if (rule.getPkg() != null) {
- mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER);
- }
- } catch (PackageManager.NameNotFoundException e) {
- newConfig.automaticRules.removeAt(i);
+
+ deleteRulesWithoutOwner(newConfig.automaticRules);
+ if (Flags.modesApi()) {
+ deleteRulesWithoutOwner(newConfig.deletedRules);
+ for (int i = newConfig.deletedRules.size() - 1; i >= 0; i--) {
+ ZenRule deletedRule = newConfig.deletedRules.valueAt(i);
+ if (deletedRule.deletionInstant == null
+ || deletedRule.deletionInstant.isBefore(keptRuleThreshold)) {
+ newConfig.deletedRules.removeAt(i);
+ }
+ }
+ }
+
+ if (!newConfig.equals(mConfig)) {
+ setConfigLocked(newConfig, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI,
+ "cleanUpZenRules", Process.SYSTEM_UID);
+ }
+ }
+ }
+
+ private void deleteRulesWithoutOwner(ArrayMap<String, ZenRule> ruleList) {
+ long currentTime = Flags.modesApi() ? mClock.millis() : System.currentTimeMillis();
+ if (ruleList != null) {
+ for (int i = ruleList.size() - 1; i >= 0; i--) {
+ ZenRule rule = ruleList.valueAt(i);
+ if (RULE_INSTANCE_GRACE_PERIOD < (currentTime - rule.creationTime)) {
+ try {
+ if (rule.getPkg() != null) {
+ mPm.getPackageInfo(rule.getPkg(), PackageManager.MATCH_ANY_USER);
}
+ } catch (PackageManager.NameNotFoundException e) {
+ ruleList.removeAt(i);
}
}
}
- setConfigLocked(newConfig, null, UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "cleanUpZenRules",
- Process.SYSTEM_UID);
}
}
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java b/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
deleted file mode 100644
index 4454601f2254..000000000000
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlCallbackHelper.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-
-import android.annotation.NonNull;
-import android.app.BackgroundInstallControlManager;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.IRemoteCallback;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.util.Slog;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.ServiceThread;
-
-public class BackgroundInstallControlCallbackHelper {
-
- @VisibleForTesting static final String FLAGGED_PACKAGE_NAME_KEY = "packageName";
- @VisibleForTesting static final String FLAGGED_USER_ID_KEY = "userId";
- private static final String TAG = "BackgroundInstallControlCallbackHelper";
-
- private final Handler mHandler;
-
- BackgroundInstallControlCallbackHelper() {
- HandlerThread backgroundThread =
- new ServiceThread(
- "BackgroundInstallControlCallbackHelperBg",
- THREAD_PRIORITY_BACKGROUND,
- true);
- backgroundThread.start();
- mHandler = new Handler(backgroundThread.getLooper());
- }
-
- @NonNull @VisibleForTesting
- final RemoteCallbackList<IRemoteCallback> mCallbacks = new RemoteCallbackList<>();
-
- /** Registers callback that gets invoked upon detection of an MBA
- *
- * NOTE: The callback is user context agnostic and currently broadcasts to all users of other
- * users app installs. This is fine because the API is for SystemServer use only.
- */
- public void registerBackgroundInstallCallback(IRemoteCallback callback) {
- synchronized (mCallbacks) {
- mCallbacks.register(callback, null);
- }
- }
-
- /** Unregisters callback */
- public void unregisterBackgroundInstallCallback(IRemoteCallback callback) {
- synchronized (mCallbacks) {
- mCallbacks.unregister(callback);
- }
- }
-
- /**
- * Invokes all registered callbacks Callbacks are processed through user provided-threads and
- * parameters are passed in via {@link BackgroundInstallControlManager} InstallEvent
- */
- public void notifyAllCallbacks(int userId, String packageName) {
- Bundle extras = new Bundle();
- extras.putCharSequence(FLAGGED_PACKAGE_NAME_KEY, packageName);
- extras.putInt(FLAGGED_USER_ID_KEY, userId);
- synchronized (mCallbacks) {
- mHandler.post(
- () ->
- mCallbacks.broadcast(
- callback -> {
- try {
- callback.sendResult(extras);
- } catch (RemoteException e) {
- Slog.e(
- TAG,
- "error detected: " + e.getLocalizedMessage(),
- e);
- }
- }));
- }
- }
-}
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index 3a9dedcf2d7b..7f0aadce3143 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -16,12 +16,7 @@
package com.android.server.pm;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
import android.app.usage.UsageEvents;
import android.app.usage.UsageStatsManagerInternal;
import android.content.Context;
@@ -35,7 +30,6 @@ import android.content.pm.ParceledListSlice;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
-import android.os.IRemoteCallback;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
@@ -75,10 +69,8 @@ public class BackgroundInstallControlService extends SystemService {
private static final String DISK_FILE_NAME = "states";
private static final String DISK_DIR_NAME = "bic";
- private static final String ENFORCE_PERMISSION_ERROR_MSG =
- "User is not permitted to call service: ";
-
private static final int MAX_FOREGROUND_TIME_FRAMES_SIZE = 10;
+
private static final int MSG_USAGE_EVENT_RECEIVED = 0;
private static final int MSG_PACKAGE_ADDED = 1;
private static final int MSG_PACKAGE_REMOVED = 2;
@@ -86,20 +78,19 @@ public class BackgroundInstallControlService extends SystemService {
private final Context mContext;
private final BinderService mBinderService;
private final PackageManager mPackageManager;
- // TODO migrate all internal PackageManager calls to PackageManagerInternal where possible.
- // b/310983905
private final PackageManagerInternal mPackageManagerInternal;
private final UsageStatsManagerInternal mUsageStatsManagerInternal;
private final PermissionManagerServiceInternal mPermissionManager;
private final Handler mHandler;
private final File mDiskFile;
+
private SparseSetArray<String> mBackgroundInstalledPackages = null;
- private final BackgroundInstallControlCallbackHelper mCallbackHelper;
// User ID -> package name -> set of foreground time frame
- private final SparseArrayMap<String, TreeSet<ForegroundTimeFrame>>
- mInstallerForegroundTimeFrames = new SparseArrayMap<>();
+ private final SparseArrayMap<String,
+ TreeSet<ForegroundTimeFrame>> mInstallerForegroundTimeFrames =
+ new SparseArrayMap<>();
public BackgroundInstallControlService(@NonNull Context context) {
this(new InjectorImpl(context));
@@ -115,11 +106,13 @@ public class BackgroundInstallControlService extends SystemService {
mHandler = new EventHandler(injector.getLooper(), this);
mDiskFile = injector.getDiskFile();
mUsageStatsManagerInternal = injector.getUsageStatsManagerInternal();
- mCallbackHelper = injector.getBackgroundInstallControlCallbackHelper();
mUsageStatsManagerInternal.registerListener(
(userId, event) ->
- mHandler.obtainMessage(MSG_USAGE_EVENT_RECEIVED, userId, 0, event)
- .sendToTarget());
+ mHandler.obtainMessage(MSG_USAGE_EVENT_RECEIVED,
+ userId,
+ 0,
+ event).sendToTarget()
+ );
mBinderService = new BinderService(this);
}
@@ -133,15 +126,12 @@ public class BackgroundInstallControlService extends SystemService {
@Override
public ParceledListSlice<PackageInfo> getBackgroundInstalledPackages(
@PackageManager.PackageInfoFlagsBits long flags, int userId) {
- mService.enforceCallerQueryPackagesPermissions();
if (!Build.IS_DEBUGGABLE) {
return mService.getBackgroundInstalledPackages(flags, userId);
}
// The debug.transparency.bg-install-apps (only works for debuggable builds)
// is used to set mock list of background installed apps for testing.
// The list of apps' names is delimited by ",".
- // TODO: Remove after migrating test to new background install method using
- // {@link BackgroundInstallControlCallbackHelperTest}.installPackage b/310983905
String propertyString = SystemProperties.get("debug.transparency.bg-install-apps");
if (TextUtils.isEmpty(propertyString)) {
return mService.getBackgroundInstalledPackages(flags, userId);
@@ -149,41 +139,16 @@ public class BackgroundInstallControlService extends SystemService {
return mService.getMockBackgroundInstalledPackages(propertyString);
}
}
-
- @Override
- public void registerBackgroundInstallCallback(IRemoteCallback callback) {
- mService.enforceCallerQueryPackagesPermissions();
- mService.enforceCallerInteractCrossUserPermissions();
- mService.mCallbackHelper.registerBackgroundInstallCallback(callback);
- }
-
- @Override
- public void unregisterBackgroundInstallCallback(IRemoteCallback callback) {
- mService.enforceCallerQueryPackagesPermissions();
- mService.enforceCallerInteractCrossUserPermissions();
- mService.mCallbackHelper.unregisterBackgroundInstallCallback(callback);
- }
- }
-
- @RequiresPermission(QUERY_ALL_PACKAGES)
- void enforceCallerQueryPackagesPermissions() throws SecurityException {
- mContext.enforceCallingPermission(QUERY_ALL_PACKAGES,
- ENFORCE_PERMISSION_ERROR_MSG + QUERY_ALL_PACKAGES);
- }
-
- @RequiresPermission(INTERACT_ACROSS_USERS_FULL)
- void enforceCallerInteractCrossUserPermissions() throws SecurityException {
- mContext.enforceCallingPermission(INTERACT_ACROSS_USERS_FULL,
- ENFORCE_PERMISSION_ERROR_MSG + INTERACT_ACROSS_USERS_FULL);
}
@VisibleForTesting
ParceledListSlice<PackageInfo> getBackgroundInstalledPackages(
@PackageManager.PackageInfoFlagsBits long flags, int userId) {
List<PackageInfo> packages = mPackageManager.getInstalledPackagesAsUser(
- PackageManager.PackageInfoFlags.of(flags), userId);
+ PackageManager.PackageInfoFlags.of(flags), userId);
initBackgroundInstalledPackages();
+
ListIterator<PackageInfo> iter = packages.listIterator();
while (iter.hasNext()) {
String packageName = iter.next().packageName;
@@ -205,9 +170,8 @@ public class BackgroundInstallControlService extends SystemService {
List<PackageInfo> mockPackages = new ArrayList<>();
for (String name : mockPackageNames) {
try {
- PackageInfo packageInfo =
- mPackageManager.getPackageInfo(
- name, PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL));
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(name,
+ PackageManager.PackageInfoFlags.of(PackageManager.MATCH_ALL));
mockPackages.add(packageInfo);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Package's PackageInfo not found " + name);
@@ -228,16 +192,18 @@ public class BackgroundInstallControlService extends SystemService {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case MSG_USAGE_EVENT_RECEIVED:
- mService.handleUsageEvent(
- (UsageEvents.Event) msg.obj, msg.arg1 /* userId */);
+ case MSG_USAGE_EVENT_RECEIVED: {
+ mService.handleUsageEvent((UsageEvents.Event) msg.obj, msg.arg1 /* userId */);
break;
- case MSG_PACKAGE_ADDED:
+ }
+ case MSG_PACKAGE_ADDED: {
mService.handlePackageAdd((String) msg.obj, msg.arg1 /* userId */);
break;
- case MSG_PACKAGE_REMOVED:
+ }
+ case MSG_PACKAGE_REMOVED: {
mService.handlePackageRemove((String) msg.obj, msg.arg1 /* userId */);
break;
+ }
default:
Slog.w(TAG, "Unknown message: " + msg.what);
}
@@ -247,9 +213,8 @@ public class BackgroundInstallControlService extends SystemService {
void handlePackageAdd(String packageName, int userId) {
ApplicationInfo appInfo = null;
try {
- appInfo =
- mPackageManager.getApplicationInfoAsUser(
- packageName, PackageManager.ApplicationInfoFlags.of(0), userId);
+ appInfo = mPackageManager.getApplicationInfoAsUser(packageName,
+ PackageManager.ApplicationInfoFlags.of(0), userId);
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Package's appInfo not found " + packageName);
return;
@@ -268,18 +233,15 @@ public class BackgroundInstallControlService extends SystemService {
// the installers without INSTALL_PACKAGES perm can't perform
// the installation in background. So we can just filter out them.
- if (mPermissionManager.checkPermission(
- installerPackageName,
- android.Manifest.permission.INSTALL_PACKAGES,
- Context.DEVICE_ID_DEFAULT,
- userId)
- != PERMISSION_GRANTED) {
+ if (mPermissionManager.checkPermission(installerPackageName,
+ android.Manifest.permission.INSTALL_PACKAGES, Context.DEVICE_ID_DEFAULT,
+ userId) != PackageManager.PERMISSION_GRANTED) {
return;
}
// convert up-time to current time.
- final long installTimestamp =
- System.currentTimeMillis() - (SystemClock.uptimeMillis() - appInfo.createTimestamp);
+ final long installTimestamp = System.currentTimeMillis()
+ - (SystemClock.uptimeMillis() - appInfo.createTimestamp);
if (installedByAdb(initiatingPackageName)
|| wasForegroundInstallation(installerPackageName, userId, installTimestamp)) {
@@ -288,7 +250,6 @@ public class BackgroundInstallControlService extends SystemService {
initBackgroundInstalledPackages();
mBackgroundInstalledPackages.add(userId, packageName);
- mCallbackHelper.notifyAllCallbacks(userId, packageName);
writeBackgroundInstalledPackagesToDisk();
}
@@ -298,8 +259,8 @@ public class BackgroundInstallControlService extends SystemService {
return PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName);
}
- private boolean wasForegroundInstallation(
- String installerPackageName, int userId, long installTimestamp) {
+ private boolean wasForegroundInstallation(String installerPackageName,
+ int userId, long installTimestamp) {
TreeSet<BackgroundInstallControlService.ForegroundTimeFrame> foregroundTimeFrames =
mInstallerForegroundTimeFrames.get(userId, installerPackageName);
@@ -388,12 +349,12 @@ public class BackgroundInstallControlService extends SystemService {
for (int i = 0; i < mBackgroundInstalledPackages.size(); i++) {
int userId = mBackgroundInstalledPackages.keyAt(i);
for (String packageName : mBackgroundInstalledPackages.get(userId)) {
- long token =
- protoOutputStream.start(
- BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token = protoOutputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
protoOutputStream.write(
BackgroundInstalledPackageProto.PACKAGE_NAME, packageName);
- protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, userId + 1);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.USER_ID, userId + 1);
protoOutputStream.end(token);
}
}
@@ -426,28 +387,23 @@ public class BackgroundInstallControlService extends SystemService {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token =
- protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token = protoInputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName =
- protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName = protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId =
- protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID)
- - 1;
+ userId = protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID) - 1;
break;
default:
- Slog.w(
- TAG,
- "Undefined field in proto: "
- + protoInputStream.getFieldNumber());
+ Slog.w(TAG, "Undefined field in proto: "
+ + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -476,12 +432,9 @@ public class BackgroundInstallControlService extends SystemService {
if (mInstallerForegroundTimeFrames.contains(userId, pkgName)) {
return true;
}
- return mPermissionManager.checkPermission(
- pkgName,
- android.Manifest.permission.INSTALL_PACKAGES,
- Context.DEVICE_ID_DEFAULT,
- userId)
- == PERMISSION_GRANTED;
+ return mPermissionManager.checkPermission(pkgName,
+ android.Manifest.permission.INSTALL_PACKAGES, Context.DEVICE_ID_DEFAULT,
+ userId) == PackageManager.PERMISSION_GRANTED;
}
@Override
@@ -495,22 +448,21 @@ public class BackgroundInstallControlService extends SystemService {
publishBinderService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE, mBinderService);
}
- mPackageManagerInternal.getPackageList(
- new PackageManagerInternal.PackageListObserver() {
- @Override
- public void onPackageAdded(String packageName, int uid) {
- final int userId = UserHandle.getUserId(uid);
- mHandler.obtainMessage(MSG_PACKAGE_ADDED, userId, 0, packageName)
- .sendToTarget();
- }
+ mPackageManagerInternal.getPackageList(new PackageManagerInternal.PackageListObserver() {
+ @Override
+ public void onPackageAdded(String packageName, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ mHandler.obtainMessage(MSG_PACKAGE_ADDED,
+ userId, 0, packageName).sendToTarget();
+ }
- @Override
- public void onPackageRemoved(String packageName, int uid) {
- final int userId = UserHandle.getUserId(uid);
- mHandler.obtainMessage(MSG_PACKAGE_REMOVED, userId, 0, packageName)
- .sendToTarget();
- }
- });
+ @Override
+ public void onPackageRemoved(String packageName, int uid) {
+ final int userId = UserHandle.getUserId(uid);
+ mHandler.obtainMessage(MSG_PACKAGE_REMOVED,
+ userId, 0, packageName).sendToTarget();
+ }
+ });
}
// The foreground time frame (ForegroundTimeFrame) represents the period
@@ -566,7 +518,7 @@ public class BackgroundInstallControlService extends SystemService {
}
/**
- * Dependency injector for {@link BackgroundInstallControlService}.
+ * Dependency injector for {@link #BackgroundInstallControlService)}.
*/
interface Injector {
Context getContext();
@@ -582,8 +534,6 @@ public class BackgroundInstallControlService extends SystemService {
Looper getLooper();
File getDiskFile();
-
- BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper();
}
private static final class InjectorImpl implements Injector {
@@ -620,11 +570,11 @@ public class BackgroundInstallControlService extends SystemService {
@Override
public Looper getLooper() {
- ServiceThread serviceThread =
- new ServiceThread(
- TAG, android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
+ ServiceThread serviceThread = new ServiceThread(TAG,
+ android.os.Process.THREAD_PRIORITY_FOREGROUND, true /* allowIo */);
serviceThread.start();
return serviceThread.getLooper();
+
}
@Override
@@ -633,10 +583,5 @@ public class BackgroundInstallControlService extends SystemService {
File file = new File(dir, DISK_FILE_NAME);
return file;
}
-
- @Override
- public BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper() {
- return new BackgroundInstallControlCallbackHelper();
- }
}
}
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 127bf495d2ac..991555495ad2 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -1610,21 +1610,117 @@ public class LauncherAppsService extends SystemService {
"Can't access AppMarketActivity for another user")) {
return null;
}
+ final int callingUser = getCallingUserId();
final long identity = Binder.clearCallingIdentity();
+
try {
- // TODO(b/316118005): Add code to launch the app installer for the packageName.
- Intent appMarketIntent = new Intent(Intent.ACTION_MAIN);
- appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET);
- final PendingIntent pi = PendingIntent.getActivityAsUser(
- mContext, /* requestCode */ 0, appMarketIntent, PendingIntent.FLAG_ONE_SHOT
- | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
- /* options */ null, user);
- return pi == null ? null : pi.getIntentSender();
+ if (packageName == null) {
+ return buildAppMarketIntentSenderForUser(user);
+ }
+
+ String installerPackageName = getInstallerPackage(packageName, callingUser);
+ if (installerPackageName == null
+ || mPackageManagerInternal.getPackageUid(
+ installerPackageName, /* flags= */ 0, user.getIdentifier())
+ < 0) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Can't find installer for "
+ + packageName
+ + " in user: "
+ + user.getIdentifier());
+ }
+ return buildAppMarketIntentSenderForUser(user);
+ }
+
+ Intent packageInfoIntent =
+ buildMarketPackageInfoIntent(
+ packageName, installerPackageName, callingPackage);
+ if (mPackageManagerInternal
+ .queryIntentActivities(
+ packageInfoIntent,
+ packageInfoIntent.resolveTypeIfNeeded(
+ mContext.getContentResolver()),
+ PackageManager.MATCH_ALL,
+ Process.myUid(),
+ user.getIdentifier())
+ .isEmpty()) {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Can't resolve package info intent for package "
+ + packageName
+ + " and installer: "
+ + installerPackageName);
+ }
+ return buildAppMarketIntentSenderForUser(user);
+ }
+
+ return buildIntentSenderForUser(packageInfoIntent, user);
} finally {
Binder.restoreCallingIdentity(identity);
}
}
+ @Nullable
+ private IntentSender buildAppMarketIntentSenderForUser(@NonNull UserHandle user) {
+ Intent appMarketIntent = new Intent(Intent.ACTION_MAIN);
+ appMarketIntent.addCategory(Intent.CATEGORY_APP_MARKET);
+ return buildIntentSenderForUser(appMarketIntent, user);
+ }
+
+ @Nullable
+ private IntentSender buildIntentSenderForUser(
+ @NonNull Intent intent, @NonNull UserHandle user) {
+ final PendingIntent pi =
+ PendingIntent.getActivityAsUser(
+ mContext,
+ /* requestCode */ 0,
+ intent,
+ PendingIntent.FLAG_ONE_SHOT
+ | PendingIntent.FLAG_IMMUTABLE
+ | PendingIntent.FLAG_CANCEL_CURRENT,
+ /* options */ null,
+ user);
+ return pi == null ? null : pi.getIntentSender();
+ }
+
+ @Nullable
+ private String getInstallerPackage(@NonNull String packageName, int callingUserId) {
+ String installerPackageName = null;
+ try {
+ installerPackageName =
+ mIPM.getInstallSourceInfo(packageName, callingUserId)
+ .getInstallingPackageName();
+ } catch (RemoteException re) {
+ Slog.e(TAG, "Couldn't find installer for " + packageName, re);
+ }
+
+ return installerPackageName;
+ }
+
+ @NonNull
+ private Intent buildMarketPackageInfoIntent(
+ @NonNull String packageName,
+ @NonNull String installerPackageName,
+ @NonNull String callingPackage) {
+ return new Intent(Intent.ACTION_VIEW)
+ .setData(
+ new Uri.Builder()
+ .scheme("market")
+ .authority("details")
+ .appendQueryParameter("id", packageName)
+ .build())
+ .putExtra(
+ Intent.EXTRA_REFERRER,
+ new Uri.Builder()
+ .scheme("android-app")
+ .authority(callingPackage)
+ .build())
+ .setPackage(installerPackageName);
+ }
+
@Override
public void startActivityAsUser(IApplicationThread caller, String callingPackage,
String callingFeatureId, ComponentName component, Rect sourceBounds,
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 3adeb4b5925f..446c6293aa35 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -77,6 +77,7 @@ import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBinder;
import android.os.LocaleList;
import android.os.Looper;
@@ -113,7 +114,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
-import com.android.internal.os.BackgroundThread;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.Preconditions;
@@ -485,7 +485,14 @@ public class ShortcutService extends IShortcutService.Stub {
}
public ShortcutService(Context context) {
- this(context, BackgroundThread.get().getLooper(), /*onyForPackgeManagerApis*/ false);
+ this(context, getBgLooper(), /*onyForPackgeManagerApis*/ false);
+ }
+
+ private static Looper getBgLooper() {
+ final HandlerThread handlerThread = new HandlerThread("shortcut",
+ android.os.Process.THREAD_PRIORITY_BACKGROUND);
+ handlerThread.start();
+ return handlerThread.getLooper();
}
@VisibleForTesting
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index c0e33084f9c4..b384725711c4 100755
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -60,6 +60,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Surface;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -88,15 +89,25 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private final Context mContext;
private final Listener mListener;
private final TvInputHal mHal = new TvInputHal(this);
+
+ private final Object mLock = new Object();
+
+ @GuardedBy("mLock")
private final SparseArray<Connection> mConnections = new SparseArray<>();
+ @GuardedBy("mLock")
private final List<TvInputHardwareInfo> mHardwareList = new ArrayList<>();
+ @GuardedBy("mLock")
private final List<HdmiDeviceInfo> mHdmiDeviceList = new ArrayList<>();
/* A map from a device ID to the matching TV input ID. */
+ @GuardedBy("mLock")
private final SparseArray<String> mHardwareInputIdMap = new SparseArray<>();
/* A map from a HDMI logical address to the matching TV input ID. */
+ @GuardedBy("mLock")
private final SparseArray<String> mHdmiInputIdMap = new SparseArray<>();
+ @GuardedBy("mLock")
private final Map<String, TvInputInfo> mInputMap = new ArrayMap<>();
/* A map from a HDMI input parent ID to the related input IDs. */
+ @GuardedBy("mLock")
private final Map<String, List<String>> mHdmiParentInputMap = new ArrayMap<>();
private final AudioManager mAudioManager;
@@ -114,16 +125,16 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private int mCurrentIndex = 0;
private int mCurrentMaxIndex = 0;
+ @GuardedBy("mLock")
private final SparseBooleanArray mHdmiStateMap = new SparseBooleanArray();
+ @GuardedBy("mLock")
private final List<Message> mPendingHdmiDeviceEvents = new ArrayList<>();
-
+ @GuardedBy("mLock")
private final List<Message> mPendingTvinputInfoEvents = new ArrayList<>();
// Calls to mListener should happen here.
private final Handler mHandler = new ListenerHandler();
- private final Object mLock = new Object();
-
public TvInputHardwareManager(Context context, Listener listener) {
mContext = context;
mListener = listener;
@@ -141,7 +152,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
hdmiControlService.addDeviceEventListener(mHdmiDeviceEventListener);
hdmiControlService.addSystemAudioModeChangeListener(
mHdmiSystemAudioModeChangeListener);
- mHdmiDeviceList.addAll(hdmiControlService.getInputDevices());
+ synchronized (mLock) {
+ mHdmiDeviceList.addAll(hdmiControlService.getInputDevices());
+ }
} catch (RemoteException e) {
Slog.w(TAG, "Error registering listeners to HdmiControlService:", e);
}
@@ -172,6 +185,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
+ @GuardedBy("mLock")
private void buildHardwareListLocked() {
mHardwareList.clear();
for (int i = 0; i < mConnections.size(); ++i) {
@@ -301,6 +315,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
+ @GuardedBy("mLock")
private boolean checkUidChangedLocked(
Connection connection, int callingUid, int resolvedUserId) {
Integer connectionCallingUid = connection.getCallingUidLocked();
@@ -496,6 +511,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
+ @GuardedBy("mLock")
private TvInputHardwareInfo findHardwareInfoForHdmiPortLocked(int port) {
for (TvInputHardwareInfo hardwareInfo : mHardwareList) {
if (hardwareInfo.getType() == TvInputHardwareInfo.TV_INPUT_TYPE_HDMI
@@ -506,6 +522,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return null;
}
+ @GuardedBy("mLock")
private int findDeviceIdForInputIdLocked(String inputId) {
for (int i = 0; i < mConnections.size(); ++i) {
int key = mConnections.keyAt(i);
@@ -597,6 +614,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return false;
}
+ @GuardedBy("mLock")
private void processPendingHdmiDeviceEventsLocked() {
for (Iterator<Message> it = mPendingHdmiDeviceEvents.iterator(); it.hasNext(); ) {
Message msg = it.next();
@@ -611,6 +629,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
+ @GuardedBy("mLock")
private void processPendingTvInputInfoEventsLocked() {
for (Iterator<Message> it = mPendingTvinputInfoEvents.iterator(); it.hasNext(); ) {
Message msg = it.next();
@@ -748,6 +767,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
// *Locked methods assume TvInputHardwareManager.mLock is held.
+ @GuardedBy("mLock")
public void resetLocked(TvInputHardwareImpl hardware, ITvInputHardwareCallback callback,
TvInputInfo info, Integer callingUid, Integer resolvedUserId,
ResourceClientProfile profile) {
@@ -776,50 +796,62 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
+ @GuardedBy("mLock")
public void updateConfigsLocked(TvStreamConfig[] configs) {
mConfigs = configs;
}
+ @GuardedBy("mLock")
public TvInputHardwareInfo getHardwareInfoLocked() {
return mHardwareInfo;
}
+ @GuardedBy("mLock")
public TvInputInfo getInfoLocked() {
return mInfo;
}
+ @GuardedBy("mLock")
public ITvInputHardware getHardwareLocked() {
return mHardware;
}
+ @GuardedBy("mLock")
public TvInputHardwareImpl getHardwareImplLocked() {
return mHardware;
}
+ @GuardedBy("mLock")
public ITvInputHardwareCallback getCallbackLocked() {
return mCallback;
}
+ @GuardedBy("mLock")
public TvStreamConfig[] getConfigsLocked() {
return mConfigs;
}
+ @GuardedBy("mLock")
public Integer getCallingUidLocked() {
return mCallingUid;
}
+ @GuardedBy("mLock")
public Integer getResolvedUserIdLocked() {
return mResolvedUserId;
}
+ @GuardedBy("mLock")
public void setOnFirstFrameCapturedLocked(Runnable runnable) {
mOnFirstFrameCaptured = runnable;
}
+ @GuardedBy("mLock")
public Runnable getOnFirstFrameCapturedLocked() {
return mOnFirstFrameCaptured;
}
+ @GuardedBy("mLock")
public ResourceClientProfile getResourceClientProfileLocked() {
return mResourceClientProfile;
}
@@ -844,6 +876,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
+ " }";
}
+ @GuardedBy("mLock")
public boolean updateCableConnectionStatusLocked(int cableConnectionStatus) {
// Update connection status only if it's not default value
if (cableConnectionStatus != TvInputHardwareInfo.CABLE_CONNECTION_STATUS_UNKNOWN
@@ -855,10 +888,12 @@ class TvInputHardwareManager implements TvInputHal.Callback {
return mIsCableConnectionStatusUpdated;
}
+ @GuardedBy("mLock")
private int getConfigsLengthLocked() {
return mConfigs == null ? 0 : mConfigs.length;
}
+ @GuardedBy("mLock")
private int getInputStateLocked() {
int configsLength = getConfigsLengthLocked();
if (configsLength > 0) {
@@ -880,7 +915,6 @@ class TvInputHardwareManager implements TvInputHal.Callback {
private class TvInputHardwareImpl extends ITvInputHardware.Stub {
private final TvInputHardwareInfo mInfo;
- private boolean mReleased = false;
private final Object mImplLock = new Object();
private final AudioManager.OnAudioPortUpdateListener mAudioListener =
@@ -909,28 +943,44 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
};
+ @GuardedBy("mImplLock")
+ private boolean mReleased = false;
+ @GuardedBy("mImplLock")
private int mOverrideAudioType = AudioManager.DEVICE_NONE;
+ @GuardedBy("mImplLock")
private String mOverrideAudioAddress = "";
+ @GuardedBy("mImplLock")
private AudioDevicePort mAudioSource;
+ @GuardedBy("mImplLock")
private List<AudioDevicePort> mAudioSink = new ArrayList<>();
+ @GuardedBy("mImplLock")
private AudioPatch mAudioPatch = null;
// Set to an invalid value for a volume, so that current volume can be applied at the
// first call to updateAudioConfigLocked().
+ @GuardedBy("mImplLock")
private float mCommittedVolume = -1f;
+ @GuardedBy("mImplLock")
private float mSourceVolume = 0.0f;
+ @GuardedBy("mImplLock")
private TvStreamConfig mActiveConfig = null;
+ @GuardedBy("mImplLock")
private int mDesiredSamplingRate = 0;
+ @GuardedBy("mImplLock")
private int mDesiredChannelMask = AudioFormat.CHANNEL_OUT_DEFAULT;
+ @GuardedBy("mImplLock")
private int mDesiredFormat = AudioFormat.ENCODING_DEFAULT;
public TvInputHardwareImpl(TvInputHardwareInfo info) {
mInfo = info;
mAudioManager.registerAudioPortUpdateListener(mAudioListener);
if (mInfo.getAudioType() != AudioManager.DEVICE_NONE) {
- mAudioSource = findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress());
- findAudioSinkFromAudioPolicy(mAudioSink);
+ synchronized (mImplLock) {
+ mAudioSource =
+ findAudioDevicePort(mInfo.getAudioType(), mInfo.getAudioAddress());
+ findAudioSinkFromAudioPolicy(mAudioSink);
+ }
}
}
@@ -1025,6 +1075,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
/**
* Update audio configuration (source, sink, patch) all up to current state.
*/
+ @GuardedBy("mImplLock")
private void updateAudioConfigLocked() {
boolean sinkUpdated = updateAudioSinkLocked();
boolean sourceUpdated = updateAudioSourceLocked();
@@ -1204,6 +1255,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
}
}
+ @GuardedBy("mImplLock")
private boolean updateAudioSourceLocked() {
if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) {
return false;
@@ -1214,6 +1266,7 @@ class TvInputHardwareManager implements TvInputHal.Callback {
: !mAudioSource.equals(previousSource);
}
+ @GuardedBy("mImplLock")
private boolean updateAudioSinkLocked() {
if (mInfo.getAudioType() == AudioManager.DEVICE_NONE) {
return false;
diff --git a/services/core/java/com/android/server/vcn/VcnContext.java b/services/core/java/com/android/server/vcn/VcnContext.java
index 6ce868540070..ed04e5fde024 100644
--- a/services/core/java/com/android/server/vcn/VcnContext.java
+++ b/services/core/java/com/android/server/vcn/VcnContext.java
@@ -34,6 +34,7 @@ public class VcnContext {
@NonNull private final Looper mLooper;
@NonNull private final VcnNetworkProvider mVcnNetworkProvider;
@NonNull private final FeatureFlags mFeatureFlags;
+ @NonNull private final com.android.net.flags.FeatureFlags mCoreNetFeatureFlags;
private final boolean mIsInTestMode;
public VcnContext(
@@ -48,6 +49,7 @@ public class VcnContext {
// Auto-generated class
mFeatureFlags = new FeatureFlagsImpl();
+ mCoreNetFeatureFlags = new com.android.net.flags.FeatureFlagsImpl();
}
@NonNull
@@ -69,6 +71,14 @@ public class VcnContext {
return mIsInTestMode;
}
+ public boolean isFlagNetworkMetricMonitorEnabled() {
+ return mFeatureFlags.networkMetricMonitor();
+ }
+
+ public boolean isFlagIpSecTransformStateEnabled() {
+ return mCoreNetFeatureFlags.ipsecTransformState();
+ }
+
@NonNull
public FeatureFlags getFeatureFlags() {
return mFeatureFlags;
diff --git a/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
new file mode 100644
index 000000000000..5f4852f77727
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/routeselection/IpSecPacketLossDetector.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn.routeselection;
+
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.IpSecTransformState;
+import android.net.Network;
+import android.net.vcn.VcnManager;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.OutcomeReceiver;
+import android.os.PowerManager;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.VcnContext;
+
+import java.util.BitSet;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * IpSecPacketLossDetector is responsible for continuously monitoring IPsec packet loss
+ *
+ * <p>When the packet loss rate surpass the threshold, IpSecPacketLossDetector will report it to the
+ * caller
+ *
+ * <p>IpSecPacketLossDetector will start monitoring when the network being monitored is selected AND
+ * an inbound IpSecTransform has been applied to this network.
+ *
+ * <p>This class is flag gated by "network_metric_monitor" and "ipsec_tramsform_state"
+ */
+public class IpSecPacketLossDetector extends NetworkMetricMonitor {
+ private static final String TAG = IpSecPacketLossDetector.class.getSimpleName();
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ static final int PACKET_LOSS_UNAVALAIBLE = -1;
+
+ // For VoIP, losses between 5% and 10% of the total packet stream will affect the quality
+ // significantly (as per "Computer Networking for LANS to WANS: Hardware, Software and
+ // Security"). For audio and video streaming, above 10-12% packet loss is unacceptable (as per
+ // "ICTP-SDU: About PingER"). Thus choose 12% as a conservative default threshold to declare a
+ // validation failure.
+ private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT = 12;
+
+ private static final int POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT = 20;
+
+ private long mPollIpSecStateIntervalMs;
+ private final int mPacketLossRatePercentThreshold;
+
+ @NonNull private final Handler mHandler;
+ @NonNull private final PowerManager mPowerManager;
+ @NonNull private final Object mCancellationToken = new Object();
+ @NonNull private final PacketLossCalculator mPacketLossCalculator;
+
+ @Nullable private IpSecTransformWrapper mInboundTransform;
+ @Nullable private IpSecTransformState mLastIpSecTransformState;
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public IpSecPacketLossDetector(
+ @NonNull VcnContext vcnContext,
+ @NonNull Network network,
+ @Nullable PersistableBundleWrapper carrierConfig,
+ @NonNull NetworkMetricMonitorCallback callback,
+ @NonNull Dependencies deps)
+ throws IllegalAccessException {
+ super(vcnContext, network, carrierConfig, callback);
+
+ Objects.requireNonNull(deps, "Missing deps");
+
+ if (!vcnContext.isFlagIpSecTransformStateEnabled()) {
+ // Caller error
+ logWtf("ipsecTransformState flag disabled");
+ throw new IllegalAccessException("ipsecTransformState flag disabled");
+ }
+
+ mHandler = new Handler(getVcnContext().getLooper());
+
+ mPowerManager = getVcnContext().getContext().getSystemService(PowerManager.class);
+
+ mPacketLossCalculator = deps.getPacketLossCalculator();
+
+ mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig);
+ mPacketLossRatePercentThreshold = getPacketLossRatePercentThreshold(carrierConfig);
+
+ // Register for system broadcasts to monitor idle mode change
+ final IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ getVcnContext()
+ .getContext()
+ .registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(
+ intent.getAction())
+ && mPowerManager.isDeviceIdleMode()) {
+ mLastIpSecTransformState = null;
+ }
+ }
+ },
+ intentFilter,
+ null /* broadcastPermission not required */,
+ mHandler);
+ }
+
+ public IpSecPacketLossDetector(
+ @NonNull VcnContext vcnContext,
+ @NonNull Network network,
+ @Nullable PersistableBundleWrapper carrierConfig,
+ @NonNull NetworkMetricMonitorCallback callback)
+ throws IllegalAccessException {
+ this(vcnContext, network, carrierConfig, callback, new Dependencies());
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class Dependencies {
+ public PacketLossCalculator getPacketLossCalculator() {
+ return new PacketLossCalculator();
+ }
+ }
+
+ private static long getPollIpSecStateIntervalMs(
+ @Nullable PersistableBundleWrapper carrierConfig) {
+ final int seconds;
+
+ if (carrierConfig != null) {
+ seconds =
+ carrierConfig.getInt(
+ VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY,
+ POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT);
+ } else {
+ seconds = POLL_IPSEC_STATE_INTERVAL_SECONDS_DEFAULT;
+ }
+
+ return TimeUnit.SECONDS.toMillis(seconds);
+ }
+
+ private static int getPacketLossRatePercentThreshold(
+ @Nullable PersistableBundleWrapper carrierConfig) {
+ if (carrierConfig != null) {
+ return carrierConfig.getInt(
+ VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY,
+ IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT);
+ }
+ return IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_DEFAULT;
+ }
+
+ @Override
+ protected void onSelectedUnderlyingNetworkChanged() {
+ if (!isSelectedUnderlyingNetwork()) {
+ mInboundTransform = null;
+ stop();
+ }
+
+ // No action when the underlying network got selected. Wait for the inbound transform to
+ // start the monitor
+ }
+
+ @Override
+ public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inboundTransform) {
+ Objects.requireNonNull(inboundTransform, "inboundTransform is null");
+
+ if (Objects.equals(inboundTransform, mInboundTransform)) {
+ return;
+ }
+
+ if (!isSelectedUnderlyingNetwork()) {
+ logWtf("setInboundTransform called but network not selected");
+ return;
+ }
+
+ // When multiple parallel inbound transforms are created, NetworkMetricMonitor will be
+ // enabled on the last one as a sample
+ mInboundTransform = inboundTransform;
+ start();
+ }
+
+ @Override
+ public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) {
+ // The already scheduled event will not be affected. The followup events will be scheduled
+ // with the new interval
+ mPollIpSecStateIntervalMs = getPollIpSecStateIntervalMs(carrierConfig);
+ }
+
+ @Override
+ protected void start() {
+ super.start();
+ clearTransformStateAndPollingEvents();
+ mHandler.postDelayed(new PollIpSecStateRunnable(), mCancellationToken, 0L);
+ }
+
+ @Override
+ public void stop() {
+ super.stop();
+ clearTransformStateAndPollingEvents();
+ }
+
+ private void clearTransformStateAndPollingEvents() {
+ mHandler.removeCallbacksAndEqualMessages(mCancellationToken);
+ mLastIpSecTransformState = null;
+ }
+
+ @Override
+ public void close() {
+ super.close();
+
+ if (mInboundTransform != null) {
+ mInboundTransform.close();
+ }
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ @Nullable
+ public IpSecTransformState getLastTransformState() {
+ return mLastIpSecTransformState;
+ }
+
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ @Nullable
+ public IpSecTransformWrapper getInboundTransformInternal() {
+ return mInboundTransform;
+ }
+
+ private class PollIpSecStateRunnable implements Runnable {
+ @Override
+ public void run() {
+ if (!isStarted()) {
+ logWtf("Monitor stopped but PollIpSecStateRunnable not removed from Handler");
+ return;
+ }
+
+ getInboundTransformInternal()
+ .getIpSecTransformState(
+ new HandlerExecutor(mHandler), new IpSecTransformStateReceiver());
+
+ // Schedule for next poll
+ mHandler.postDelayed(
+ new PollIpSecStateRunnable(), mCancellationToken, mPollIpSecStateIntervalMs);
+ }
+ }
+
+ private class IpSecTransformStateReceiver
+ implements OutcomeReceiver<IpSecTransformState, RuntimeException> {
+ @Override
+ public void onResult(@NonNull IpSecTransformState state) {
+ getVcnContext().ensureRunningOnLooperThread();
+
+ if (!isStarted()) {
+ return;
+ }
+
+ onIpSecTransformStateReceived(state);
+ }
+
+ @Override
+ public void onError(@NonNull RuntimeException error) {
+ getVcnContext().ensureRunningOnLooperThread();
+
+ // Nothing we can do here
+ logW("TransformStateReceiver#onError " + error.toString());
+ }
+ }
+
+ private void onIpSecTransformStateReceived(@NonNull IpSecTransformState state) {
+ if (mLastIpSecTransformState == null) {
+ // This is first time to poll the state
+ mLastIpSecTransformState = state;
+ return;
+ }
+
+ final int packetLossRate =
+ mPacketLossCalculator.getPacketLossRatePercentage(
+ mLastIpSecTransformState, state, getLogPrefix());
+
+ if (packetLossRate == PACKET_LOSS_UNAVALAIBLE) {
+ return;
+ }
+
+ final String logMsg =
+ "packetLossRate: "
+ + packetLossRate
+ + "% in the past "
+ + (state.getTimestamp() - mLastIpSecTransformState.getTimestamp())
+ + "ms";
+
+ mLastIpSecTransformState = state;
+ if (packetLossRate < mPacketLossRatePercentThreshold) {
+ logV(logMsg);
+ onValidationResultReceivedInternal(false /* isFailed */);
+ } else {
+ logInfo(logMsg);
+ onValidationResultReceivedInternal(true /* isFailed */);
+ }
+ }
+
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public static class PacketLossCalculator {
+ /** Calculate the packet loss rate between two timestamps */
+ public int getPacketLossRatePercentage(
+ @NonNull IpSecTransformState oldState,
+ @NonNull IpSecTransformState newState,
+ String logPrefix) {
+ logVIpSecTransform("oldState", oldState, logPrefix);
+ logVIpSecTransform("newState", newState, logPrefix);
+
+ final int replayWindowSize = oldState.getReplayBitmap().length * 8;
+ final long oldSeqHi = oldState.getRxHighestSequenceNumber();
+ final long oldSeqLow = Math.max(0L, oldSeqHi - replayWindowSize + 1);
+ final long newSeqHi = newState.getRxHighestSequenceNumber();
+ final long newSeqLow = Math.max(0L, newSeqHi - replayWindowSize + 1);
+
+ if (oldSeqHi == newSeqHi || newSeqHi < replayWindowSize) {
+ // The replay window did not proceed and all packets might have been delivered out
+ // of order
+ return PACKET_LOSS_UNAVALAIBLE;
+ }
+
+ // Get the expected packet count by assuming there is no packet loss. In this case, SA
+ // should receive all packets whose sequence numbers are smaller than the lower bound of
+ // the replay window AND the packets received within the window.
+ // When the lower bound is 0, it's not possible to tell whether packet with seqNo 0 is
+ // received or not. For simplicity just assume that packet is received.
+ final long newExpectedPktCnt = newSeqLow + getPacketCntInReplayWindow(newState);
+ final long oldExpectedPktCnt = oldSeqLow + getPacketCntInReplayWindow(oldState);
+
+ final long expectedPktCntDiff = newExpectedPktCnt - oldExpectedPktCnt;
+ final long actualPktCntDiff = newState.getPacketCount() - oldState.getPacketCount();
+
+ logV(
+ TAG,
+ logPrefix
+ + " expectedPktCntDiff: "
+ + expectedPktCntDiff
+ + " actualPktCntDiff: "
+ + actualPktCntDiff);
+
+ if (expectedPktCntDiff < 0
+ || expectedPktCntDiff == 0
+ || actualPktCntDiff < 0
+ || actualPktCntDiff > expectedPktCntDiff) {
+ logWtf(TAG, "Impossible values for expectedPktCntDiff or" + " actualPktCntDiff");
+ return PACKET_LOSS_UNAVALAIBLE;
+ }
+
+ return 100 - (int) (actualPktCntDiff * 100 / expectedPktCntDiff);
+ }
+ }
+
+ private static void logVIpSecTransform(
+ String transformTag, IpSecTransformState state, String logPrefix) {
+ final String stateString =
+ " seqNo: "
+ + state.getRxHighestSequenceNumber()
+ + " | pktCnt: "
+ + state.getPacketCount()
+ + " | pktCntInWindow: "
+ + getPacketCntInReplayWindow(state);
+ logV(TAG, logPrefix + " " + transformTag + stateString);
+ }
+
+ /** Get the number of received packets within the replay window */
+ private static long getPacketCntInReplayWindow(@NonNull IpSecTransformState state) {
+ return BitSet.valueOf(state.getReplayBitmap()).cardinality();
+ }
+}
diff --git a/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
new file mode 100644
index 000000000000..a79f188713e1
--- /dev/null
+++ b/services/core/java/com/android/server/vcn/routeselection/NetworkMetricMonitor.java
@@ -0,0 +1,269 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn.routeselection;
+
+import static com.android.server.VcnManagementService.LOCAL_LOG;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.IpSecTransform;
+import android.net.IpSecTransformState;
+import android.net.Network;
+import android.os.OutcomeReceiver;
+import android.util.CloseGuard;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.annotations.VisibleForTesting.Visibility;
+import com.android.server.vcn.VcnContext;
+
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * NetworkMetricMonitor is responsible for managing metric monitoring and tracking validation
+ * results.
+ *
+ * <p>This class is flag gated by "network_metric_monitor"
+ */
+public abstract class NetworkMetricMonitor implements AutoCloseable {
+ private static final String TAG = NetworkMetricMonitor.class.getSimpleName();
+
+ private static final boolean VDBG = false; // STOPSHIP: if true
+
+ @NonNull private final CloseGuard mCloseGuard = new CloseGuard();
+
+ @NonNull private final VcnContext mVcnContext;
+ @NonNull private final Network mNetwork;
+ @NonNull private final NetworkMetricMonitorCallback mCallback;
+
+ private boolean mIsSelectedUnderlyingNetwork;
+ private boolean mIsStarted;
+ private boolean mIsValidationFailed;
+
+ protected NetworkMetricMonitor(
+ @NonNull VcnContext vcnContext,
+ @NonNull Network network,
+ @Nullable PersistableBundleWrapper carrierConfig,
+ @NonNull NetworkMetricMonitorCallback callback)
+ throws IllegalAccessException {
+ if (!vcnContext.isFlagNetworkMetricMonitorEnabled()) {
+ // Caller error
+ logWtf("networkMetricMonitor flag disabled");
+ throw new IllegalAccessException("networkMetricMonitor flag disabled");
+ }
+
+ mVcnContext = Objects.requireNonNull(vcnContext, "Missing vcnContext");
+ mNetwork = Objects.requireNonNull(network, "Missing network");
+ mCallback = Objects.requireNonNull(callback, "Missing callback");
+
+ mIsSelectedUnderlyingNetwork = false;
+ mIsStarted = false;
+ mIsValidationFailed = false;
+ }
+
+ /** Callback to notify caller of the validation result */
+ public interface NetworkMetricMonitorCallback {
+ /** Called when there is a validation result is ready */
+ void onValidationResultReceived();
+ }
+
+ /**
+ * Start monitoring
+ *
+ * <p>This method might be called on a an already started monitor for updating monitor
+ * properties (e.g. IpSecTransform, carrier config)
+ *
+ * <p>Subclasses MUST call super.start() when overriding this method
+ */
+ protected void start() {
+ mIsStarted = true;
+ }
+
+ /**
+ * Stop monitoring
+ *
+ * <p>Subclasses MUST call super.stop() when overriding this method
+ */
+ public void stop() {
+ mIsValidationFailed = false;
+ mIsStarted = false;
+ }
+
+ /** Called by the subclasses when the validation result is ready */
+ protected void onValidationResultReceivedInternal(boolean isFailed) {
+ mIsValidationFailed = isFailed;
+ mCallback.onValidationResultReceived();
+ }
+
+ /** Called when the underlying network changes to selected or unselected */
+ protected abstract void onSelectedUnderlyingNetworkChanged();
+
+ /**
+ * Mark the network being monitored selected or unselected
+ *
+ * <p>Subclasses MUST call super when overriding this method
+ */
+ public void setIsSelectedUnderlyingNetwork(boolean isSelectedUnderlyingNetwork) {
+ if (mIsSelectedUnderlyingNetwork == isSelectedUnderlyingNetwork) {
+ return;
+ }
+
+ mIsSelectedUnderlyingNetwork = isSelectedUnderlyingNetwork;
+ onSelectedUnderlyingNetworkChanged();
+ }
+
+ /** Wrapper that allows injection for testing purposes */
+ @VisibleForTesting(visibility = Visibility.PROTECTED)
+ public static class IpSecTransformWrapper {
+ @NonNull public final IpSecTransform ipSecTransform;
+
+ public IpSecTransformWrapper(@NonNull IpSecTransform ipSecTransform) {
+ this.ipSecTransform = ipSecTransform;
+ }
+
+ /** Poll an IpSecTransformState */
+ public void getIpSecTransformState(
+ @NonNull Executor executor,
+ @NonNull OutcomeReceiver<IpSecTransformState, RuntimeException> callback) {
+ ipSecTransform.getIpSecTransformState(executor, callback);
+ }
+
+ /** Close this instance and release the underlying resources */
+ public void close() {
+ ipSecTransform.close();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(ipSecTransform);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof IpSecTransformWrapper)) {
+ return false;
+ }
+
+ final IpSecTransformWrapper other = (IpSecTransformWrapper) o;
+
+ return Objects.equals(ipSecTransform, other.ipSecTransform);
+ }
+ }
+
+ /** Set the IpSecTransform that applied to the Network being monitored */
+ public void setInboundTransform(@NonNull IpSecTransform inTransform) {
+ setInboundTransformInternal(new IpSecTransformWrapper(inTransform));
+ }
+
+ /**
+ * Set the IpSecTransform that applied to the Network being monitored *
+ *
+ * <p>Subclasses MUST call super when overriding this method
+ */
+ @VisibleForTesting(visibility = Visibility.PRIVATE)
+ public void setInboundTransformInternal(@NonNull IpSecTransformWrapper inTransform) {
+ // Subclasses MUST override it if they care
+ }
+
+ /** Update the carrierconfig */
+ public void setCarrierConfig(@Nullable PersistableBundleWrapper carrierConfig) {
+ // Subclasses MUST override it if they care
+ }
+
+ public boolean isValidationFailed() {
+ return mIsValidationFailed;
+ }
+
+ public boolean isSelectedUnderlyingNetwork() {
+ return mIsSelectedUnderlyingNetwork;
+ }
+
+ public boolean isStarted() {
+ return mIsStarted;
+ }
+
+ @NonNull
+ public VcnContext getVcnContext() {
+ return mVcnContext;
+ }
+
+ // Override methods for AutoCloseable. Subclasses MUST call super when overriding this method
+ @Override
+ public void close() {
+ mCloseGuard.close();
+
+ stop();
+ }
+
+ // Override #finalize() to use closeGuard for flagging that #close() was not called
+ @SuppressWarnings("Finalize")
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private String getClassName() {
+ return this.getClass().getSimpleName();
+ }
+
+ protected String getLogPrefix() {
+ return " [Network " + mNetwork + "] ";
+ }
+
+ protected void logV(String msg) {
+ if (VDBG) {
+ Slog.v(getClassName(), getLogPrefix() + msg);
+ LOCAL_LOG.log("[VERBOSE ] " + getClassName() + getLogPrefix() + msg);
+ }
+ }
+
+ protected void logInfo(String msg) {
+ Slog.i(getClassName(), getLogPrefix() + msg);
+ LOCAL_LOG.log("[INFO ] " + getClassName() + getLogPrefix() + msg);
+ }
+
+ protected void logW(String msg) {
+ Slog.w(getClassName(), getLogPrefix() + msg);
+ LOCAL_LOG.log("[WARN ] " + getClassName() + getLogPrefix() + msg);
+ }
+
+ protected void logWtf(String msg) {
+ Slog.wtf(getClassName(), getLogPrefix() + msg);
+ LOCAL_LOG.log("[WTF ] " + getClassName() + getLogPrefix() + msg);
+ }
+
+ protected static void logV(String className, String msgWithPrefix) {
+ if (VDBG) {
+ Slog.wtf(className, msgWithPrefix);
+ LOCAL_LOG.log("[VERBOSE ] " + className + msgWithPrefix);
+ }
+ }
+
+ protected static void logWtf(String className, String msgWithPrefix) {
+ Slog.wtf(className, msgWithPrefix);
+ LOCAL_LOG.log("[WTF ] " + className + msgWithPrefix);
+ }
+}
diff --git a/services/core/java/com/android/server/wearable/OWNERS b/services/core/java/com/android/server/wearable/OWNERS
index 073e2d79850b..eca48b742cef 100644
--- a/services/core/java/com/android/server/wearable/OWNERS
+++ b/services/core/java/com/android/server/wearable/OWNERS
@@ -1,3 +1 @@
-charliewang@google.com
-oni@google.com
-volnov@google.com \ No newline at end of file
+include /core/java/android/app/wearable/OWNERS \ No newline at end of file
diff --git a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
index cd48f5d527c1..106be5f124a0 100644
--- a/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
+++ b/services/core/java/com/android/server/wearable/WearableSensingManagerService.java
@@ -218,7 +218,7 @@ public class WearableSensingManagerService extends
PersistableBundle data,
SharedMemory sharedMemory,
RemoteCallback callback) {
- Slog.i(TAG, "WearableSensingManagerInternal provideData.");
+ Slog.d(TAG, "WearableSensingManagerInternal provideData.");
Objects.requireNonNull(data);
Objects.requireNonNull(callback);
mContext.enforceCallingOrSelfPermission(
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index b94206dd700a..8aaf76a165ab 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -1311,7 +1311,7 @@ class BackNavigationController {
Rect insets;
if (mainWindow != null) {
insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
- mBounds, WindowInsets.Type.systemBars(),
+ mBounds, WindowInsets.Type.tappableElement(),
false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
} else {
@@ -1596,7 +1596,9 @@ class BackNavigationController {
// skip commitVisibility call in setVisibility cause the activity won't visible here.
// Call it again to make sure the activity could be visible while handling the pending
// animation.
- activity.commitVisibility(true, true);
+ // Do not performLayout during prepare animation, because it could cause focus window
+ // change. Let that happen after the BackNavigationInfo has returned to shell.
+ activity.commitVisibility(true, false /* performLayout */);
activity.mTransitionController.mSnapshotController
.mActivitySnapshotController.addOnBackPressedActivity(activity);
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6033220e260d..02b3f15979ce 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -808,7 +808,6 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
mWmService.mAtmService.mTaskOrganizerController.dispatchPendingEvents();
mWmService.mAtmService.mTaskFragmentOrganizerController.dispatchPendingEvents();
mWmService.mSyncEngine.onSurfacePlacement();
- mWmService.mAnimator.executeAfterPrepareSurfacesRunnables();
checkAppTransitionReady(surfacePlacer);
diff --git a/services/core/lint-baseline.xml b/services/core/lint-baseline.xml
index 070bd4b1c5a9..2ccd1e4c00c7 100644
--- a/services/core/lint-baseline.xml
+++ b/services/core/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="5" by="lint 7.2.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NonUserGetterCalled"
@@ -145,4 +145,4 @@
line="7158"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
index 69a5e5c3a901..db985fd16749 100644
--- a/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/ClearRequestSession.java
@@ -50,7 +50,8 @@ public final class ClearRequestSession extends RequestSession<ClearCredentialSta
long startedTimestamp) {
super(context, sessionCallback, lock, userId, callingUid, request, callback,
RequestInfo.TYPE_UNDEFINED,
- callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp);
+ callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp,
+ /*shouldBindClientToDeath=*/ true);
}
/**
diff --git a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
index 31409ab1de4b..b24accbe3231 100644
--- a/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/CreateRequestSession.java
@@ -63,7 +63,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
long startedTimestamp) {
super(context, sessionCallback, lock, userId, callingUid, request, callback,
RequestInfo.TYPE_CREATE,
- callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp);
+ callingAppInfo, enabledProviders, cancellationSignal, startedTimestamp,
+ /*shouldBindClientToDeath=*/ true);
mRequestSessionMetric.collectCreateFlowInitialMetricInfo(
/*origin=*/request.getOrigin() != null, request);
mPrimaryProviders = primaryProviders;
diff --git a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
index 0f914c32346d..0187ce8140f5 100644
--- a/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java
@@ -65,10 +65,13 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ
IAutoFillManagerClient autoFillCallback) {
super(context, sessionCallback, lock, userId, callingUid, request, callback,
RequestInfo.TYPE_GET, callingAppInfo, enabledProviders,
- cancellationSignal, 0L);
+ cancellationSignal, 0L, /*shouldBindClientToDeath=*/ false);
mAutoFillCallback = autoFillCallback;
mAutofillSessionId = request.getData().getInt(SESSION_ID_KEY, -1);
mAutofillRequestId = request.getData().getInt(REQUEST_ID_KEY, -1);
+ if (mAutoFillCallback != null) {
+ setUpClientCallbackListener(mAutoFillCallback.asBinder());
+ }
}
/**
@@ -144,17 +147,27 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ
@Override
public void onFinalErrorReceived(ComponentName componentName, String errorType,
String message) {
- // Not applicable for session without UI
+ respondToClientWithErrorAndFinish(errorType, message);
}
@Override
public void onUiCancellation(boolean isUserCancellation) {
- // Not applicable for session without UI
+ String exception = GetCandidateCredentialsException.TYPE_USER_CANCELED;
+ String message = "User cancelled the selector";
+ if (!isUserCancellation) {
+ exception = GetCandidateCredentialsException.TYPE_INTERRUPTED;
+ message = "The UI was interrupted - please try again.";
+ }
+ mRequestSessionMetric.collectFrameworkException(exception);
+ respondToClientWithErrorAndFinish(exception, message);
}
@Override
public void onUiSelectorInvocationFailure() {
- // Not applicable for session without UI
+ String exception = GetCandidateCredentialsException.TYPE_NO_CREDENTIAL;
+ mRequestSessionMetric.collectFrameworkException(exception);
+ respondToClientWithErrorAndFinish(exception,
+ "No credentials available.");
}
@Override
diff --git a/services/credentials/java/com/android/server/credentials/GetRequestSession.java b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
index 3f57c804cba0..49ea19a6f098 100644
--- a/services/credentials/java/com/android/server/credentials/GetRequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/GetRequestSession.java
@@ -57,7 +57,7 @@ public class GetRequestSession extends RequestSession<GetCredentialRequest,
long startedTimestamp) {
super(context, sessionCallback, lock, userId, callingUid, request, callback,
getRequestInfoFromRequest(request), callingAppInfo, enabledProviders,
- cancellationSignal, startedTimestamp);
+ cancellationSignal, startedTimestamp, /*shouldBindClientToDeath=*/ true);
mRequestSessionMetric.collectGetFlowInitialMetricInfo(request);
}
diff --git a/services/credentials/java/com/android/server/credentials/RequestSession.java b/services/credentials/java/com/android/server/credentials/RequestSession.java
index da44aac5826a..67c52e6e4719 100644
--- a/services/credentials/java/com/android/server/credentials/RequestSession.java
+++ b/services/credentials/java/com/android/server/credentials/RequestSession.java
@@ -122,7 +122,8 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
@NonNull String requestType,
CallingAppInfo callingAppInfo,
Set<ComponentName> enabledProviders,
- CancellationSignal cancellationSignal, long timestampStarted) {
+ CancellationSignal cancellationSignal, long timestampStarted,
+ boolean shouldBindClientToDeath) {
mContext = context;
mLock = lock;
mSessionCallback = sessionCallback;
@@ -146,16 +147,18 @@ abstract class RequestSession<T, U, V> implements CredentialManagerUi.Credential
mRequestSessionMetric.collectInitialPhaseMetricInfo(timestampStarted,
mCallingUid, ApiName.getMetricCodeFromRequestInfo(mRequestType));
setCancellationListener();
- if (Flags.clearSessionEnabled()) {
- setUpClientCallbackListener();
+ if (shouldBindClientToDeath && Flags.clearSessionEnabled()) {
+ if (mClientCallback != null && mClientCallback instanceof IInterface) {
+ setUpClientCallbackListener(((IInterface) mClientCallback).asBinder());
+ }
}
}
- private void setUpClientCallbackListener() {
+ protected void setUpClientCallbackListener(IBinder clientBinder) {
if (mClientCallback != null && mClientCallback instanceof IInterface) {
IInterface callback = (IInterface) mClientCallback;
try {
- callback.asBinder().linkToDeath(mDeathRecipient, 0);
+ clientBinder.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
Slog.e(TAG, e.getMessage());
}
diff --git a/services/lint-baseline.xml b/services/lint-baseline.xml
index 8489c17dd878..a311d07e52fb 100644
--- a/services/lint-baseline.xml
+++ b/services/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="SimpleManualPermissionEnforcement"
@@ -56,4 +56,4 @@
column="13"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/services/print/lint-baseline.xml b/services/print/lint-baseline.xml
index 1bf031a9e289..11c0cc8ea93c 100644
--- a/services/print/lint-baseline.xml
+++ b/services/print/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="8.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="SimpleManualPermissionEnforcement"
@@ -12,4 +12,4 @@
column="13"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/Android.bp b/services/tests/BackgroundInstallControlServiceTests/host/Android.bp
index e3954355491d..4fcdbfc21f6c 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/Android.bp
+++ b/services/tests/BackgroundInstallControlServiceTests/host/Android.bp
@@ -33,7 +33,6 @@ java_test_host {
":BackgroundInstallControlServiceTestApp",
":BackgroundInstallControlMockApp1",
":BackgroundInstallControlMockApp2",
- ":BackgroundInstallControlMockApp3",
],
test_suites: [
"general-tests",
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml b/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml
index 031d57fbe182..1e7a78aa6f93 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml
+++ b/services/tests/BackgroundInstallControlServiceTests/host/AndroidTest.xml
@@ -29,14 +29,11 @@
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file"
- key="BackgroundInstallControlMockApp1.apk"
- value="/data/local/tmp/BackgroundInstallControlMockApp1.apk" />
+ key="BackgroundInstallControlMockApp1.apk"
+ value="/data/local/tmp/BackgroundInstallControlMockApp1.apk" />
<option name="push-file"
- key="BackgroundInstallControlMockApp2.apk"
- value="/data/local/tmp/BackgroundInstallControlMockApp2.apk" />
- <option name="push-file"
- key="BackgroundInstallControlMockApp3.apk"
- value="/data/local/tmp/BackgroundInstallControlMockApp3.apk" />
+ key="BackgroundInstallControlMockApp2.apk"
+ value="/data/local/tmp/BackgroundInstallControlMockApp2.apk" />
</target_preparer>
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java b/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java
index 5092a4659eb9..74506076d82f 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java
+++ b/services/tests/BackgroundInstallControlServiceTests/host/src/com/android/server/pm/test/BackgroundInstallControlServiceHostTest.java
@@ -41,26 +41,17 @@ public final class BackgroundInstallControlServiceHostTest extends BaseHostJUnit
private static final String MOCK_APK_FILE_1 = "BackgroundInstallControlMockApp1.apk";
private static final String MOCK_APK_FILE_2 = "BackgroundInstallControlMockApp2.apk";
- // TODO: Move the silent installs to test-app using {@link
- // BackgroundInstallControlServiceTest#installPackage(String, String)} and remove deviceConfig
- // branch in BICS.
- // b/310983905
@Test
public void testGetMockBackgroundInstalledPackages() throws Exception {
- installPackage(TEST_DATA_DIR + MOCK_APK_FILE_1);
+ installPackage(TEST_DATA_DIR + MOCK_APK_FILE_1);
installPackage(TEST_DATA_DIR + MOCK_APK_FILE_2);
assertThat(getDevice().getAppPackageInfo(MOCK_PACKAGE_NAME_1)).isNotNull();
assertThat(getDevice().getAppPackageInfo(MOCK_PACKAGE_NAME_2)).isNotNull();
- assertThat(
- getDevice()
- .setProperty(
- "debug.transparency.bg-install-apps",
- MOCK_PACKAGE_NAME_1 + "," + MOCK_PACKAGE_NAME_2))
- .isTrue();
- runDeviceTest(
- "BackgroundInstallControlServiceTest", "testGetMockBackgroundInstalledPackages");
+ assertThat(getDevice().setProperty("debug.transparency.bg-install-apps",
+ MOCK_PACKAGE_NAME_1 + "," + MOCK_PACKAGE_NAME_2)).isTrue();
+ runDeviceTest("testGetMockBackgroundInstalledPackages");
assertThat(getDevice().uninstallPackage(MOCK_PACKAGE_NAME_1)).isNull();
assertThat(getDevice().uninstallPackage(MOCK_PACKAGE_NAME_2)).isNull();
@@ -68,30 +59,16 @@ public final class BackgroundInstallControlServiceHostTest extends BaseHostJUnit
assertThat(getDevice().getAppPackageInfo(MOCK_PACKAGE_NAME_2)).isNull();
}
- @Test
- public void testRegisterCallback() throws Exception {
- runDeviceTest(
- "BackgroundInstallControlServiceTest",
- "testRegisterBackgroundInstallControlCallback");
- }
-
- @Test
- public void testUnregisterCallback() throws Exception {
- runDeviceTest(
- "BackgroundInstallControlServiceTest",
- "testUnregisterBackgroundInstallControlCallback");
- }
-
private void installPackage(String path) throws DeviceNotAvailableException {
String cmd = "pm install -t --force-queryable " + path;
CommandResult result = getDevice().executeShellV2Command(cmd);
assertThat(result.getStatus() == CommandStatus.SUCCESS).isTrue();
}
- private void runDeviceTest(String testName, String method) throws DeviceNotAvailableException {
+ private void runDeviceTest(String method) throws DeviceNotAvailableException {
var options = new DeviceTestRunOptions(PACKAGE_NAME);
- options.setTestClassName(PACKAGE_NAME + "." + testName);
+ options.setTestClassName(PACKAGE_NAME + ".BackgroundInstallControlServiceTest");
options.setTestMethodName(method);
runDeviceTests(options);
}
-} \ No newline at end of file
+}
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml
index b5b8ea0f40c7..1fa1f84cd04e 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml
+++ b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/AndroidManifest.xml
@@ -21,9 +21,6 @@
<uses-library android:name="android.test.runner" />
</application>
- <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
- <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
-
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:label="APCT tests for background install control service"
android:targetPackage="com.android.server.pm.test.app" />
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java
index f033fed73b27..b74e5619fd0c 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java
+++ b/services/tests/BackgroundInstallControlServiceTests/host/test-app/BackgroundInstallControlServiceTestApp/src/com/android/server/pm/test/app/BackgroundInstallControlServiceTest.java
@@ -16,256 +16,54 @@
package com.android.server.pm.test.app;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-
-import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
-
import static com.google.common.truth.Truth.assertThat;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.IBackgroundInstallControlService;
import android.content.pm.PackageInfo;
-import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.ParceledListSlice;
-import android.os.Bundle;
-import android.os.IRemoteCallback;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
-import android.util.Pair;
+import android.os.UserHandle;
-import androidx.annotation.NonNull;
-import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.ShellIdentityUtils;
-import com.android.compatibility.common.util.ThrowingRunnable;
-
-import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.FileInputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Supplier;
import java.util.stream.Collectors;
@RunWith(AndroidJUnit4.class)
public class BackgroundInstallControlServiceTest {
private static final String TAG = "BackgroundInstallControlServiceTest";
- private static final String ACTION_INSTALL_COMMIT =
- "com.android.server.pm.test.app.BackgroundInstallControlServiceTest"
- + ".ACTION_INSTALL_COMMIT";
- private static final String MOCK_PACKAGE_NAME = "com.android.servicestests.apps.bicmockapp3";
-
- private static final String TEST_DATA_DIR = "/data/local/tmp/";
- private static final String MOCK_APK_FILE = "BackgroundInstallControlMockApp3.apk";
private IBackgroundInstallControlService mIBics;
@Before
public void setUp() {
- mIBics =
- IBackgroundInstallControlService.Stub.asInterface(
- ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
+ mIBics = IBackgroundInstallControlService.Stub.asInterface(
+ ServiceManager.getService(Context.BACKGROUND_INSTALL_CONTROL_SERVICE));
assertThat(mIBics).isNotNull();
}
- @After
- public void tearDown() {
- runShellCommand("pm uninstall " + MOCK_PACKAGE_NAME);
- }
-
@Test
public void testGetMockBackgroundInstalledPackages() throws RemoteException {
- ParceledListSlice<PackageInfo> slice =
- ShellIdentityUtils.invokeMethodWithShellPermissions(
- mIBics,
- (bics) -> {
- try {
- return bics.getBackgroundInstalledPackages(
- PackageManager.MATCH_ALL, Process.myUserHandle()
- .getIdentifier());
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- },
- QUERY_ALL_PACKAGES);
+ ParceledListSlice<PackageInfo> slice = mIBics.getBackgroundInstalledPackages(
+ PackageManager.MATCH_ALL,
+ UserHandle.USER_ALL);
assertThat(slice).isNotNull();
var packageList = slice.getList();
assertThat(packageList).isNotNull();
assertThat(packageList).hasSize(2);
- var expectedPackageNames =
- Set.of(
- "com.android.servicestests.apps.bicmockapp1",
- "com.android.servicestests.apps.bicmockapp2");
- var actualPackageNames =
- packageList.stream()
- .map((packageInfo) -> packageInfo.packageName)
- .collect(Collectors.toSet());
+ var expectedPackageNames = Set.of("com.android.servicestests.apps.bicmockapp1",
+ "com.android.servicestests.apps.bicmockapp2");
+ var actualPackageNames = packageList.stream().map((packageInfo) -> packageInfo.packageName)
+ .collect(Collectors.toSet());
assertThat(actualPackageNames).containsExactlyElementsIn(expectedPackageNames);
}
-
- @Test
- public void testRegisterBackgroundInstallControlCallback()
- throws Exception {
- String testPackageName = "test";
- int testUserId = 1;
- ArrayList<Pair<String, Integer>> sharedResource = new ArrayList<>();
- IRemoteCallback testCallback =
- new IRemoteCallback.Stub() {
- private final ArrayList<Pair<String, Integer>> mArray = sharedResource;
-
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- mArray.add(new Pair(testPackageName, testUserId));
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mIBics,
- (bics) -> {
- try {
- bics.registerBackgroundInstallCallback(testCallback);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- },
- QUERY_ALL_PACKAGES,
- INTERACT_ACROSS_USERS_FULL);
- installPackage(TEST_DATA_DIR + MOCK_APK_FILE, MOCK_PACKAGE_NAME);
-
- assertUntil(() -> sharedResource.size() == 1, 2000);
- assertThat(sharedResource.get(0).first).isEqualTo(testPackageName);
- assertThat(sharedResource.get(0).second).isEqualTo(testUserId);
- }
-
- @Test
- public void testUnregisterBackgroundInstallControlCallback() {
- String testValue = "test";
- ArrayList<String> sharedResource = new ArrayList<>();
- IRemoteCallback testCallback =
- new IRemoteCallback.Stub() {
- private final ArrayList<String> mArray = sharedResource;
-
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- mArray.add(testValue);
- }
- };
- ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
- mIBics,
- (bics) -> {
- try {
- bics.registerBackgroundInstallCallback(testCallback);
- bics.unregisterBackgroundInstallCallback(testCallback);
- } catch (RemoteException e) {
- throw new RuntimeException(e);
- }
- },
- QUERY_ALL_PACKAGES,
- INTERACT_ACROSS_USERS_FULL);
- installPackage(TEST_DATA_DIR + MOCK_APK_FILE, MOCK_PACKAGE_NAME);
-
- assertUntil(() -> sharedResource.isEmpty(), 2000);
- }
-
- private static boolean installPackage(String apkPath, String packageName) {
- Context context = InstrumentationRegistry.getInstrumentation().getContext();
- final CountDownLatch installLatch = new CountDownLatch(1);
- final BroadcastReceiver installReceiver =
- new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- int packageInstallStatus =
- intent.getIntExtra(
- PackageInstaller.EXTRA_STATUS,
- PackageInstaller.STATUS_FAILURE_INVALID);
- if (packageInstallStatus == PackageInstaller.STATUS_SUCCESS) {
- installLatch.countDown();
- }
- }
- };
- final IntentFilter intentFilter = new IntentFilter(ACTION_INSTALL_COMMIT);
- context.registerReceiver(installReceiver, intentFilter, Context.RECEIVER_EXPORTED);
-
- PackageInstaller packageInstaller = context.getPackageManager().getPackageInstaller();
- PackageInstaller.SessionParams params =
- new PackageInstaller.SessionParams(
- PackageInstaller.SessionParams.MODE_FULL_INSTALL);
- params.setRequireUserAction(PackageInstaller.SessionParams.USER_ACTION_NOT_REQUIRED);
- try {
- int sessionId = packageInstaller.createSession(params);
- PackageInstaller.Session session = packageInstaller.openSession(sessionId);
- OutputStream out = session.openWrite(packageName, 0, -1);
- FileInputStream fis = new FileInputStream(apkPath);
- byte[] buffer = new byte[65536];
- int size;
- while ((size = fis.read(buffer)) != -1) {
- out.write(buffer, 0, size);
- }
- session.fsync(out);
- fis.close();
- out.close();
-
- runWithShellPermissionIdentity(
- () -> {
- session.commit(createPendingIntent(context).getIntentSender());
- installLatch.await(5, TimeUnit.SECONDS);
- });
- return true;
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- private static PendingIntent createPendingIntent(Context context) {
- PendingIntent pendingIntent =
- PendingIntent.getBroadcast(
- context,
- 1,
- new Intent(ACTION_INSTALL_COMMIT)
- .setPackage(
- BackgroundInstallControlServiceTest.class.getPackageName()),
- PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_MUTABLE);
- return pendingIntent;
- }
-
- private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
- throws Exception {
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
- .adoptShellPermissionIdentity();
- try {
- command.run();
- } finally {
- InstrumentationRegistry.getInstrumentation()
- .getUiAutomation()
- .dropShellPermissionIdentity();
- }
- }
-
- private static void assertUntil(Supplier<Boolean> condition, int timeoutMs) {
- long endTime = System.currentTimeMillis() + timeoutMs;
- while (System.currentTimeMillis() <= endTime) {
- if (condition.get()) return;
- try {
- Thread.sleep(10);
- } catch (InterruptedException e) {
- throw new RuntimeException(e);
- }
- }
- assertThat(condition.get()).isTrue();
- }
}
diff --git a/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp b/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp
index 39b0ff782b72..7804f4ce9d02 100644
--- a/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp
+++ b/services/tests/BackgroundInstallControlServiceTests/host/test-app/MockApp/Android.bp
@@ -50,11 +50,3 @@ android_test_helper_app {
"--rename-manifest-package com.android.servicestests.apps.bicmockapp2",
],
}
-
-android_test_helper_app {
- name: "BackgroundInstallControlMockApp3",
- defaults: ["bic-mock-app-defaults"],
- aaptflags: [
- "--rename-manifest-package com.android.servicestests.apps.bicmockapp3",
- ],
-}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
index 5c50acb13f30..a8af98f7a332 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/RefreshRateSettingsUtilsTest.java
@@ -72,14 +72,18 @@ public class RefreshRateSettingsUtilsTest {
@Test
public void testFindHighestRefreshRateForDefaultDisplay() {
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
- assertEquals(DEFAULT_REFRESH_RATE,
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
+ assertEquals(120,
RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
/* delta= */ 0);
+ }
- when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock);
- assertEquals(120,
+ @Test
+ public void testFindHighestRefreshRate_DisplayIsNull() {
+ when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(null);
+ assertEquals(DEFAULT_REFRESH_RATE,
RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext),
/* delta= */ 0);
+
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
index a0e5fd8e1b34..83479e28fe24 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java
@@ -27,8 +27,6 @@ import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_R
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_HIGH_ZONE;
import static android.hardware.display.DisplayManager.DeviceConfig.KEY_REFRESH_RATE_IN_LOW_ZONE;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertArrayEquals;
@@ -290,6 +288,7 @@ public class DisplayModeDirectorTest {
};
private static final int DISPLAY_ID = Display.DEFAULT_DISPLAY;
+ private static final int DISPLAY_ID_2 = Display.DEFAULT_DISPLAY + 1;
private static final int MODE_ID = 1;
private static final float TRANSITION_POINT = 0.763f;
@@ -1550,23 +1549,39 @@ public class DisplayModeDirectorTest {
public void testPeakRefreshRate_FlagEnabled() {
when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
.thenReturn(true);
- float highestRefreshRate = 130;
- doReturn(highestRefreshRate).when(() ->
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
DisplayModeDirector director =
- createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+ Display.Mode[] modes1 = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 130),
+ };
+ Display.Mode[] modes2 = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 140),
+ };
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
+ supportedModesByDisplay.put(DISPLAY_ID, modes1);
+ supportedModesByDisplay.put(DISPLAY_ID_2, modes2);
+
Sensor lightSensor = createLightSensor();
SensorManager sensorManager = createMockSensorManager(lightSensor);
director.start(sensorManager);
+ director.injectSupportedModesByDisplay(supportedModesByDisplay);
setPeakRefreshRate(Float.POSITIVE_INFINITY);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote vote1 = director.getVote(DISPLAY_ID,
Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- highestRefreshRate);
+ Vote vote2 = director.getVote(DISPLAY_ID_2,
+ Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 0, /* frameRateHigh= */ 130);
+ assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 0, /* frameRateHigh= */ 140);
}
@Test
@@ -1584,32 +1599,85 @@ public class DisplayModeDirectorTest {
setPeakRefreshRate(peakRefreshRate);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0,
+ /* frameRateHigh= */ peakRefreshRate);
+ }
+
+ @Test
+ public void testPeakRefreshRate_DisplayChanged() {
+ when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+ .thenReturn(true);
+ DisplayModeDirector director =
+ new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+ mInjector.mDisplayInfo.supportedModes = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 130),
+ };
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ setPeakRefreshRate(Float.POSITIVE_INFINITY);
+
+ Vote vote = director.getVote(DISPLAY_ID,
Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */
- peakRefreshRate);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 130);
+
+ // The highest refresh rate of the display changes
+ mInjector.mDisplayInfo.supportedModes = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 140),
+ };
+ director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_PEAK_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 0, /* frameRateHigh= */ 140);
}
@Test
public void testMinRefreshRate_FlagEnabled() {
when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
.thenReturn(true);
- float highestRefreshRate = 130;
- doReturn(highestRefreshRate).when(() ->
- RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay(mContext));
DisplayModeDirector director =
- createDirectorFromRefreshRateArray(new float[] {60.f, 90.f}, 0);
+ new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+ Display.Mode[] modes1 = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 130),
+ };
+ Display.Mode[] modes2 = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 140),
+ };
+ SparseArray<Display.Mode[]> supportedModesByDisplay = new SparseArray<>();
+ supportedModesByDisplay.put(DISPLAY_ID, modes1);
+ supportedModesByDisplay.put(DISPLAY_ID_2, modes2);
+
Sensor lightSensor = createLightSensor();
SensorManager sensorManager = createMockSensorManager(lightSensor);
director.start(sensorManager);
+ director.injectSupportedModesByDisplay(supportedModesByDisplay);
setMinRefreshRate(Float.POSITIVE_INFINITY);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
+ Vote vote1 = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ Vote vote2 = director.getVote(DISPLAY_ID_2,
Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
- assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ highestRefreshRate,
+ assertVoteForRenderFrameRateRange(vote1, /* frameRateLow= */ 130,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+ assertVoteForRenderFrameRateRange(vote2, /* frameRateLow= */ 140,
/* frameRateHigh= */ Float.POSITIVE_INFINITY);
}
@@ -1628,13 +1696,50 @@ public class DisplayModeDirectorTest {
setMinRefreshRate(minRefreshRate);
- Vote vote = director.getVote(Display.DEFAULT_DISPLAY,
- Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ minRefreshRate,
/* frameRateHigh= */ Float.POSITIVE_INFINITY);
}
@Test
+ public void testMinRefreshRate_DisplayChanged() {
+ when(mDisplayManagerFlags.isBackUpSmoothDisplayAndForcePeakRefreshRateEnabled())
+ .thenReturn(true);
+ DisplayModeDirector director =
+ new DisplayModeDirector(mContext, mHandler, mInjector, mDisplayManagerFlags);
+ director.getBrightnessObserver().setDefaultDisplayState(Display.STATE_ON);
+ mInjector.mDisplayInfo.supportedModes = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 130),
+ };
+
+ Sensor lightSensor = createLightSensor();
+ SensorManager sensorManager = createMockSensorManager(lightSensor);
+ director.start(sensorManager);
+
+ setMinRefreshRate(Float.POSITIVE_INFINITY);
+
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 130,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+
+ // The highest refresh rate of the display changes
+ mInjector.mDisplayInfo.supportedModes = new Display.Mode[] {
+ new Display.Mode(/* modeId= */ 1, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 60),
+ new Display.Mode(/* modeId= */ 2, /* width= */ 1280, /* height= */ 720,
+ /* refreshRate= */ 140),
+ };
+ director.getDisplayObserver().onDisplayChanged(DISPLAY_ID);
+
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_USER_SETTING_MIN_RENDER_FRAME_RATE);
+ assertVoteForRenderFrameRateRange(vote, /* frameRateLow= */ 140,
+ /* frameRateHigh= */ Float.POSITIVE_INFINITY);
+ }
+
+ @Test
public void testSensorRegistration() {
// First, configure brightness zones or DMD won't register for sensor data.
final FakeDeviceConfig config = mInjector.getDeviceConfig();
@@ -3329,7 +3434,7 @@ public class DisplayModeDirectorTest {
public static class FakesInjector implements DisplayModeDirector.Injector {
private final FakeDeviceConfig mDeviceConfig;
private final DisplayInfo mDisplayInfo;
- private final Display mDisplay;
+ private final Map<Integer, Display> mDisplays;
private boolean mDisplayInfoValid = true;
private final DisplayManagerInternal mDisplayManagerInternal;
private final StatusBarManagerInternal mStatusBarManagerInternal;
@@ -3350,7 +3455,8 @@ public class DisplayModeDirectorTest {
mDisplayInfo.defaultModeId = MODE_ID;
mDisplayInfo.supportedModes = new Display.Mode[] {new Display.Mode(MODE_ID,
800, 600, /* refreshRate= */ 60)};
- mDisplay = createDisplay(DISPLAY_ID);
+ mDisplays = Map.of(DISPLAY_ID, createDisplay(DISPLAY_ID),
+ DISPLAY_ID_2, createDisplay(DISPLAY_ID_2));
mDisplayManagerInternal = displayManagerInternal;
mStatusBarManagerInternal = statusBarManagerInternal;
mSensorManagerInternal = sensorManagerInternal;
@@ -3381,12 +3487,12 @@ public class DisplayModeDirectorTest {
@Override
public Display getDisplay(int displayId) {
- return mDisplay;
+ return mDisplays.get(displayId);
}
@Override
public Display[] getDisplays() {
- return new Display[] { mDisplay };
+ return mDisplays.values().toArray(new Display[0]);
}
@Override
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java
deleted file mode 100644
index e1fce9b75906..000000000000
--- a/services/tests/mockingservicestests/src/com/android/server/pm/BackgroundInstallControlCallbackHelperTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.pm;
-
-import static com.android.server.pm.BackgroundInstallControlCallbackHelper.FLAGGED_PACKAGE_NAME_KEY;
-import static com.android.server.pm.BackgroundInstallControlCallbackHelper.FLAGGED_USER_ID_KEY;
-
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.after;
-import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.verify;
-
-import android.os.Bundle;
-import android.os.IRemoteCallback;
-import android.os.RemoteException;
-import android.platform.test.annotations.Presubmit;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-import org.mockito.ArgumentCaptor;
-
-/** Unit tests for {@link BackgroundInstallControlCallbackHelperTest} */
-@Presubmit
-@RunWith(JUnit4.class)
-public class BackgroundInstallControlCallbackHelperTest {
-
- private final IRemoteCallback mCallback =
- spy(
- new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle extras) {}
- });
-
- private BackgroundInstallControlCallbackHelper mCallbackHelper;
-
- @Before
- public void setup() {
- mCallbackHelper = new BackgroundInstallControlCallbackHelper();
- }
-
- @Test
- public void registerBackgroundInstallControlCallback_registers_successfully() {
- mCallbackHelper.registerBackgroundInstallCallback(mCallback);
-
- synchronized (mCallbackHelper.mCallbacks) {
- assertEquals(1, mCallbackHelper.mCallbacks.getRegisteredCallbackCount());
- assertEquals(mCallback, mCallbackHelper.mCallbacks.getRegisteredCallbackItem(0));
- }
- }
-
- @Test
- public void unregisterBackgroundInstallControlCallback_unregisters_successfully() {
- synchronized (mCallbackHelper.mCallbacks) {
- mCallbackHelper.mCallbacks.register(mCallback);
- }
-
- mCallbackHelper.unregisterBackgroundInstallCallback(mCallback);
-
- synchronized (mCallbackHelper.mCallbacks) {
- assertEquals(0, mCallbackHelper.mCallbacks.getRegisteredCallbackCount());
- }
- }
-
- @Test
- public void notifyAllCallbacks_broadcastsToCallbacks()
- throws RemoteException {
- String testPackageName = "testname";
- int testUserId = 1;
- mCallbackHelper.registerBackgroundInstallCallback(mCallback);
-
- mCallbackHelper.notifyAllCallbacks(testUserId, testPackageName);
-
- ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
- verify(mCallback, after(1000).times(1)).sendResult(bundleCaptor.capture());
- Bundle receivedBundle = bundleCaptor.getValue();
- assertEquals(testPackageName, receivedBundle.getString(FLAGGED_PACKAGE_NAME_KEY));
- assertEquals(testUserId, receivedBundle.getInt(FLAGGED_USER_ID_KEY));
- }
-}
diff --git a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
index c0051c6c9e17..eee37525ee37 100644
--- a/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AnrHelperTest.java
@@ -133,7 +133,8 @@ public class AnrHelperTest {
verify(mAnrApp.mErrorState, timeout(TIMEOUT_MS)).appNotResponding(
eq(activityShortComponentName), eq(appInfo), eq(parentShortComponentName),
eq(parentProcess), eq(aboveSystem), eq(timeoutRecord), eq(mAuxExecutorService),
- eq(false) /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/, eq(mEarlyDumpFuture));
+ anyBoolean() /* onlyDumpSelf */, eq(false) /*isContinuousAnr*/,
+ eq(mEarlyDumpFuture));
}
@Test
diff --git a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
index 3069d25e39d7..daf18edaf2de 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BackgroundInstallControlServiceTest.java
@@ -16,10 +16,6 @@
package com.android.server.pm;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -31,7 +27,6 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -102,6 +97,7 @@ public final class BackgroundInstallControlServiceTest {
private Looper mLooper;
private File mFile;
+
@Mock
private Context mContext;
@Mock
@@ -112,12 +108,8 @@ public final class BackgroundInstallControlServiceTest {
private UsageStatsManagerInternal mUsageStatsManagerInternal;
@Mock
private PermissionManagerServiceInternal mPermissionManager;
- @Mock
- private BackgroundInstallControlCallbackHelper mCallbackHelper;
-
@Captor
private ArgumentCaptor<PackageManagerInternal.PackageListObserver> mPackageListObserverCaptor;
-
@Captor
private ArgumentCaptor<UsageEventListener> mUsageEventListenerCaptor;
@@ -127,12 +119,11 @@ public final class BackgroundInstallControlServiceTest {
mTestLooper = new TestLooper();
mLooper = mTestLooper.getLooper();
- mFile =
- new File(
- InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(),
- "test");
- mBackgroundInstallControlService =
- new BackgroundInstallControlService(new MockInjector(mContext));
+ mFile = new File(
+ InstrumentationRegistry.getInstrumentation().getContext().getCacheDir(),
+ "test");
+ mBackgroundInstallControlService = new BackgroundInstallControlService(
+ new MockInjector(mContext));
verify(mUsageStatsManagerInternal).registerListener(mUsageEventListenerCaptor.capture());
mUsageEventListener = mUsageEventListenerCaptor.getValue();
@@ -152,7 +143,8 @@ public final class BackgroundInstallControlServiceTest {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
mBackgroundInstallControlService.initBackgroundInstalledPackages();
assertNotNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- assertEquals(0, mBackgroundInstallControlService.getBackgroundInstalledPackages().size());
+ assertEquals(0,
+ mBackgroundInstallControlService.getBackgroundInstalledPackages().size());
}
@Test
@@ -169,9 +161,12 @@ public final class BackgroundInstallControlServiceTest {
// Write test data to the file on the disk.
try {
ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
- long token = protoOutputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
- protoOutputStream.write(BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
- protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
+ long token = protoOutputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
protoOutputStream.end(token);
protoOutputStream.flush();
atomicFile.finishWrite(fileOutputStream);
@@ -203,14 +198,20 @@ public final class BackgroundInstallControlServiceTest {
try {
ProtoOutputStream protoOutputStream = new ProtoOutputStream(fileOutputStream);
- long token = protoOutputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
- protoOutputStream.write(BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
- protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
+ long token = protoOutputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_1);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.USER_ID, USER_ID_1 + 1);
protoOutputStream.end(token);
- token = protoOutputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
- protoOutputStream.write(BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_2);
- protoOutputStream.write(BackgroundInstalledPackageProto.USER_ID, USER_ID_2 + 1);
+ token = protoOutputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.PACKAGE_NAME, PACKAGE_NAME_2);
+ protoOutputStream.write(
+ BackgroundInstalledPackageProto.USER_ID, USER_ID_2 + 1);
protoOutputStream.end(token);
protoOutputStream.flush();
@@ -240,7 +241,7 @@ public final class BackgroundInstallControlServiceTest {
// Read the file on the disk to verify
var packagesInDisk = new SparseSetArray<>();
AtomicFile atomicFile = new AtomicFile(mFile);
- try (FileInputStream fileInputStream = atomicFile.openRead()) {
+ try (FileInputStream fileInputStream = atomicFile.openRead()) {
ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -248,25 +249,23 @@ public final class BackgroundInstallControlServiceTest {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token =
- protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token = protoInputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName =
- protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName = protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId =
- protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID)
- - 1;
+ userId = protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID) - 1;
break;
default:
- fail("Undefined field in proto: " + protoInputStream.getFieldNumber());
+ fail("Undefined field in proto: "
+ + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -297,7 +296,7 @@ public final class BackgroundInstallControlServiceTest {
// Read the file on the disk to verify
var packagesInDisk = new SparseSetArray<>();
AtomicFile atomicFile = new AtomicFile(mFile);
- try (FileInputStream fileInputStream = atomicFile.openRead()) {
+ try (FileInputStream fileInputStream = atomicFile.openRead()) {
ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -305,25 +304,23 @@ public final class BackgroundInstallControlServiceTest {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token =
- protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token = protoInputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName =
- protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName = protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId =
- protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID)
- - 1;
+ userId = protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID) - 1;
break;
default:
- fail("Undefined field in proto: " + protoInputStream.getFieldNumber());
+ fail("Undefined field in proto: "
+ + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -356,7 +353,7 @@ public final class BackgroundInstallControlServiceTest {
// Read the file on the disk to verify
var packagesInDisk = new SparseSetArray<>();
AtomicFile atomicFile = new AtomicFile(mFile);
- try (FileInputStream fileInputStream = atomicFile.openRead()) {
+ try (FileInputStream fileInputStream = atomicFile.openRead()) {
ProtoInputStream protoInputStream = new ProtoInputStream(fileInputStream);
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
@@ -364,25 +361,23 @@ public final class BackgroundInstallControlServiceTest {
!= (int) BackgroundInstalledPackagesProto.BG_INSTALLED_PKG) {
continue;
}
- long token =
- protoInputStream.start(BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
+ long token = protoInputStream.start(
+ BackgroundInstalledPackagesProto.BG_INSTALLED_PKG);
String packageName = null;
int userId = UserHandle.USER_NULL;
while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) {
switch (protoInputStream.getFieldNumber()) {
case (int) BackgroundInstalledPackageProto.PACKAGE_NAME:
- packageName =
- protoInputStream.readString(
- BackgroundInstalledPackageProto.PACKAGE_NAME);
+ packageName = protoInputStream.readString(
+ BackgroundInstalledPackageProto.PACKAGE_NAME);
break;
case (int) BackgroundInstalledPackageProto.USER_ID:
- userId =
- protoInputStream.readInt(
- BackgroundInstalledPackageProto.USER_ID)
- - 1;
+ userId = protoInputStream.readInt(
+ BackgroundInstalledPackageProto.USER_ID) - 1;
break;
default:
- fail("Undefined field in proto: " + protoInputStream.getFieldNumber());
+ fail("Undefined field in proto: "
+ + protoInputStream.getFieldNumber());
}
}
protoInputStream.end(token);
@@ -404,55 +399,51 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_permissionDenied() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PackageManager.PERMISSION_DENIED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, 0);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_DENIED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, 0);
mTestLooper.dispatchAll();
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
}
@Test
public void testHandleUsageEvent_permissionGranted() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED, USER_ID_1, INSTALLER_NAME_1, 0);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, 0);
mTestLooper.dispatchAll();
- assertEquals(
- 1, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ assertEquals(1,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
}
@Test
public void testHandleUsageEvent_ignoredEvent() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(UsageEvents.Event.USER_INTERACTION, USER_ID_1, INSTALLER_NAME_1, 0);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.USER_INTERACTION,
+ USER_ID_1, INSTALLER_NAME_1, 0);
mTestLooper.dispatchAll();
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
}
@Test
public void testHandleUsageEvent_firstActivityResumedHalfTimeFrame() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_1);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -470,18 +461,14 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_firstActivityResumedOneTimeFrame() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_1);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -499,23 +486,16 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_firstActivityResumedOneAndHalfTimeFrame() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_1);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_3);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -537,13 +517,12 @@ public final class BackgroundInstallControlServiceTest {
@Test
public void testHandleUsageEvent_firstNoneActivityResumed() {
- assertEquals(
- 0, mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
+ assertEquals(0,
+ mBackgroundInstallControlService.getInstallerForegroundTimeFrames().numMaps());
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
mTestLooper.dispatchAll();
var installerForegroundTimeFrames =
@@ -556,26 +535,27 @@ public final class BackgroundInstallControlServiceTest {
}
@Test
- public void testHandleUsageEvent_packageAddedNoUsageEvent()
- throws NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedNoUsageEvent() throws
+ NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo =
- new InstallSourceInfo(
- /* initiatingPackageName= */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo= */ null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ /* initiatingPackageName = */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo = */ null,
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
- .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(PACKAGE_NAME_1),
+ any(),
+ anyInt())
+ ).thenReturn(appInfo);
- long createTimestamp =
- PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(
- appInfo,
+ long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+ - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -592,26 +572,27 @@ public final class BackgroundInstallControlServiceTest {
}
@Test
- public void testHandleUsageEvent_packageAddedInsideTimeFrame()
- throws NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedInsideTimeFrame() throws
+ NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo =
- new InstallSourceInfo(
- /* initiatingPackageName= */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo= */ null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ /* initiatingPackageName = */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo = */ null,
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
- .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(PACKAGE_NAME_1),
+ any(),
+ anyInt())
+ ).thenReturn(appInfo);
- long createTimestamp =
- PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(
- appInfo,
+ long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+ - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -623,16 +604,12 @@ public final class BackgroundInstallControlServiceTest {
// The 2 usage events make the package adding inside a time frame.
// So it's not a background install. Thus, it's null for the return of
// mBackgroundInstallControlService.getBackgroundInstalledPackages()
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_1);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_1);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -640,26 +617,27 @@ public final class BackgroundInstallControlServiceTest {
}
@Test
- public void testHandleUsageEvent_packageAddedOutsideTimeFrame1()
- throws NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedOutsideTimeFrame1() throws
+ NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo =
- new InstallSourceInfo(
- /* initiatingPackageName= */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo= */ null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ /* initiatingPackageName = */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo = */ null,
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
- .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(PACKAGE_NAME_1),
+ any(),
+ anyInt())
+ ).thenReturn(appInfo);
- long createTimestamp =
- PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(
- appInfo,
+ long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+ - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -672,16 +650,12 @@ public final class BackgroundInstallControlServiceTest {
// Compared to testHandleUsageEvent_packageAddedInsideTimeFrame,
// it's a background install. Thus, it's not null for the return of
// mBackgroundInstallControlService.getBackgroundInstalledPackages()
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -691,28 +665,28 @@ public final class BackgroundInstallControlServiceTest {
assertEquals(1, packages.size());
assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
}
-
@Test
- public void testHandleUsageEvent_packageAddedOutsideTimeFrame2()
- throws NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedOutsideTimeFrame2() throws
+ NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
- InstallSourceInfo installSourceInfo =
- new InstallSourceInfo(
- /* initiatingPackageName= */ INSTALLER_NAME_1,
- /* initiatingPackageSigningInfo= */ null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ /* initiatingPackageName = */ INSTALLER_NAME_1,
+ /* initiatingPackageSigningInfo = */ null,
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ INSTALLER_NAME_1);
assertEquals(installSourceInfo.getInstallingPackageName(), INSTALLER_NAME_1);
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
- .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(PACKAGE_NAME_1),
+ any(),
+ anyInt())
+ ).thenReturn(appInfo);
- long createTimestamp =
- PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(
- appInfo,
+ long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+ - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -726,16 +700,12 @@ public final class BackgroundInstallControlServiceTest {
// Compared to testHandleUsageEvent_packageAddedInsideTimeFrame,
// it's a background install. Thus, it's not null for the return of
// mBackgroundInstallControlService.getBackgroundInstalledPackages()
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_2,
- INSTALLER_NAME_2,
- USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_2, INSTALLER_NAME_2, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -745,31 +715,31 @@ public final class BackgroundInstallControlServiceTest {
assertEquals(1, packages.size());
assertTrue(packages.contains(USER_ID_1, PACKAGE_NAME_1));
}
-
@Test
- public void testHandleUsageEvent_packageAddedThroughAdb()
- throws NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedThroughAdb() throws
+ NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
// This test is a duplicate of testHandleUsageEvent_packageAddedThroughAdb except the
// initiatingPackageName used to be null but is now "com.android.shell". This test ensures
// that the behavior is still the same for when the initiatingPackageName is null.
- InstallSourceInfo installSourceInfo =
- new InstallSourceInfo(
- /* initiatingPackageName= */ null,
- /* initiatingPackageSigningInfo= */ null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ /* initiatingPackageName = */ null,
+ /* initiatingPackageSigningInfo = */ null,
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ INSTALLER_NAME_1);
// b/265203007
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
- .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(PACKAGE_NAME_1),
+ any(),
+ anyInt())
+ ).thenReturn(appInfo);
- long createTimestamp =
- PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(
- appInfo,
+ long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+ - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -781,16 +751,12 @@ public final class BackgroundInstallControlServiceTest {
// for ADB installs the initiatingPackageName used to be null, despite being detected
// as a background install. Since we do not want to treat side-loaded apps as background
// install getBackgroundInstalledPackages() is expected to return null
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -798,31 +764,31 @@ public final class BackgroundInstallControlServiceTest {
var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
assertNull(packages);
}
-
@Test
- public void testHandleUsageEvent_packageAddedThroughAdb2()
- throws NoSuchFieldException, PackageManager.NameNotFoundException {
+ public void testHandleUsageEvent_packageAddedThroughAdb2() throws
+ NoSuchFieldException, PackageManager.NameNotFoundException {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
// This test is a duplicate of testHandleUsageEvent_packageAddedThroughAdb except the
// initiatingPackageName used to be null but is now "com.android.shell". This test ensures
// that the behavior is still the same after this change.
- InstallSourceInfo installSourceInfo =
- new InstallSourceInfo(
- /* initiatingPackageName= */ "com.android.shell",
- /* initiatingPackageSigningInfo= */ null,
- /* originatingPackageName= */ null,
- /* installingPackageName= */ INSTALLER_NAME_1);
+ InstallSourceInfo installSourceInfo = new InstallSourceInfo(
+ /* initiatingPackageName = */ "com.android.shell",
+ /* initiatingPackageSigningInfo = */ null,
+ /* originatingPackageName = */ null,
+ /* installingPackageName = */ INSTALLER_NAME_1);
// b/265203007
when(mPackageManager.getInstallSourceInfo(anyString())).thenReturn(installSourceInfo);
ApplicationInfo appInfo = mock(ApplicationInfo.class);
- when(mPackageManager.getApplicationInfoAsUser(eq(PACKAGE_NAME_1), any(), anyInt()))
- .thenReturn(appInfo);
+ when(mPackageManager.getApplicationInfoAsUser(
+ eq(PACKAGE_NAME_1),
+ any(),
+ anyInt())
+ ).thenReturn(appInfo);
- long createTimestamp =
- PACKAGE_ADD_TIMESTAMP_1 - (System.currentTimeMillis() - SystemClock.uptimeMillis());
- FieldSetter.setField(
- appInfo,
+ long createTimestamp = PACKAGE_ADD_TIMESTAMP_1
+ - (System.currentTimeMillis() - SystemClock.uptimeMillis());
+ FieldSetter.setField(appInfo,
ApplicationInfo.class.getDeclaredField("createTimestamp"),
createTimestamp);
@@ -834,16 +800,12 @@ public final class BackgroundInstallControlServiceTest {
// for ADB installs the initiatingPackageName is com.android.shell, despite being detected
// as a background install. Since we do not want to treat side-loaded apps as background
// install getBackgroundInstalledPackages() is expected to return null
- doReturn(PERMISSION_GRANTED)
- .when(mPermissionManager)
- .checkPermission(anyString(), anyString(), anyInt(), anyInt());
- generateUsageEvent(
- UsageEvents.Event.ACTIVITY_RESUMED,
- USER_ID_1,
- INSTALLER_NAME_1,
- USAGE_EVENT_TIMESTAMP_2);
- generateUsageEvent(
- Event.ACTIVITY_STOPPED, USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
+ doReturn(PackageManager.PERMISSION_GRANTED).when(mPermissionManager).checkPermission(
+ anyString(), anyString(), anyInt(), anyInt());
+ generateUsageEvent(UsageEvents.Event.ACTIVITY_RESUMED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_2);
+ generateUsageEvent(Event.ACTIVITY_STOPPED,
+ USER_ID_1, INSTALLER_NAME_1, USAGE_EVENT_TIMESTAMP_3);
mPackageListObserver.onPackageAdded(PACKAGE_NAME_1, uid);
mTestLooper.dispatchAll();
@@ -851,7 +813,6 @@ public final class BackgroundInstallControlServiceTest {
var packages = mBackgroundInstallControlService.getBackgroundInstalledPackages();
assertNull(packages);
}
-
@Test
public void testPackageRemoved() {
assertNull(mBackgroundInstallControlService.getBackgroundInstalledPackages());
@@ -898,7 +859,8 @@ public final class BackgroundInstallControlServiceTest {
packages.add(packageInfo2);
var packageInfo3 = makePackageInfo(PACKAGE_NAME_3);
packages.add(packageInfo3);
- doReturn(packages).when(mPackageManager).getInstalledPackagesAsUser(any(), anyInt());
+ doReturn(packages).when(mPackageManager).getInstalledPackagesAsUser(
+ any(), anyInt());
var resultPackages =
mBackgroundInstallControlService.getBackgroundInstalledPackages(0L, USER_ID_1);
@@ -908,44 +870,18 @@ public final class BackgroundInstallControlServiceTest {
assertFalse(resultPackages.getList().contains(packageInfo3));
}
- @Test(expected = SecurityException.class)
- public void enforceCallerQueryPackagesPermissionsThrowsSecurityException() {
- doThrow(new SecurityException("test")).when(mContext)
- .enforceCallingPermission(eq(QUERY_ALL_PACKAGES), anyString());
-
- mBackgroundInstallControlService.enforceCallerQueryPackagesPermissions();
- }
-
- @Test
- public void enforceCallerQueryPackagesPermissionsDoesNotThrowSecurityException() {
- //enforceCallerQueryPackagesPermissions do not throw
-
- mBackgroundInstallControlService.enforceCallerQueryPackagesPermissions();
- }
-
- @Test(expected = SecurityException.class)
- public void enforceCallerInteractCrossUserPermissionsThrowsSecurityException() {
- doThrow(new SecurityException("test")).when(mContext)
- .enforceCallingPermission(eq(INTERACT_ACROSS_USERS_FULL), anyString());
-
- mBackgroundInstallControlService.enforceCallerInteractCrossUserPermissions();
- }
- @Test
- public void enforceCallerInteractCrossUserPermissionsDoesNotThrowSecurityException() {
- //enforceCallerQueryPackagesPermissions do not throw
-
- mBackgroundInstallControlService.enforceCallerInteractCrossUserPermissions();
- }
-
/**
* Mock a usage event occurring.
*
* @param usageEventId id of a usage event
- * @param userId user id of a usage event
- * @param pkgName package name of a usage event
- * @param timestamp timestamp of a usage event
+ * @param userId user id of a usage event
+ * @param pkgName package name of a usage event
+ * @param timestamp timestamp of a usage event
*/
- private void generateUsageEvent(int usageEventId, int userId, String pkgName, long timestamp) {
+ private void generateUsageEvent(int usageEventId,
+ int userId,
+ String pkgName,
+ long timestamp) {
Event event = new Event(usageEventId, timestamp);
event.mPackage = pkgName;
mUsageEventListener.onUsageEvent(userId, event);
@@ -999,10 +935,5 @@ public final class BackgroundInstallControlServiceTest {
public File getDiskFile() {
return mFile;
}
-
- @Override
- public BackgroundInstallControlCallbackHelper getBackgroundInstallControlCallbackHelper() {
- return mCallbackHelper;
- }
}
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
index c10c3c28e9dd..9b25f58acc96 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationHistoryManagerTest.java
@@ -183,7 +183,6 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
assertThat(mHistoryManager.doesHistoryExistForUser(mProfileId)).isFalse();
verify(mDb, times(2)).disableHistory();
}
-
@Test
public void testAddProfile_historyEnabledInPrimary() {
// create a history
@@ -610,4 +609,14 @@ public class NotificationHistoryManagerTest extends UiServiceTestCase {
assertThat(mHistoryManager.isHistoryEnabled(USER_SYSTEM)).isFalse();
}
+ @Test
+ public void testDelayedPackageRemoval_userLocked() {
+ String pkg = "pkg";
+ mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
+ mHistoryManager.onUserUnlocked(USER_SYSTEM);
+ mHistoryManager.onUserStopped(USER_SYSTEM);
+ mHistoryManager.onPackageRemoved(USER_SYSTEM, pkg);
+
+ // no exception, yay
+ }
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index 53ca704b6d86..bf850cfe04db 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -44,8 +44,10 @@ import android.content.pm.ParceledListSlice;
import android.content.pm.ShortcutInfo;
import android.graphics.Bitmap;
import android.graphics.drawable.Icon;
+import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Build;
+import android.os.DeadObjectException;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -99,6 +101,20 @@ public class NotificationListenerServiceTest extends UiServiceTestCase {
}
@Test
+ public void testGetActiveNotifications_handlesBinderErrors() throws RemoteException {
+ TestListenerService service = new TestListenerService();
+ INotificationManager noMan = service.getNoMan();
+ when(noMan.getActiveNotificationsFromListener(any(), any(), anyInt()))
+ .thenThrow(new BadParcelableException("oops", new DeadObjectException("")));
+
+ assertNotNull(service.getActiveNotifications());
+ assertNotNull(service.getActiveNotifications(NotificationListenerService.TRIM_FULL));
+ assertNotNull(service.getActiveNotifications(new String[0]));
+ assertNull(service.getActiveNotifications(
+ new String[0], NotificationListenerService.TRIM_LIGHT));
+ }
+
+ @Test
public void testGetActiveNotifications_preP_mapsExtraPeople() throws RemoteException {
TestListenerService service = new TestListenerService();
service.attachBaseContext(mContext);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 177d64555899..dd252f3ffd20 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -60,6 +60,7 @@ import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.time.Instant;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -407,6 +408,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.userModifiedFields = 16;
rule.iconResName = ICON_RES_NAME;
rule.triggerDescription = TRIGGER_DESC;
+ rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
Parcel parcel = Parcel.obtain();
rule.writeToParcel(parcel, 0);
@@ -432,9 +434,10 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.userModifiedFields, parceled.userModifiedFields);
assertEquals(rule.triggerDescription, parceled.triggerDescription);
assertEquals(rule.zenPolicy, parceled.zenPolicy);
+ assertEquals(rule.deletionInstant, parceled.deletionInstant);
+
assertEquals(rule, parceled);
assertEquals(rule.hashCode(), parceled.hashCode());
-
}
@Test
@@ -510,6 +513,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
rule.userModifiedFields = 4;
rule.iconResName = ICON_RES_NAME;
rule.triggerDescription = TRIGGER_DESC;
+ rule.deletionInstant = Instant.ofEpochMilli(1701790147000L);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
writeRuleXml(rule, baos);
@@ -539,6 +543,7 @@ public class ZenModeConfigTest extends UiServiceTestCase {
assertEquals(rule.userModifiedFields, fromXml.userModifiedFields);
assertEquals(rule.triggerDescription, fromXml.triggerDescription);
assertEquals(rule.iconResName, fromXml.iconResName);
+ assertEquals(rule.deletionInstant, fromXml.deletionInstant);
}
@Test
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
index 7e92e427b9a4..9d7cf53e62db 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeDiffTest.java
@@ -65,18 +65,22 @@ import java.util.Set;
@TestableLooper.RunWithLooper
public class ZenModeDiffTest extends UiServiceTestCase {
// Base set of exempt fields independent of fields that are enabled/disabled via flags.
- // version is not included in the diff; manual & automatic rules have special handling
+ // version is not included in the diff; manual & automatic rules have special handling;
+ // deleted rules are not included in the diff.
public static final Set<String> ZEN_MODE_CONFIG_EXEMPT_FIELDS =
- Set.of("version", "manualRule", "automaticRules");
+ android.app.Flags.modesApi()
+ ? Set.of("version", "manualRule", "automaticRules", "deletedRules")
+ : Set.of("version", "manualRule", "automaticRules");
// Differences for flagged fields are only generated if the flag is enabled.
- // TODO: b/310620812 - Remove this exempt list when flag is inlined.
+ // "Metadata" fields (userModifiedFields, deletionInstant) are not compared.
private static final Set<String> ZEN_RULE_EXEMPT_FIELDS =
android.app.Flags.modesApi()
- ? Set.of()
+ ? Set.of("userModifiedFields", "deletionInstant")
: Set.of(RuleDiff.FIELD_TYPE, RuleDiff.FIELD_TRIGGER_DESCRIPTION,
RuleDiff.FIELD_ICON_RES, RuleDiff.FIELD_ALLOW_MANUAL,
- RuleDiff.FIELD_ZEN_DEVICE_EFFECTS, RuleDiff.FIELD_USER_MODIFIED_FIELDS);
+ RuleDiff.FIELD_ZEN_DEVICE_EFFECTS, "userModifiedFields",
+ "deletionInstant");
// allowPriorityChannels is flagged by android.app.modes_api
public static final Set<String> ZEN_MODE_CONFIG_FLAGGED_FIELDS =
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 0224ff35219b..9e3e336fa12f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -43,6 +43,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.provider.Settings.Global.ZEN_MODE_ALARMS;
import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
import static android.provider.Settings.Global.ZEN_MODE_OFF;
@@ -92,6 +93,7 @@ import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
+import android.Manifest;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.AppGlobals;
@@ -104,6 +106,7 @@ import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
@@ -116,6 +119,7 @@ import android.media.VolumePolicy;
import android.net.Uri;
import android.os.Parcel;
import android.os.Process;
+import android.os.SimpleClock;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.flag.junit.SetFlagsRule;
@@ -172,12 +176,16 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
+import java.time.Instant;
+import java.time.ZoneOffset;
+import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
@SmallTest
@SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service.
@@ -232,6 +240,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Mock PackageManager mPackageManager;
private Resources mResources;
private TestableLooper mTestableLooper;
+ private final TestClock mTestClock = new TestClock();
private ZenModeHelper mZenModeHelper;
private ContentResolver mContentResolver;
@Mock DeviceEffectsApplier mDeviceEffectsApplier;
@@ -269,7 +278,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
mConditionProviders.addSystemProvider(new CountdownConditionProvider());
mConditionProviders.addSystemProvider(new ScheduleConditionProvider());
mZenModeEventLogger = new ZenModeEventLoggerFake(mPackageManager);
- mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(),
+ mZenModeHelper = new ZenModeHelper(mContext, mTestableLooper.getLooper(), mTestClock,
mConditionProviders, mTestFlagResolver, mZenModeEventLogger);
ResolveInfo ri = new ResolveInfo();
@@ -1198,7 +1207,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
@Test
public void ruleUidAutomaticZenRuleRemovedUpdatesCache() throws Exception {
when(mContext.checkCallingPermission(anyString()))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
+ .thenReturn(PERMISSION_GRANTED);
setupZenConfig();
// one enabled automatic rule
@@ -1780,7 +1789,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void testDoNotUpdateModifiedDefaultAutoRule() {
// mDefaultConfig is set to default config in setup by getDefaultConfigParser
when(mContext.checkCallingPermission(anyString()))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
+ .thenReturn(PERMISSION_GRANTED);
// shouldn't update rule that's been modified
ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule();
@@ -1806,7 +1815,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
public void testDoNotUpdateEnabledDefaultAutoRule() {
// mDefaultConfig is set to default config in setup by getDefaultConfigParser
when(mContext.checkCallingPermission(anyString()))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
+ .thenReturn(PERMISSION_GRANTED);
// shouldn't update the rule that's enabled
ZenModeConfig.ZenRule updatedDefaultRule = new ZenModeConfig.ZenRule();
@@ -1833,7 +1842,7 @@ public class ZenModeHelperTest extends UiServiceTestCase {
// mDefaultConfig is set to default config in setup by getDefaultConfigParser
final String defaultRuleName = "rule name test";
when(mContext.checkCallingPermission(anyString()))
- .thenReturn(PackageManager.PERMISSION_GRANTED);
+ .thenReturn(PERMISSION_GRANTED);
// will update rule that is not enabled and modified
ZenModeConfig.ZenRule customDefaultRule = new ZenModeConfig.ZenRule();
@@ -4318,6 +4327,324 @@ public class ZenModeHelperTest extends UiServiceTestCase {
}
@Test
+ public void removeAndAddAutomaticZenRule_wasCustomized_isRestored() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ // Start with a rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mTestClock.setNowMillis(1000);
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build())
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000);
+ assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).canUpdate()).isTrue();
+
+ // User customizes it.
+ AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build())
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+ Process.SYSTEM_UID);
+
+ // App deletes it.
+ mTestClock.advanceByMillis(1000);
+ mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1);
+
+ // App adds it again.
+ mTestClock.advanceByMillis(1000);
+ String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+ // Verify that the rule was restored:
+ // - id and creation time is the same as the original one.
+ // - ZenPolicy is the one that the user had set.
+ // - rule still has the user-modified fields.
+ AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+ assertThat(finalRule.getCreationTime()).isEqualTo(1000); // And not 3000.
+ assertThat(newRuleId).isEqualTo(ruleId);
+ assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_ALARMS);
+ assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo(
+ ZenPolicy.STATE_ALLOW);
+ assertThat(finalRule.getUserModifiedFields()).isEqualTo(
+ AutomaticZenRule.FIELD_INTERRUPTION_FILTER);
+ assertThat(finalRule.getZenPolicy().getUserModifiedFields()).isEqualTo(
+ ZenPolicy.FIELD_PRIORITY_CATEGORY_REPEAT_CALLERS);
+
+ // Also, we discarded the "deleted rule" since we already used it for restoration.
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0);
+ }
+
+ @Test
+ public void removeAndAddAutomaticZenRule_wasNotCustomized_isNotRestored() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ // Start with a single rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mTestClock.setNowMillis(1000);
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build())
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000);
+
+ // App deletes it.
+ mTestClock.advanceByMillis(1000);
+ mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0);
+
+ // App adds it again.
+ mTestClock.advanceByMillis(1000);
+ String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+ // Verify that the rule was recreated. This means id and creation time are new.
+ AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+ assertThat(finalRule.getCreationTime()).isEqualTo(3000);
+ assertThat(newRuleId).isNotEqualTo(ruleId);
+ }
+
+ @Test
+ public void removeAndAddAutomaticZenRule_recreatedButNotByApp_isNotRestored() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ // Start with a single rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mTestClock.setNowMillis(1000);
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build())
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000);
+
+ // User customizes it.
+ mTestClock.advanceByMillis(1000);
+ AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build())
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+ Process.SYSTEM_UID);
+
+ // App deletes it.
+ mTestClock.advanceByMillis(1000);
+ mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_APP, "delete it",
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(1);
+
+ // User creates it again (unusual case, but ok).
+ mTestClock.advanceByMillis(1000);
+ String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_USER, "add it anew", CUSTOM_PKG_UID);
+
+ // Verify that the rule was recreated. This means id and creation time are new, and the rule
+ // matches the latest data supplied to addAZR.
+ AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+ assertThat(finalRule.getCreationTime()).isEqualTo(4000);
+ assertThat(newRuleId).isNotEqualTo(ruleId);
+ assertThat(finalRule.getInterruptionFilter()).isEqualTo(INTERRUPTION_FILTER_PRIORITY);
+ assertThat(finalRule.getZenPolicy().getPriorityCategoryRepeatCallers()).isEqualTo(
+ ZenPolicy.STATE_DISALLOW);
+
+ // Also, we discarded the "deleted rule" since we're not interested in recreating it.
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0);
+ }
+
+ @Test
+ public void removeAndAddAutomaticZenRule_removedByUser_isNotRestored() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+
+ // Start with a single rule.
+ mZenModeHelper.mConfig.automaticRules.clear();
+ mTestClock.setNowMillis(1000);
+ AutomaticZenRule rule = new AutomaticZenRule.Builder("Test", CONDITION_ID)
+ .setInterruptionFilter(INTERRUPTION_FILTER_PRIORITY)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(false).build())
+ .build();
+ String ruleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it", CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.getAutomaticZenRule(ruleId).getCreationTime()).isEqualTo(1000);
+
+ // User customizes it.
+ mTestClock.advanceByMillis(1000);
+ AutomaticZenRule userUpdate = new AutomaticZenRule.Builder(rule)
+ .setInterruptionFilter(INTERRUPTION_FILTER_ALARMS)
+ .setZenPolicy(new ZenPolicy.Builder().allowRepeatCallers(true).build())
+ .build();
+ mZenModeHelper.updateAutomaticZenRule(ruleId, userUpdate, UPDATE_ORIGIN_USER, "userUpdate",
+ Process.SYSTEM_UID);
+
+ // User deletes it.
+ mTestClock.advanceByMillis(1000);
+ mZenModeHelper.removeAutomaticZenRule(ruleId, UPDATE_ORIGIN_USER, "delete it",
+ CUSTOM_PKG_UID);
+ assertThat(mZenModeHelper.mConfig.automaticRules).hasSize(0);
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(0);
+
+ // App creates it again.
+ mTestClock.advanceByMillis(1000);
+ String newRuleId = mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(), rule,
+ UPDATE_ORIGIN_APP, "add it again", CUSTOM_PKG_UID);
+
+ // Verify that the rule was recreated. This means id and creation time are new.
+ AutomaticZenRule finalRule = mZenModeHelper.getAutomaticZenRule(newRuleId);
+ assertThat(finalRule.getCreationTime()).isEqualTo(4000);
+ assertThat(newRuleId).isNotEqualTo(ruleId);
+ }
+
+ @Test
+ public void removeAutomaticZenRule_preservedForRestoringByPackageAndConditionId() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mContext.getTestablePermissions().setPermission(Manifest.permission.MANAGE_NOTIFICATIONS,
+ PERMISSION_GRANTED); // So that canManageAZR passes although packages don't match.
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ // Start with a bunch of customized rules where conditionUris are not unique.
+ String id1 = mZenModeHelper.addAutomaticZenRule("pkg1",
+ new AutomaticZenRule.Builder("Test1", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+ String id2 = mZenModeHelper.addAutomaticZenRule("pkg1",
+ new AutomaticZenRule.Builder("Test2", Uri.parse("uri2")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+ String id3 = mZenModeHelper.addAutomaticZenRule("pkg1",
+ new AutomaticZenRule.Builder("Test3", Uri.parse("uri2")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+ String id4 = mZenModeHelper.addAutomaticZenRule("pkg2",
+ new AutomaticZenRule.Builder("Test4", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+ String id5 = mZenModeHelper.addAutomaticZenRule("pkg2",
+ new AutomaticZenRule.Builder("Test5", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+ for (ZenRule zenRule : mZenModeHelper.mConfig.automaticRules.values()) {
+ zenRule.userModifiedFields = AutomaticZenRule.FIELD_INTERRUPTION_FILTER;
+ }
+
+ mZenModeHelper.removeAutomaticZenRule(id1, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID);
+ mZenModeHelper.removeAutomaticZenRule(id2, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID);
+ mZenModeHelper.removeAutomaticZenRule(id3, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID);
+ mZenModeHelper.removeAutomaticZenRule(id4, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID);
+ mZenModeHelper.removeAutomaticZenRule(id5, UPDATE_ORIGIN_APP, "begone", CUSTOM_PKG_UID);
+
+ assertThat(mZenModeHelper.mConfig.deletedRules.keySet())
+ .containsExactly("pkg1|uri1", "pkg1|uri2", "pkg2|uri1");
+ assertThat(mZenModeHelper.mConfig.deletedRules.values().stream().map(zr -> zr.name)
+ .collect(Collectors.toList()))
+ .containsExactly("Test1", "Test3", "Test5");
+ }
+
+ @Test
+ public void removeAllZenRules_preservedForRestoring() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Test1", Uri.parse("uri1")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+ mZenModeHelper.addAutomaticZenRule(mContext.getPackageName(),
+ new AutomaticZenRule.Builder("Test2", Uri.parse("uri2")).build(), UPDATE_ORIGIN_APP,
+ "add it", CUSTOM_PKG_UID);
+
+ for (ZenRule zenRule : mZenModeHelper.mConfig.automaticRules.values()) {
+ zenRule.userModifiedFields = AutomaticZenRule.FIELD_INTERRUPTION_FILTER;
+ }
+
+ mZenModeHelper.removeAutomaticZenRules(mContext.getPackageName(), UPDATE_ORIGIN_APP,
+ "begone", CUSTOM_PKG_UID);
+
+ assertThat(mZenModeHelper.mConfig.deletedRules).hasSize(2);
+ }
+
+ @Test
+ public void removeAllZenRules_fromSystem_deletesPreservedRulesToo() {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ mZenModeHelper.mConfig.automaticRules.clear();
+
+ // Start with deleted rules from 2 different packages.
+ Instant now = Instant.ofEpochMilli(1701796461000L);
+ ZenRule pkg1Rule = newZenRule("pkg1", now.minus(1, ChronoUnit.DAYS), now);
+ ZenRule pkg2Rule = newZenRule("pkg2", now.minus(2, ChronoUnit.DAYS), now);
+ mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg1Rule), pkg1Rule);
+ mZenModeHelper.mConfig.deletedRules.put(ZenModeConfig.deletedRuleKey(pkg2Rule), pkg2Rule);
+
+ mZenModeHelper.removeAutomaticZenRules("pkg1",
+ UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI, "goodbye pkg1", Process.SYSTEM_UID);
+
+ // Preserved rules from pkg1 are gone; those from pkg2 are still there.
+ assertThat(mZenModeHelper.mConfig.deletedRules.values().stream().map(r -> r.pkg)
+ .collect(Collectors.toSet())).containsExactly("pkg2");
+ }
+
+ @Test
+ public void testRuleCleanup() throws Exception {
+ mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
+ Instant now = Instant.ofEpochMilli(1701796461000L);
+ Instant yesterday = now.minus(1, ChronoUnit.DAYS);
+ Instant aWeekAgo = now.minus(7, ChronoUnit.DAYS);
+ Instant twoMonthsAgo = now.minus(60, ChronoUnit.DAYS);
+ mTestClock.setNowMillis(now.toEpochMilli());
+
+ when(mPackageManager.getPackageInfo(eq("good_pkg"), anyInt()))
+ .thenReturn(new PackageInfo());
+ when(mPackageManager.getPackageInfo(eq("bad_pkg"), anyInt()))
+ .thenThrow(new PackageManager.NameNotFoundException("bad_pkg is not here"));
+
+ // Set up a config for another user containing:
+ ZenModeConfig config = new ZenModeConfig();
+ config.user = 42;
+ mZenModeHelper.mConfigs.put(42, config);
+ // okay rules (not deleted, package exists, with a range of creation dates).
+ config.automaticRules.put("ar1", newZenRule("good_pkg", now, null));
+ config.automaticRules.put("ar2", newZenRule("good_pkg", yesterday, null));
+ config.automaticRules.put("ar3", newZenRule("good_pkg", twoMonthsAgo, null));
+ // newish rules for a missing package
+ config.automaticRules.put("ar4", newZenRule("bad_pkg", yesterday, null));
+ // oldish rules belonging to a missing package
+ config.automaticRules.put("ar5", newZenRule("bad_pkg", aWeekAgo, null));
+ // rules deleted recently
+ config.deletedRules.put("del1", newZenRule("good_pkg", twoMonthsAgo, yesterday));
+ config.deletedRules.put("del2", newZenRule("good_pkg", twoMonthsAgo, aWeekAgo));
+ // rules deleted a long time ago
+ config.deletedRules.put("del3", newZenRule("good_pkg", twoMonthsAgo, twoMonthsAgo));
+ // rules for a missing package, created recently and deleted recently
+ config.deletedRules.put("del4", newZenRule("bad_pkg", yesterday, now));
+ // rules for a missing package, created a long time ago and deleted recently
+ config.deletedRules.put("del5", newZenRule("bad_pkg", twoMonthsAgo, now));
+ // rules for a missing package, created a long time ago and deleted a long time ago
+ config.deletedRules.put("del6", newZenRule("bad_pkg", twoMonthsAgo, twoMonthsAgo));
+
+ mZenModeHelper.onUserUnlocked(42); // copies config and cleans it up.
+
+ assertThat(mZenModeHelper.mConfig.automaticRules.keySet())
+ .containsExactly("ar1", "ar2", "ar3", "ar4");
+ assertThat(mZenModeHelper.mConfig.deletedRules.keySet())
+ .containsExactly("del1", "del2", "del4");
+ }
+
+ private static ZenRule newZenRule(String pkg, Instant createdAt, @Nullable Instant deletedAt) {
+ ZenRule rule = new ZenRule();
+ rule.pkg = pkg;
+ rule.creationTime = createdAt.toEpochMilli();
+ rule.deletionInstant = deletedAt;
+ // Plus stuff so that isValidAutomaticRule() passes
+ rule.name = "A rule from " + pkg + " created on " + createdAt;
+ rule.conditionId = Uri.parse(rule.name);
+ return rule;
+ }
+
+ @Test
public void applyGlobalZenModeAsImplicitZenRule_createsImplicitRuleAndActivatesIt() {
mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API);
mZenModeHelper.mConfig.automaticRules.clear();
@@ -4919,4 +5246,25 @@ public class ZenModeHelperTest extends UiServiceTestCase {
return parser.nextTag();
}
}
+
+ private static class TestClock extends SimpleClock {
+ private long mNowMillis = 441644400000L;
+
+ private TestClock() {
+ super(ZoneOffset.UTC);
+ }
+
+ @Override
+ public long millis() {
+ return mNowMillis;
+ }
+
+ private void setNowMillis(long millis) {
+ mNowMillis = millis;
+ }
+
+ private void advanceByMillis(long millis) {
+ mNowMillis += millis;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index f5282cb492f0..9bb2da0ff70c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -3309,7 +3309,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// keyguard to back to the app, expect IME insets is not frozen
app.mActivityRecord.commitVisibility(true, false);
mDisplayContent.updateImeInputAndControlTarget(app);
- mDisplayContent.mWmService.mRoot.performSurfacePlacement();
+ performSurfacePlacementAndWaitForWindowAnimator();
assertFalse(app.mActivityRecord.mImeInsetsFrozenUntilStartInput);
@@ -3358,7 +3358,7 @@ public class ActivityRecordTests extends WindowTestsBase {
mDisplayContent.setImeLayeringTarget(app2);
app2.mActivityRecord.commitVisibility(true, false);
mDisplayContent.updateImeInputAndControlTarget(app2);
- mDisplayContent.mWmService.mRoot.performSurfacePlacement();
+ performSurfacePlacementAndWaitForWindowAnimator();
// Verify after unfreezing app2's IME insets state, we won't dispatch visible IME insets
// to client if the app didn't request IME visible.
@@ -3412,7 +3412,7 @@ public class ActivityRecordTests extends WindowTestsBase {
// frozen until the input started.
mDisplayContent.setImeLayeringTarget(app1);
mDisplayContent.updateImeInputAndControlTarget(app1);
- mDisplayContent.mWmService.mRoot.performSurfacePlacement();
+ performSurfacePlacementAndWaitForWindowAnimator();
assertEquals(app1, mDisplayContent.getImeInputTarget());
assertFalse(activity1.mImeInsetsFrozenUntilStartInput);
diff --git a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
index 8bd54731c7c2..2d3c4bbe8bdc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SplashScreenExceptionListTest.java
@@ -28,6 +28,7 @@ import android.os.HandlerExecutor;
import android.os.Looper;
import android.platform.test.annotations.Presubmit;
import android.provider.DeviceConfig;
+import android.util.Log;
import androidx.test.filters.MediumTest;
@@ -147,6 +148,8 @@ public class SplashScreenExceptionListTest {
private void setExceptionListAndWaitForCallback(String commaSeparatedList) {
CountDownLatch latch = new CountDownLatch(1);
mOnUpdateDeviceConfig = rawList -> {
+ Log.i(getClass().getSimpleName(), "updateDeviceConfig expected="
+ + commaSeparatedList + " actual=" + rawList);
if (commaSeparatedList.equals(rawList)) {
latch.countDown();
}
@@ -155,7 +158,7 @@ public class SplashScreenExceptionListTest {
KEY_SPLASH_SCREEN_EXCEPTION_LIST, commaSeparatedList, false);
try {
assertTrue("Timed out waiting for DeviceConfig to be updated.",
- latch.await(1, TimeUnit.SECONDS));
+ latch.await(5, TimeUnit.SECONDS));
} catch (InterruptedException e) {
Assert.fail(e.getMessage());
}
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 60e84b03ec89..9c421ba29796 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -1054,6 +1054,19 @@ class WindowTestsBase extends SystemServiceTestsBase {
}
/**
+ * Performs surface placement and waits for WindowAnimator to complete the frame. It is used
+ * to execute the callbacks if the surface placement is expected to add some callbacks via
+ * {@link WindowAnimator#addAfterPrepareSurfacesRunnable}.
+ */
+ void performSurfacePlacementAndWaitForWindowAnimator() {
+ mWm.mAnimator.ready();
+ if (!mWm.mWindowPlacerLocked.isTraversalScheduled()) {
+ mRootWindowContainer.performSurfacePlacement();
+ }
+ waitUntilWindowAnimatorIdle();
+ }
+
+ /**
* Avoids rotating screen disturbed by some conditions. It is usually used for the default
* display that is not the instance of {@link TestDisplayContent} (it bypasses the conditions).
*
diff --git a/services/usb/lint-baseline.xml b/services/usb/lint-baseline.xml
index c2c0a350d5ad..62a2ee56a0cf 100644
--- a/services/usb/lint-baseline.xml
+++ b/services/usb/lint-baseline.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 7.1.0-dev" type="baseline" client="" dependencies="true" name="" variant="all" version="7.1.0-dev">
+<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NonUserGetterCalled"
@@ -12,4 +12,4 @@
column="42"/>
</issue>
-</issues>
+</issues> \ No newline at end of file
diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
index 250c3a54c928..2a6ac98b4d98 100644
--- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java
@@ -196,7 +196,7 @@ public final class TelephonyPermissions {
// We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
// revoked.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
+ return appOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
}
@@ -249,7 +249,7 @@ public final class TelephonyPermissions {
// We have READ_PHONE_STATE permission, so return true as long as the AppOps bit hasn't been
// revoked.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- return appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
+ return appOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_PHONE_STATE, uid, callingPackage,
callingFeatureId, null) == AppOpsManager.MODE_ALLOWED;
}
@@ -521,7 +521,7 @@ public final class TelephonyPermissions {
// We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
// revoked.
AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
- return appOps.noteOp(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage,
+ return appOps.noteOpNoThrow(AppOpsManager.OPSTR_READ_CALL_LOG, uid, callingPackage,
callingPackageName, null) == AppOpsManager.MODE_ALLOWED;
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 56156024fbab..a5c6d57aed82 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1315,7 +1315,7 @@ public class SubscriptionManager {
* A source of phone number: the EF-MSISDN (see 3GPP TS 31.102),
* or EF-MDN for CDMA (see 3GPP2 C.P0065-B), from UICC application.
*
- * <p>The availability and a of the number depends on the carrier.
+ * <p>The availability and accuracy of the number depends on the carrier.
* The number may be updated by over-the-air update to UICC applications
* from the carrier, or by other means with physical access to the SIM.
*/
@@ -1557,12 +1557,21 @@ public class SubscriptionManager {
* caller can see all subscription across user profiles as it does today today even if it's
* {@code false}.
*/
- private boolean mIsForAllUserProfiles = false;
+ private final boolean mIsForAllUserProfiles;
/** @hide */
@UnsupportedAppUsage
public SubscriptionManager(Context context) {
- if (DBG) logd("SubscriptionManager created");
+ this(context, false /*isForAllUserProfiles*/);
+ }
+
+ /** Constructor */
+ private SubscriptionManager(Context context, boolean isForAllUserProfiles) {
+ if (DBG) {
+ logd("SubscriptionManager created "
+ + (isForAllUserProfiles ? "for all user profile" : ""));
+ }
+ mIsForAllUserProfiles = isForAllUserProfiles;
mContext = context;
}
@@ -1998,7 +2007,7 @@ public class SubscriptionManager {
}
/**
- * Convert this subscription manager instance into one that can see all subscriptions across
+ * Create a new subscription manager instance that can see all subscriptions across
* user profiles.
*
* @return a SubscriptionManager that can see all subscriptions regardless its user profile
@@ -2008,13 +2017,12 @@ public class SubscriptionManager {
* @see #getActiveSubscriptionInfoCount
* @see UserHandle
*/
- @FlaggedApi(Flags.FLAG_WORK_PROFILE_API_SPLIT)
+ @FlaggedApi(Flags.FLAG_ENFORCE_SUBSCRIPTION_USER_FILTER)
// @RequiresPermission(TODO(b/308809058))
// The permission check for accessing all subscriptions will be enforced upon calling the
// individual APIs linked above.
@NonNull public SubscriptionManager createForAllUserProfiles() {
- mIsForAllUserProfiles = true;
- return this;
+ return new SubscriptionManager(mContext, true/*isForAllUserProfiles*/);
}
/**
diff --git a/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java b/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java
index fee1b25f04e5..2bc056ee743f 100644
--- a/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java
+++ b/tests/BinaryTransparencyHostTest/test-app/src/android/transparency/test/app/BinaryTransparencyTest.java
@@ -16,9 +16,6 @@
package android.transparency.test.app;
-import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
-import static android.Manifest.permission.QUERY_ALL_PACKAGES;
-
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -30,7 +27,6 @@ import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.internal.os.IBinaryTransparencyService.AppInfo;
import org.junit.Before;
@@ -120,13 +116,7 @@ public class BinaryTransparencyTest {
@Test
public void testCollectAllSilentInstalledMbaInfo() {
// Action
- var appInfoList =
- ShellIdentityUtils.invokeMethodWithShellPermissions(
- mBt,
- (Bt) ->
- mBt.collectAllSilentInstalledMbaInfo(new Bundle()),
- QUERY_ALL_PACKAGES,
- INTERACT_ACROSS_USERS_FULL);
+ var appInfoList = mBt.collectAllSilentInstalledMbaInfo(new Bundle());
// Verify
assertThat(appInfoList).isNotEmpty(); // because we just installed from the host side
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java
index 29cbf01dc6da..e3988cd20199 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityEmbeddingSecondaryActivity.java
@@ -24,8 +24,8 @@ import android.os.Bundle;
import android.view.View;
import android.widget.ToggleButton;
+import androidx.window.embedding.ActivityEmbeddingController;
import androidx.window.embedding.SplitAttributes;
-import androidx.window.embedding.SplitAttributesCalculatorParams;
import androidx.window.embedding.SplitController;
/**
@@ -66,7 +66,9 @@ public class ActivityEmbeddingSecondaryActivity extends Activity {
@Override
public void onClick(View v) {
// This triggers a recalcuation of splitatributes.
- mSplitController.invalidateTopVisibleSplitAttributes();
+ ActivityEmbeddingController
+ .getInstance(ActivityEmbeddingSecondaryActivity.this)
+ .invalidateTopVisibleActivityStacks();
}
});
findViewById(R.id.secondary_enter_pip_button).setOnClickListener(
diff --git a/tests/SurfaceControlViewHostTest/AndroidManifest.xml b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
index e50cbc52a5b8..71f01ac5ded1 100644
--- a/tests/SurfaceControlViewHostTest/AndroidManifest.xml
+++ b/tests/SurfaceControlViewHostTest/AndroidManifest.xml
@@ -32,6 +32,16 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+
+ <activity android:name="SurfaceInputTestActivity"
+ android:label="Surface Input Test"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
<service android:name=".EmbeddedWindowService"
android:process="com.android.test.viewembed.embedded_process"/>
</application>
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
index abc15b49ad98..5aaf30a5b3a7 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/EmbeddedWindowService.java
@@ -23,15 +23,21 @@ import android.annotation.Nullable;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.RemoteException;
+import android.util.Log;
+import android.view.Choreographer;
import android.view.Display;
import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -43,6 +49,9 @@ public class EmbeddedWindowService extends Service {
private Handler mHandler;
+ private IBinder mInputToken;
+ private SurfaceControl mSurfaceControl;
+
@Override
public void onCreate() {
super.onCreate();
@@ -101,9 +110,49 @@ public class EmbeddedWindowService extends Service {
}
});
}
+
@Override
public void relayout(WindowManager.LayoutParams lp) {
mHandler.post(() -> mVr.relayout(lp));
}
+
+ @Override
+ public void attachEmbeddedSurfaceControl(SurfaceControl parentSc, int displayId,
+ IBinder hostToken) {
+ mHandler.post(() -> {
+ Paint paint = new Paint();
+ paint.setTextSize(40);
+ paint.setColor(Color.WHITE);
+
+ mSurfaceControl = new SurfaceControl.Builder().setName("Child SurfaceControl")
+ .setParent(parentSc).setBufferSize(500, 500).build();
+ new SurfaceControl.Transaction().show(mSurfaceControl).apply();
+
+ Surface surface = new Surface(mSurfaceControl);
+ Canvas c = surface.lockCanvas(null);
+ c.drawColor(Color.BLUE);
+ c.drawText("Remote", 250, 250, paint);
+ surface.unlockCanvasAndPost(c);
+ WindowManager wm = getSystemService(WindowManager.class);
+ mInputToken = wm.registerBatchedSurfaceControlInputReceiver(displayId, hostToken,
+ mSurfaceControl,
+ Choreographer.getInstance(), event -> {
+ Log.d(TAG, "onInputEvent-remote " + event);
+ return false;
+ });
+
+ });
+ }
+
+ @Override
+ public void tearDownEmbeddedSurfaceControl() {
+ if (mSurfaceControl != null) {
+ new SurfaceControl.Transaction().remove(mSurfaceControl);
+ }
+ if (mInputToken != null) {
+ WindowManager wm = getSystemService(WindowManager.class);
+ wm.unregisterSurfaceControlInputReceiver(mInputToken);
+ }
+ }
}
}
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
index 9e9faf03ba1c..6b65b40ef8c6 100644
--- a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/IAttachEmbeddedWindow.aidl
@@ -19,8 +19,11 @@ package com.android.test.viewembed;
import android.os.IBinder;
import com.android.test.viewembed.IAttachEmbeddedWindowCallback;
import android.view.WindowManager.LayoutParams;
+import android.view.SurfaceControl;
interface IAttachEmbeddedWindow {
void attachEmbedded(IBinder hostToken, int width, int height, in IAttachEmbeddedWindowCallback callback);
void relayout(in LayoutParams lp);
+ oneway void attachEmbeddedSurfaceControl(in SurfaceControl parentSurfaceControl, int displayId, IBinder hostToken);
+ oneway void tearDownEmbeddedSurfaceControl();
} \ No newline at end of file
diff --git a/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
new file mode 100644
index 000000000000..e5f8f47aeecd
--- /dev/null
+++ b/tests/SurfaceControlViewHostTest/src/com/android/test/viewembed/SurfaceInputTestActivity.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.viewembed;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.AttachedSurfaceControl;
+import android.view.Choreographer;
+import android.view.Gravity;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.ViewTreeObserver;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+
+/**
+ * Used to manually test that {@link android.view.SurfaceControlInputReceiver} API works.
+ */
+public class SurfaceInputTestActivity extends Activity {
+
+ private static final String TAG = "SurfaceInputTestActivity";
+ private SurfaceView mLocalSurfaceView;
+ private SurfaceView mRemoteSurfaceView;
+ private IBinder mInputToken;
+ private IAttachEmbeddedWindow mIAttachEmbeddedWindow;
+ private SurfaceControl mParentSurfaceControl;
+
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ // Called when the connection with the service is established
+ public void onServiceConnected(ComponentName className, IBinder service) {
+ Log.d(TAG, "Service Connected");
+ mIAttachEmbeddedWindow = IAttachEmbeddedWindow.Stub.asInterface(service);
+ loadEmbedded();
+ }
+
+ public void onServiceDisconnected(ComponentName className) {
+ Log.d(TAG, "Service Disconnected");
+ mIAttachEmbeddedWindow = null;
+ }
+ };
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver();
+ viewTreeObserver.addOnPreDrawListener(
+ new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ addLocalChildSurfaceControl(getWindow().getRootSurfaceControl());
+ viewTreeObserver.removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ LinearLayout content = new LinearLayout(this);
+ mLocalSurfaceView = new SurfaceView(this);
+ content.addView(mLocalSurfaceView, new LinearLayout.LayoutParams(
+ 500, 500, Gravity.CENTER_HORIZONTAL | Gravity.TOP));
+
+ mRemoteSurfaceView = new SurfaceView(this);
+ content.addView(mRemoteSurfaceView, new LinearLayout.LayoutParams(
+ 500, 500, Gravity.CENTER_HORIZONTAL | Gravity.TOP));
+
+ setContentView(content);
+
+ mLocalSurfaceView.setZOrderOnTop(true);
+ mLocalSurfaceView.getHolder().addCallback(mLocalSurfaceViewCallback);
+
+ mRemoteSurfaceView.setZOrderOnTop(true);
+ mRemoteSurfaceView.getHolder().addCallback(mRemoteSurfaceViewHolder);
+
+ Intent intent = new Intent(this, EmbeddedWindowService.class);
+ intent.setAction(IAttachEmbeddedWindow.class.getName());
+ Log.d(TAG, "bindService");
+ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken);
+ }
+
+ private void addLocalChildSurfaceControl(AttachedSurfaceControl attachedSurfaceControl) {
+ SurfaceControl surfaceControl = new SurfaceControl.Builder().setName("LocalSC")
+ .setBufferSize(100, 100).build();
+ attachedSurfaceControl.buildReparentTransaction(surfaceControl)
+ .setVisibility(surfaceControl, true)
+ .setCrop(surfaceControl, new Rect(0, 0, 100, 100))
+ .setPosition(surfaceControl, 250, 1000)
+ .setLayer(surfaceControl, 1).apply();
+
+ Paint paint = new Paint();
+ paint.setColor(Color.WHITE);
+ paint.setTextSize(20);
+
+ Surface surface = new Surface(surfaceControl);
+ Canvas c = surface.lockCanvas(null);
+ c.drawColor(Color.GREEN);
+ c.drawText("Local SC", 0, 0, paint);
+ surface.unlockCanvasAndPost(c);
+ WindowManager wm = getSystemService(WindowManager.class);
+ mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
+ attachedSurfaceControl.getHostToken(), surfaceControl,
+ Choreographer.getInstance(), event -> {
+ Log.d(TAG, "onInputEvent-sc " + event);
+ return false;
+ });
+ }
+
+ private final SurfaceHolder.Callback mLocalSurfaceViewCallback = new SurfaceHolder.Callback() {
+ private IBinder mInputToken;
+
+ @Override
+ public void surfaceCreated(@NonNull SurfaceHolder holder) {
+ Paint paint = new Paint();
+ paint.setColor(Color.WHITE);
+ paint.setTextSize(40);
+
+ Canvas c = holder.lockCanvas();
+ c.drawColor(Color.RED);
+ c.drawText("Local", 250, 250, paint);
+ holder.unlockCanvasAndPost(c);
+
+ WindowManager wm = getSystemService(WindowManager.class);
+ mInputToken = wm.registerBatchedSurfaceControlInputReceiver(getDisplayId(),
+ mLocalSurfaceView.getHostToken(), mLocalSurfaceView.getSurfaceControl(),
+ Choreographer.getInstance(), event -> {
+ Log.d(TAG, "onInputEvent-local " + event);
+ return false;
+ });
+ }
+
+ @Override
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
+
+ }
+
+ @Override
+ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
+ if (mInputToken != null) {
+ getWindowManager().unregisterSurfaceControlInputReceiver(mInputToken);
+ }
+ }
+ };
+
+ private final SurfaceHolder.Callback mRemoteSurfaceViewHolder = new SurfaceHolder.Callback() {
+ @Override
+ public void surfaceCreated(@NonNull SurfaceHolder holder) {
+ mParentSurfaceControl = mRemoteSurfaceView.getSurfaceControl();
+ loadEmbedded();
+ }
+
+ @Override
+ public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
+ int height) {
+ }
+
+ @Override
+ public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
+ if (mIAttachEmbeddedWindow != null) {
+ try {
+ mIAttachEmbeddedWindow.tearDownEmbeddedSurfaceControl();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to tear down embedded SurfaceControl", e);
+ }
+ }
+ }
+ };
+
+ private void loadEmbedded() {
+ if (mParentSurfaceControl == null || mIAttachEmbeddedWindow == null) {
+ return;
+ }
+ try {
+ mIAttachEmbeddedWindow.attachEmbeddedSurfaceControl(mParentSurfaceControl,
+ getDisplayId(), mRemoteSurfaceView.getHostToken());
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to load embedded SurfaceControl", e);
+ }
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
new file mode 100644
index 000000000000..9daba6a79a27
--- /dev/null
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/IpSecPacketLossDetectorTest.java
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vcn.routeselection;
+
+import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY;
+import static android.net.vcn.VcnManager.VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY;
+
+import static com.android.server.vcn.routeselection.IpSecPacketLossDetector.PACKET_LOSS_UNAVALAIBLE;
+import static com.android.server.vcn.util.PersistableBundleUtils.PersistableBundleWrapper;
+
+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.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.net.IpSecTransformState;
+import android.os.OutcomeReceiver;
+import android.os.PowerManager;
+
+import com.android.server.vcn.routeselection.IpSecPacketLossDetector.PacketLossCalculator;
+import com.android.server.vcn.routeselection.NetworkMetricMonitor.IpSecTransformWrapper;
+import com.android.server.vcn.routeselection.NetworkMetricMonitor.NetworkMetricMonitorCallback;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.Spy;
+
+import java.util.Arrays;
+import java.util.BitSet;
+import java.util.concurrent.TimeUnit;
+
+public class IpSecPacketLossDetectorTest extends NetworkEvaluationTestBase {
+ private static final String TAG = IpSecPacketLossDetectorTest.class.getSimpleName();
+
+ private static final int REPLAY_BITMAP_LEN_BYTE = 512;
+ private static final int REPLAY_BITMAP_LEN_BIT = REPLAY_BITMAP_LEN_BYTE * 8;
+ private static final int IPSEC_PACKET_LOSS_PERCENT_THRESHOLD = 5;
+ private static final long POLL_IPSEC_STATE_INTERVAL_MS = TimeUnit.SECONDS.toMillis(30L);
+
+ @Mock private IpSecTransformWrapper mIpSecTransform;
+ @Mock private NetworkMetricMonitorCallback mMetricMonitorCallback;
+ @Mock private PersistableBundleWrapper mCarrierConfig;
+ @Mock private IpSecPacketLossDetector.Dependencies mDependencies;
+ @Spy private PacketLossCalculator mPacketLossCalculator = new PacketLossCalculator();
+
+ @Captor private ArgumentCaptor<OutcomeReceiver> mTransformStateReceiverCaptor;
+ @Captor private ArgumentCaptor<BroadcastReceiver> mBroadcastReceiverCaptor;
+
+ private IpSecPacketLossDetector mIpSecPacketLossDetector;
+ private IpSecTransformState mTransformStateInitial;
+
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ mTransformStateInitial = newTransformState(0, 0, newReplayBitmap(0));
+
+ when(mCarrierConfig.getInt(
+ eq(VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY), anyInt()))
+ .thenReturn((int) TimeUnit.MILLISECONDS.toSeconds(POLL_IPSEC_STATE_INTERVAL_MS));
+ when(mCarrierConfig.getInt(
+ eq(VCN_NETWORK_SELECTION_IPSEC_PACKET_LOSS_PERCENT_THRESHOLD_KEY),
+ anyInt()))
+ .thenReturn(IPSEC_PACKET_LOSS_PERCENT_THRESHOLD);
+
+ when(mDependencies.getPacketLossCalculator()).thenReturn(mPacketLossCalculator);
+
+ mIpSecPacketLossDetector =
+ new IpSecPacketLossDetector(
+ mVcnContext,
+ mNetwork,
+ mCarrierConfig,
+ mMetricMonitorCallback,
+ mDependencies);
+ }
+
+ private static IpSecTransformState newTransformState(
+ long rxSeqNo, long packtCount, byte[] replayBitmap) {
+ return new IpSecTransformState.Builder()
+ .setRxHighestSequenceNumber(rxSeqNo)
+ .setPacketCount(packtCount)
+ .setReplayBitmap(replayBitmap)
+ .build();
+ }
+
+ private static byte[] newReplayBitmap(int receivedPktCnt) {
+ final BitSet bitSet = new BitSet(REPLAY_BITMAP_LEN_BIT);
+ for (int i = 0; i < receivedPktCnt; i++) {
+ bitSet.set(i);
+ }
+ return Arrays.copyOf(bitSet.toByteArray(), REPLAY_BITMAP_LEN_BYTE);
+ }
+
+ private void verifyStopped() {
+ assertFalse(mIpSecPacketLossDetector.isStarted());
+ assertFalse(mIpSecPacketLossDetector.isValidationFailed());
+ assertNull(mIpSecPacketLossDetector.getLastTransformState());
+
+ // No event scheduled
+ mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS);
+ assertNull(mTestLooper.nextMessage());
+ }
+
+ @Test
+ public void testInitialization() throws Exception {
+ assertFalse(mIpSecPacketLossDetector.isSelectedUnderlyingNetwork());
+ verifyStopped();
+ }
+
+ private OutcomeReceiver<IpSecTransformState, RuntimeException>
+ startMonitorAndCaptureStateReceiver() {
+ mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */);
+ mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform);
+
+ // Trigger the runnable
+ mTestLooper.dispatchAll();
+
+ verify(mIpSecTransform)
+ .getIpSecTransformState(any(), mTransformStateReceiverCaptor.capture());
+ return mTransformStateReceiverCaptor.getValue();
+ }
+
+ @Test
+ public void testStartMonitor() throws Exception {
+ final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
+ startMonitorAndCaptureStateReceiver();
+
+ assertTrue(mIpSecPacketLossDetector.isStarted());
+ assertFalse(mIpSecPacketLossDetector.isValidationFailed());
+ assertTrue(mIpSecPacketLossDetector.isSelectedUnderlyingNetwork());
+ assertEquals(mIpSecTransform, mIpSecPacketLossDetector.getInboundTransformInternal());
+
+ // Mock receiving a state
+ xfrmStateReceiver.onResult(mTransformStateInitial);
+
+ // Verify the first polled state is stored
+ assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState());
+ verify(mPacketLossCalculator, never())
+ .getPacketLossRatePercentage(any(), any(), anyString());
+
+ // Verify next poll is scheduled
+ assertNull(mTestLooper.nextMessage());
+ mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS);
+ assertNotNull(mTestLooper.nextMessage());
+ }
+
+ @Test
+ public void testStartedMonitor_enterDozeMoze() throws Exception {
+ final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
+ startMonitorAndCaptureStateReceiver();
+
+ // Mock receiving a state
+ xfrmStateReceiver.onResult(mTransformStateInitial);
+ assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState());
+
+ // Mock entering doze mode
+ final Intent intent = mock(Intent.class);
+ when(intent.getAction()).thenReturn(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
+ when(mPowerManagerService.isDeviceIdleMode()).thenReturn(true);
+
+ verify(mContext).registerReceiver(mBroadcastReceiverCaptor.capture(), any(), any(), any());
+ final BroadcastReceiver broadcastReceiver = mBroadcastReceiverCaptor.getValue();
+ broadcastReceiver.onReceive(mContext, intent);
+
+ assertNull(mIpSecPacketLossDetector.getLastTransformState());
+ }
+
+ @Test
+ public void testStartedMonitor_updateInboundTransform() throws Exception {
+ final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
+ startMonitorAndCaptureStateReceiver();
+
+ // Mock receiving a state
+ xfrmStateReceiver.onResult(mTransformStateInitial);
+ assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState());
+
+ // Update the inbound transform
+ final IpSecTransformWrapper newTransform = mock(IpSecTransformWrapper.class);
+ mIpSecPacketLossDetector.setInboundTransformInternal(newTransform);
+
+ // Verifications
+ assertNull(mIpSecPacketLossDetector.getLastTransformState());
+ mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS);
+ mTestLooper.dispatchAll();
+ verify(newTransform).getIpSecTransformState(any(), any());
+ }
+
+ @Test
+ public void testStartedMonitor_updateCarrierConfig() throws Exception {
+ startMonitorAndCaptureStateReceiver();
+
+ final int additionalPollIntervalMs = (int) TimeUnit.SECONDS.toMillis(10L);
+ when(mCarrierConfig.getInt(
+ eq(VCN_NETWORK_SELECTION_POLL_IPSEC_STATE_INTERVAL_SECONDS_KEY), anyInt()))
+ .thenReturn(
+ (int)
+ TimeUnit.MILLISECONDS.toSeconds(
+ POLL_IPSEC_STATE_INTERVAL_MS + additionalPollIntervalMs));
+ mIpSecPacketLossDetector.setCarrierConfig(mCarrierConfig);
+ mTestLooper.dispatchAll();
+
+ // The already scheduled event is still fired with the old timeout
+ mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS);
+ mTestLooper.dispatchAll();
+
+ // The next scheduled event will take 10 more seconds to fire
+ mTestLooper.moveTimeForward(POLL_IPSEC_STATE_INTERVAL_MS);
+ assertNull(mTestLooper.nextMessage());
+ mTestLooper.moveTimeForward(additionalPollIntervalMs);
+ assertNotNull(mTestLooper.nextMessage());
+ }
+
+ @Test
+ public void testStopMonitor() throws Exception {
+ mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */);
+ mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform);
+
+ assertTrue(mIpSecPacketLossDetector.isStarted());
+ assertNotNull(mTestLooper.nextMessage());
+
+ // Unselect the monitor
+ mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(false /* setIsSelected */);
+ verifyStopped();
+ }
+
+ @Test
+ public void testClose() throws Exception {
+ mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(true /* setIsSelected */);
+ mIpSecPacketLossDetector.setInboundTransformInternal(mIpSecTransform);
+
+ assertTrue(mIpSecPacketLossDetector.isStarted());
+ assertNotNull(mTestLooper.nextMessage());
+
+ // Stop the monitor
+ mIpSecPacketLossDetector.close();
+ verifyStopped();
+ verify(mIpSecTransform).close();
+ }
+
+ @Test
+ public void testTransformStateReceiverOnResultWhenStopped() throws Exception {
+ final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
+ startMonitorAndCaptureStateReceiver();
+ xfrmStateReceiver.onResult(mTransformStateInitial);
+
+ // Unselect the monitor
+ mIpSecPacketLossDetector.setIsSelectedUnderlyingNetwork(false /* setIsSelected */);
+ verifyStopped();
+
+ xfrmStateReceiver.onResult(newTransformState(1, 1, newReplayBitmap(1)));
+ verify(mPacketLossCalculator, never())
+ .getPacketLossRatePercentage(any(), any(), anyString());
+ }
+
+ @Test
+ public void testTransformStateReceiverOnError() throws Exception {
+ final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
+ startMonitorAndCaptureStateReceiver();
+ xfrmStateReceiver.onResult(mTransformStateInitial);
+
+ xfrmStateReceiver.onError(new RuntimeException("Test"));
+ verify(mPacketLossCalculator, never())
+ .getPacketLossRatePercentage(any(), any(), anyString());
+ }
+
+ private void checkHandleLossRate(
+ int mockPacketLossRate, boolean isLastStateExpectedToUpdate, boolean isCallbackExpected)
+ throws Exception {
+ final OutcomeReceiver<IpSecTransformState, RuntimeException> xfrmStateReceiver =
+ startMonitorAndCaptureStateReceiver();
+ doReturn(mockPacketLossRate)
+ .when(mPacketLossCalculator)
+ .getPacketLossRatePercentage(any(), any(), anyString());
+
+ // Mock receiving two states with mTransformStateInitial and an arbitrary transformNew
+ final IpSecTransformState transformNew = newTransformState(1, 1, newReplayBitmap(1));
+ xfrmStateReceiver.onResult(mTransformStateInitial);
+ xfrmStateReceiver.onResult(transformNew);
+
+ // Verifications
+ verify(mPacketLossCalculator)
+ .getPacketLossRatePercentage(
+ eq(mTransformStateInitial), eq(transformNew), anyString());
+
+ if (isLastStateExpectedToUpdate) {
+ assertEquals(transformNew, mIpSecPacketLossDetector.getLastTransformState());
+ } else {
+ assertEquals(mTransformStateInitial, mIpSecPacketLossDetector.getLastTransformState());
+ }
+
+ if (isCallbackExpected) {
+ verify(mMetricMonitorCallback).onValidationResultReceived();
+ } else {
+ verify(mMetricMonitorCallback, never()).onValidationResultReceived();
+ }
+ }
+
+ @Test
+ public void testHandleLossRate_validationPass() throws Exception {
+ checkHandleLossRate(
+ 2, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */);
+ }
+
+ @Test
+ public void testHandleLossRate_validationFail() throws Exception {
+ checkHandleLossRate(
+ 22, true /* isLastStateExpectedToUpdate */, true /* isCallbackExpected */);
+ }
+
+ @Test
+ public void testHandleLossRate_resultUnavalaible() throws Exception {
+ checkHandleLossRate(
+ PACKET_LOSS_UNAVALAIBLE,
+ false /* isLastStateExpectedToUpdate */,
+ false /* isCallbackExpected */);
+ }
+
+ private void checkGetPacketLossRate(
+ IpSecTransformState oldState, IpSecTransformState newState, int expectedLossRate)
+ throws Exception {
+ assertEquals(
+ expectedLossRate,
+ mPacketLossCalculator.getPacketLossRatePercentage(oldState, newState, TAG));
+ }
+
+ private void checkGetPacketLossRate(
+ IpSecTransformState oldState,
+ int rxSeqNo,
+ int packetCount,
+ int packetInWin,
+ int expectedDataLossRate)
+ throws Exception {
+ final IpSecTransformState newState =
+ newTransformState(rxSeqNo, packetCount, newReplayBitmap(packetInWin));
+ checkGetPacketLossRate(oldState, newState, expectedDataLossRate);
+ }
+
+ @Test
+ public void testGetPacketLossRate_replayWindowUnchanged() throws Exception {
+ checkGetPacketLossRate(
+ mTransformStateInitial, mTransformStateInitial, PACKET_LOSS_UNAVALAIBLE);
+ checkGetPacketLossRate(mTransformStateInitial, 3000, 2000, 2000, PACKET_LOSS_UNAVALAIBLE);
+ }
+
+ @Test
+ public void testGetPacketLossRate_againstInitialState() throws Exception {
+ checkGetPacketLossRate(mTransformStateInitial, 7000, 7001, 4096, 0);
+ checkGetPacketLossRate(mTransformStateInitial, 7000, 6000, 4096, 15);
+ checkGetPacketLossRate(mTransformStateInitial, 7000, 6000, 4000, 14);
+ }
+
+ @Test
+ public void testGetPktLossRate_oldHiSeqSmallerThanWinSize_overlappedWithNewWin()
+ throws Exception {
+ final IpSecTransformState oldState = newTransformState(2000, 1500, newReplayBitmap(1500));
+
+ checkGetPacketLossRate(oldState, 5000, 5001, 4096, 0);
+ checkGetPacketLossRate(oldState, 5000, 4000, 4096, 29);
+ checkGetPacketLossRate(oldState, 5000, 4000, 4000, 27);
+ }
+
+ @Test
+ public void testGetPktLossRate_oldHiSeqSmallerThanWinSize_notOverlappedWithNewWin()
+ throws Exception {
+ final IpSecTransformState oldState = newTransformState(2000, 1500, newReplayBitmap(1500));
+
+ checkGetPacketLossRate(oldState, 7000, 7001, 4096, 0);
+ checkGetPacketLossRate(oldState, 7000, 5000, 4096, 37);
+ checkGetPacketLossRate(oldState, 7000, 5000, 3000, 21);
+ }
+
+ @Test
+ public void testGetPktLossRate_oldHiSeqLargerThanWinSize_overlappedWithNewWin()
+ throws Exception {
+ final IpSecTransformState oldState = newTransformState(10000, 5000, newReplayBitmap(3000));
+
+ checkGetPacketLossRate(oldState, 12000, 8096, 4096, 0);
+ checkGetPacketLossRate(oldState, 12000, 7000, 4096, 36);
+ checkGetPacketLossRate(oldState, 12000, 7000, 3000, 0);
+ }
+
+ @Test
+ public void testGetPktLossRate_oldHiSeqLargerThanWinSize_notOverlappedWithNewWin()
+ throws Exception {
+ final IpSecTransformState oldState = newTransformState(10000, 5000, newReplayBitmap(3000));
+
+ checkGetPacketLossRate(oldState, 20000, 16096, 4096, 0);
+ checkGetPacketLossRate(oldState, 20000, 14000, 4096, 19);
+ checkGetPacketLossRate(oldState, 20000, 14000, 3000, 10);
+ }
+}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
index bf84bbeeedad..355c22156a78 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkEvaluationTestBase.java
@@ -20,6 +20,7 @@ import static com.android.server.vcn.VcnTestUtils.setupSystemService;
import static com.android.server.vcn.routeselection.UnderlyingNetworkControllerTest.getLinkPropertiesWithName;
import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -29,7 +30,12 @@ import android.net.LinkProperties;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.TelephonyNetworkSpecifier;
+import android.net.vcn.FeatureFlags;
+import android.os.Handler;
+import android.os.IPowerManager;
+import android.os.IThermalService;
import android.os.ParcelUuid;
+import android.os.PowerManager;
import android.os.test.TestLooper;
import android.telephony.TelephonyManager;
@@ -90,32 +96,49 @@ public abstract class NetworkEvaluationTestBase {
protected static final LinkProperties LINK_PROPERTIES = getLinkPropertiesWithName("test_iface");
+ @Mock protected Context mContext;
@Mock protected Network mNetwork;
+ @Mock protected FeatureFlags mFeatureFlags;
+ @Mock protected com.android.net.flags.FeatureFlags mCoreNetFeatureFlags;
@Mock protected TelephonySubscriptionSnapshot mSubscriptionSnapshot;
@Mock protected TelephonyManager mTelephonyManager;
+ @Mock protected IPowerManager mPowerManagerService;
protected TestLooper mTestLooper;
protected VcnContext mVcnContext;
+ protected PowerManager mPowerManager;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- final Context mockContext = mock(Context.class);
+ when(mNetwork.getNetId()).thenReturn(-1);
+
mTestLooper = new TestLooper();
mVcnContext =
spy(
new VcnContext(
- mockContext,
+ mContext,
mTestLooper.getLooper(),
mock(VcnNetworkProvider.class),
false /* isInTestMode */));
doNothing().when(mVcnContext).ensureRunningOnLooperThread();
+ doReturn(true).when(mVcnContext).isFlagNetworkMetricMonitorEnabled();
+ doReturn(true).when(mVcnContext).isFlagIpSecTransformStateEnabled();
+
setupSystemService(
- mockContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
+ mContext, mTelephonyManager, Context.TELEPHONY_SERVICE, TelephonyManager.class);
when(mTelephonyManager.createForSubscriptionId(SUB_ID)).thenReturn(mTelephonyManager);
when(mTelephonyManager.getNetworkOperator()).thenReturn(PLMN_ID);
when(mTelephonyManager.getSimSpecificCarrierId()).thenReturn(CARRIER_ID);
+
+ mPowerManager =
+ new PowerManager(
+ mContext,
+ mPowerManagerService,
+ mock(IThermalService.class),
+ mock(Handler.class));
+ setupSystemService(mContext, mPowerManager, Context.POWER_SERVICE, PowerManager.class);
}
}
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
index dbf2f514fe89..d85c5150f53f 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/NetworkPriorityClassifierTest.java
@@ -57,7 +57,7 @@ public class NetworkPriorityClassifierTest extends NetworkEvaluationTestBase {
private UnderlyingNetworkRecord mCellNetworkRecord;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
super.setUp();
mWifiNetworkRecord = getTestNetworkRecord(WIFI_NETWORK_CAPABILITIES);
diff --git a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
index a4567ddc20a1..985e70c9771e 100644
--- a/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
+++ b/tests/vcn/java/com/android/server/vcn/routeselection/UnderlyingNetworkEvaluatorTest.java
@@ -34,7 +34,7 @@ public class UnderlyingNetworkEvaluatorTest extends NetworkEvaluationTestBase {
private PersistableBundleWrapper mCarrierConfig;
@Before
- public void setUp() {
+ public void setUp() throws Exception {
super.setUp();
mCarrierConfig = new PersistableBundleWrapper(new PersistableBundle());
}