summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/current.txt10
-rw-r--r--core/api/system-current.txt10
-rw-r--r--core/java/android/app/Notification.java31
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java11
-rw-r--r--core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java26
-rw-r--r--core/java/android/credentials/flags.aconfig10
-rw-r--r--core/java/android/hardware/contexthub/HubEndpoint.java4
-rw-r--r--core/java/android/hardware/contexthub/HubEndpointSession.java2
-rw-r--r--core/java/android/hardware/contexthub/HubMessage.java131
-rw-r--r--core/java/android/hardware/display/DisplayManager.java93
-rw-r--r--core/java/android/hardware/display/DisplayManagerGlobal.java26
-rw-r--r--core/java/android/hardware/input/InputManagerGlobal.java26
-rw-r--r--core/java/android/os/Build.java9
-rw-r--r--core/java/android/os/IHintManager.aidl8
-rw-r--r--core/java/android/os/UserManager.java6
-rw-r--r--core/java/com/android/internal/display/BrightnessSynchronizer.java2
-rw-r--r--core/java/com/android/internal/widget/NotificationExpandButton.java14
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java4
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java1
-rw-r--r--core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java5
-rw-r--r--core/res/res/drawable/ic_notification_2025_collapse.xml25
-rw-r--r--core/res/res/drawable/ic_notification_2025_expand.xml25
-rw-r--r--core/res/res/drawable/notification_2025_expand_button_pill_bg.xml29
-rw-r--r--core/res/res/layout/notification_2025_expand_button.xml61
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_base.xml5
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_call.xml5
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_media.xml5
-rw-r--r--core/res/res/layout/notification_2025_template_collapsed_messaging.xml5
-rw-r--r--core/res/res/layout/notification_2025_template_conversation.xml5
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_base.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_big_picture.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_big_text.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_call.xml2
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_inbox.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_media.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_messaging.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_expanded_progress.xml3
-rw-r--r--core/res/res/layout/notification_2025_template_header.xml9
-rw-r--r--core/res/res/values/dimens.xml23
-rw-r--r--core/res/res/values/strings.xml2
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java36
-rw-r--r--graphics/java/android/graphics/BlendModeColorFilter.java2
-rw-r--r--libs/WindowManager/Jetpack/src/androidx/window/extensions/area/RearDisplayPresentationRequestCallback.java11
-rw-r--r--libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml2
-rw-r--r--libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml5
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt5
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt5
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt110
-rw-r--r--libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java79
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java53
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java15
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt19
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java7
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java2
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java34
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java16
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java1
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopViaMenuOfStaticOverviewTaskTest.kt (renamed from nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl)11
-rw-r--r--libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopViaMenuOfStaticOverviewTask.kt70
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/Android.bp33
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt27
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt1
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipUtils.kt39
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfAutoEnterPipOnGoToHomeTest.kt170
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipOnUserLeaveHintTest.kt168
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipTransition.kt46
-rw-r--r--libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipViaAppUiButtonTest.kt101
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt5
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java20
-rw-r--r--media/java/android/media/projection/MediaProjection.java13
-rw-r--r--native/android/OWNERS3
-rw-r--r--native/android/libandroid.map.txt2
-rw-r--r--native/android/performance_hint.cpp332
-rw-r--r--native/android/tests/performance_hint/PerformanceHintNativeTest.cpp342
-rw-r--r--nfc/Android.bp79
-rw-r--r--nfc/OWNERS2
-rw-r--r--nfc/TEST_MAPPING13
-rw-r--r--nfc/api/current.txt495
-rw-r--r--nfc/api/lint-baseline.txt95
-rw-r--r--nfc/api/module-lib-current.txt10
-rw-r--r--nfc/api/module-lib-lint-baseline.txt93
-rw-r--r--nfc/api/module-lib-removed.txt1
-rw-r--r--nfc/api/removed.txt17
-rw-r--r--nfc/api/system-current.txt256
-rw-r--r--nfc/api/system-lint-baseline.txt119
-rw-r--r--nfc/api/system-removed.txt12
-rw-r--r--nfc/api/test-current.txt1
-rw-r--r--nfc/api/test-removed.txt1
-rw-r--r--nfc/jarjar-rules.txt38
-rw-r--r--nfc/java/android/nfc/ApduList.aidl19
-rw-r--r--nfc/java/android/nfc/ApduList.java68
-rw-r--r--nfc/java/android/nfc/AvailableNfcAntenna.aidl19
-rw-r--r--nfc/java/android/nfc/AvailableNfcAntenna.java121
-rw-r--r--nfc/java/android/nfc/ComponentNameAndUser.aidl19
-rw-r--r--nfc/java/android/nfc/ComponentNameAndUser.java100
-rw-r--r--nfc/java/android/nfc/Constants.java42
-rw-r--r--nfc/java/android/nfc/Entry.aidl18
-rw-r--r--nfc/java/android/nfc/Entry.java85
-rw-r--r--nfc/java/android/nfc/ErrorCodes.java114
-rw-r--r--nfc/java/android/nfc/FormatException.java31
-rw-r--r--nfc/java/android/nfc/IAppCallback.aidl27
-rw-r--r--nfc/java/android/nfc/INfcAdapter.aidl128
-rw-r--r--nfc/java/android/nfc/INfcAdapterExtras.aidl40
-rw-r--r--nfc/java/android/nfc/INfcCardEmulation.aidl65
-rw-r--r--nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl29
-rw-r--r--nfc/java/android/nfc/INfcDta.aidl34
-rw-r--r--nfc/java/android/nfc/INfcEventCallback.aidl16
-rw-r--r--nfc/java/android/nfc/INfcFCardEmulation.aidl36
-rw-r--r--nfc/java/android/nfc/INfcOemExtensionCallback.aidl59
-rw-r--r--nfc/java/android/nfc/INfcTag.aidl50
-rw-r--r--nfc/java/android/nfc/INfcUnlockHandler.aidl12
-rw-r--r--nfc/java/android/nfc/INfcVendorNciCallback.aidl24
-rw-r--r--nfc/java/android/nfc/INfcWlcStateListener.aidl30
-rw-r--r--nfc/java/android/nfc/IT4tNdefNfcee.aidl33
-rw-r--r--nfc/java/android/nfc/ITagRemovedCallback.aidl8
-rw-r--r--nfc/java/android/nfc/NdefMessage.aidl19
-rw-r--r--nfc/java/android/nfc/NdefMessage.java272
-rw-r--r--nfc/java/android/nfc/NdefRecord.aidl19
-rw-r--r--nfc/java/android/nfc/NdefRecord.java1080
-rw-r--r--nfc/java/android/nfc/NfcActivityManager.java403
-rw-r--r--nfc/java/android/nfc/NfcAdapter.java2949
-rw-r--r--nfc/java/android/nfc/NfcAntennaInfo.aidl19
-rw-r--r--nfc/java/android/nfc/NfcAntennaInfo.java117
-rw-r--r--nfc/java/android/nfc/NfcControllerAlwaysOnListener.java136
-rw-r--r--nfc/java/android/nfc/NfcEvent.java56
-rw-r--r--nfc/java/android/nfc/NfcFrameworkInitializer.java71
-rw-r--r--nfc/java/android/nfc/NfcManager.java73
-rw-r--r--nfc/java/android/nfc/NfcOemExtension.java1248
-rw-r--r--nfc/java/android/nfc/NfcRoutingTableEntry.java105
-rw-r--r--nfc/java/android/nfc/NfcVendorNciCallbackListener.java115
-rw-r--r--nfc/java/android/nfc/NfcWlcStateListener.java122
-rw-r--r--nfc/java/android/nfc/OemLogItems.aidl19
-rw-r--r--nfc/java/android/nfc/OemLogItems.java333
-rw-r--r--nfc/java/android/nfc/Placeholder.java27
-rw-r--r--nfc/java/android/nfc/RoutingStatus.java79
-rw-r--r--nfc/java/android/nfc/RoutingTableAidEntry.java48
-rw-r--r--nfc/java/android/nfc/RoutingTableProtocolEntry.java131
-rw-r--r--nfc/java/android/nfc/RoutingTableSystemCodeEntry.java50
-rw-r--r--nfc/java/android/nfc/RoutingTableTechnologyEntry.java108
-rw-r--r--nfc/java/android/nfc/T4tNdefNfcee.java276
-rw-r--r--nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java202
-rw-r--r--nfc/java/android/nfc/Tag.aidl19
-rw-r--r--nfc/java/android/nfc/Tag.java508
-rw-r--r--nfc/java/android/nfc/TagLostException.java29
-rw-r--r--nfc/java/android/nfc/TechListParcel.aidl19
-rw-r--r--nfc/java/android/nfc/TechListParcel.java66
-rw-r--r--nfc/java/android/nfc/TransceiveResult.aidl19
-rw-r--r--nfc/java/android/nfc/TransceiveResult.java93
-rw-r--r--nfc/java/android/nfc/WlcListenerDeviceInfo.aidl19
-rw-r--r--nfc/java/android/nfc/WlcListenerDeviceInfo.java145
-rw-r--r--nfc/java/android/nfc/cardemulation/CardEmulation.java1497
-rw-r--r--nfc/java/android/nfc/cardemulation/HostApduService.java446
-rw-r--r--nfc/java/android/nfc/cardemulation/HostNfcFService.java279
-rw-r--r--nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java473
-rw-r--r--nfc/java/android/nfc/cardemulation/OffHostApduService.java170
-rw-r--r--nfc/java/android/nfc/cardemulation/PollingFrame.aidl19
-rw-r--r--nfc/java/android/nfc/cardemulation/PollingFrame.java283
-rw-r--r--nfc/java/android/nfc/cardemulation/Utils.java37
-rw-r--r--nfc/java/android/nfc/dta/NfcDta.java167
-rw-r--r--nfc/java/android/nfc/package.html33
-rw-r--r--nfc/java/android/nfc/tech/BasicTagTechnology.java161
-rw-r--r--nfc/java/android/nfc/tech/IsoDep.java209
-rw-r--r--nfc/java/android/nfc/tech/MifareClassic.java655
-rw-r--r--nfc/java/android/nfc/tech/MifareUltralight.java280
-rw-r--r--nfc/java/android/nfc/tech/Ndef.java408
-rw-r--r--nfc/java/android/nfc/tech/NdefFormatable.java182
-rw-r--r--nfc/java/android/nfc/tech/NfcA.java173
-rw-r--r--nfc/java/android/nfc/tech/NfcB.java125
-rw-r--r--nfc/java/android/nfc/tech/NfcBarcode.java130
-rw-r--r--nfc/java/android/nfc/tech/NfcF.java177
-rw-r--r--nfc/java/android/nfc/tech/NfcV.java126
-rw-r--r--nfc/java/android/nfc/tech/TagTechnology.java224
-rw-r--r--nfc/java/android/nfc/tech/package.html13
-rw-r--r--nfc/lint-baseline.xml81
-rw-r--r--nfc/tests/Android.bp68
-rw-r--r--nfc/tests/AndroidManifest.xml31
-rw-r--r--nfc/tests/AndroidTest.xml32
-rw-r--r--nfc/tests/src/android/nfc/NdefMessageTest.java59
-rw-r--r--nfc/tests/src/android/nfc/NdefRecordTest.java77
-rw-r--r--nfc/tests/src/android/nfc/NfcAntennaInfoTest.java77
-rw-r--r--nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java199
-rw-r--r--nfc/tests/src/android/nfc/NfcManagerTest.java71
-rw-r--r--nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java61
-rw-r--r--nfc/tests/src/android/nfc/OemLogItemsTest.java90
-rw-r--r--nfc/tests/src/android/nfc/TechListParcelTest.java82
-rw-r--r--nfc/tests/src/android/nfc/cardemulation/AidGroupTest.java95
-rw-r--r--nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java284
-rw-r--r--nfc/tests/src/android/nfc/dta/NfcDtaTest.java179
-rw-r--r--nfc/tests/src/android/nfc/tech/NfcATest.java185
-rw-r--r--nfc/tests/src/android/nfc/tech/NfcBTest.java119
-rw-r--r--nfc/tests/src/android/nfc/tech/NfcBarcodeTest.java109
-rw-r--r--nfc/tests/src/android/nfc/tech/NfcFTest.java191
-rw-r--r--nfc/tests/src/android/nfc/tech/NfcVTest.java119
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/common/ui/ActionButton.kt4
-rw-r--r--packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/PreferenceBindingTestUtils.kt13
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outline_color_selector.xml21
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outlined_background_color_selector.xml25
-rw-r--r--packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_filled_button_color.xml24
-rw-r--r--packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml1
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml87
-rw-r--r--packages/SettingsLib/SettingsTheme/res/values/styles_m3_expressive.xml475
-rw-r--r--packages/SettingsLib/SettingsTheme/res/xml/settingslib_button_shape_state_list.xml25
-rw-r--r--packages/SettingsLib/SettingsTheme/res/xml/settingslib_inner_corner_size_state_list.xml25
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt52
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt6
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt2
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt3
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt238
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt14
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt8
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt21
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt21
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt5
-rw-r--r--packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt10
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt1
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt410
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt10
-rw-r--r--packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt36
-rw-r--r--packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt47
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt8
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt3
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java25
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt6
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt33
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt2
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt4
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt21
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt5
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt98
-rw-r--r--packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java10
-rw-r--r--packages/SystemUI/res/layout/ongoing_activity_chip_content.xml (renamed from packages/SystemUI/res/layout/ongoing_activity_chip.xml)18
-rw-r--r--packages/SystemUI/res/layout/ongoing_activity_chip_primary.xml23
-rw-r--r--packages/SystemUI/res/layout/ongoing_activity_chip_secondary.xml23
-rw-r--r--packages/SystemUI/res/layout/status_bar.xml4
-rw-r--r--packages/SystemUI/res/values/dimens.xml7
-rw-r--r--packages/SystemUI/res/values/strings.xml4
-rw-r--r--packages/SystemUI/res/values/styles.xml9
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java16
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt25
-rw-r--r--packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java25
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java19
-rw-r--r--packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt7
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/SecondaryOngoingActivityChip.kt40
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt4
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java21
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt3
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java3
-rwxr-xr-xravenwood/scripts/extract-last-soong-commands.py14
-rw-r--r--ravenwood/texts/ravenwood-build.prop1
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java51
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java93
-rw-r--r--services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java10
-rw-r--r--services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java21
-rw-r--r--services/core/java/com/android/server/display/BrightnessRangeController.java2
-rw-r--r--services/core/java/com/android/server/display/feature/DisplayManagerFlags.java10
-rw-r--r--services/core/java/com/android/server/display/feature/display_flags.aconfig8
-rw-r--r--services/core/java/com/android/server/display/mode/DisplayModeDirector.java11
-rw-r--r--services/core/java/com/android/server/display/mode/ProximitySensorObserver.java10
-rw-r--r--services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java11
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java5
-rw-r--r--services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java10
-rw-r--r--services/core/java/com/android/server/power/WakefulnessSessionObserver.java13
-rw-r--r--services/core/java/com/android/server/power/hint/HintManagerService.java147
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskSupervisor.java5
-rw-r--r--services/core/java/com/android/server/wm/BackgroundActivityStartController.java52
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java3
-rw-r--r--services/tests/appfunctions/Android.bp10
-rw-r--r--services/tests/appfunctions/src/com/android/server/appfunctions/AppFunctionsLoggingTest.kt139
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java2
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java26
-rw-r--r--services/tests/displayservicetests/src/com/android/server/display/mode/DisplayModeDirectorTest.java62
-rw-r--r--services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java56
-rw-r--r--tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt5
307 files changed, 4233 insertions, 21305 deletions
diff --git a/core/api/current.txt b/core/api/current.txt
index 7c56a5811abb..d0b3a51f998e 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -20781,11 +20781,11 @@ package android.hardware.display {
method @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public void registerDisplayListener(@NonNull java.util.concurrent.Executor, long, @NonNull android.hardware.display.DisplayManager.DisplayListener);
method public void unregisterDisplayListener(android.hardware.display.DisplayManager.DisplayListener);
field public static final String DISPLAY_CATEGORY_PRESENTATION = "android.hardware.display.category.PRESENTATION";
- field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_ADDED = 1L; // 0x1L
- field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_CHANGED = 4L; // 0x4L
- field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_REFRESH_RATE = 8L; // 0x8L
- field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_REMOVED = 2L; // 0x2L
- field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_FLAG_DISPLAY_STATE = 16L; // 0x10L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_ADDED = 1L; // 0x1L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_CHANGED = 4L; // 0x4L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_REFRESH_RATE = 8L; // 0x8L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_REMOVED = 2L; // 0x2L
+ field @FlaggedApi("com.android.server.display.feature.flags.display_listener_performance_improvements") public static final long EVENT_TYPE_DISPLAY_STATE = 16L; // 0x10L
field public static final int MATCH_CONTENT_FRAMERATE_ALWAYS = 2; // 0x2
field public static final int MATCH_CONTENT_FRAMERATE_NEVER = 0; // 0x0
field public static final int MATCH_CONTENT_FRAMERATE_SEAMLESSS_ONLY = 1; // 0x1
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index ff5b2bda7ccf..a60fd117fd17 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -5157,18 +5157,18 @@ package android.hardware.contexthub {
}
@FlaggedApi("android.chre.flags.offload_api") public final class HubMessage implements android.os.Parcelable {
- ctor public HubMessage(int, @NonNull byte[]);
- ctor public HubMessage(int, @NonNull byte[], @NonNull android.hardware.contexthub.HubMessage.DeliveryParams);
method public int describeContents();
method @NonNull public byte[] getMessageBody();
method public int getMessageType();
+ method public boolean isResponseRequired();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.hardware.contexthub.HubMessage> CREATOR;
}
- public static class HubMessage.DeliveryParams {
- ctor public HubMessage.DeliveryParams(boolean);
- method public boolean isResponseRequired();
+ public static final class HubMessage.Builder {
+ ctor public HubMessage.Builder(int, @NonNull byte[]);
+ method @NonNull public android.hardware.contexthub.HubMessage build();
+ method @NonNull public android.hardware.contexthub.HubMessage.Builder setResponseRequired(boolean);
}
@FlaggedApi("android.chre.flags.offload_api") public final class HubServiceInfo implements android.os.Parcelable {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index eeb1ebb69b03..8ffea237c71d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -6453,6 +6453,13 @@ public class Notification implements Parcelable
big.setColorStateList(R.id.snooze_button, "setImageTintList", actionColor);
big.setColorStateList(R.id.bubble_button, "setImageTintList", actionColor);
+ if (Flags.notificationsRedesignTemplates()) {
+ int margin = getContentMarginTop(mContext,
+ R.dimen.notification_2025_content_margin_top);
+ big.setViewLayoutMargin(R.id.notification_main_column, RemoteViews.MARGIN_TOP,
+ margin, TypedValue.COMPLEX_UNIT_PX);
+ }
+
boolean validRemoteInput = false;
// In the UI, contextual actions appear separately from the standard actions, so we
@@ -6549,6 +6556,30 @@ public class Notification implements Parcelable
return big;
}
+ /**
+ * Calculate the top margin for the content in px, to allow enough space for the top line
+ * above, using the given resource ID for the desired spacing.
+ *
+ * @hide
+ */
+ public static int getContentMarginTop(Context context, @DimenRes int spacingRes) {
+ final Resources resources = context.getResources();
+ // The margin above the text, at the top of the notification (originally in dp)
+ int notifMargin = resources.getDimensionPixelSize(R.dimen.notification_2025_margin);
+ // Spacing between the text lines, scaling with the font size (originally in sp)
+ int spacing = resources.getDimensionPixelSize(spacingRes);
+
+ // Size of the text in the notification top line (originally in sp)
+ int[] textSizeAttr = new int[] { android.R.attr.textSize };
+ TypedArray typedArray = context.obtainStyledAttributes(
+ R.style.TextAppearance_DeviceDefault_Notification_Info, textSizeAttr);
+ int textSize = typedArray.getDimensionPixelSize(0 /* index */, -1 /* default */);
+ typedArray.recycle();
+
+ // Adding up all the values as pixels
+ return notifMargin + spacing + textSize;
+ }
+
private boolean hasValidRemoteInput(Action action) {
if (TextUtils.isEmpty(action.title) || action.actionIntent == null) {
// Weird actions
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 39c27a165588..84d67415a4b4 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -17430,12 +17430,17 @@ public class DevicePolicyManager {
}
/**
- * Removes a manged profile from the device only when called from a managed profile's context
+ * Removes a managed profile from the device.
+ *
+ * <p>
+ * Removes the managed profile which is specified by the context user
+ * ({@code Context.createContextAsUser()}).
+ * <p>
*
- * @param user UserHandle of the profile to be removed
* @return {@code true} when removal of managed profile was successful, {@code false} when
- * removal was unsuccessful or throws IllegalArgumentException when provided user was not a
+ * removal was unsuccessful or throws IllegalArgumentException when specified user was not a
* managed profile
+ *
* @hide
*/
@SystemApi
diff --git a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java
index e527de209a75..88001fc6cc3c 100644
--- a/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java
+++ b/core/java/android/app/appfunctions/SafeOneTimeExecuteAppFunctionCallback.java
@@ -19,7 +19,6 @@ package android.app.appfunctions;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.RemoteException;
-import android.os.SystemClock;
import android.util.Log;
import java.util.Objects;
@@ -40,8 +39,7 @@ public class SafeOneTimeExecuteAppFunctionCallback {
@NonNull private final IExecuteAppFunctionCallback mCallback;
- @Nullable
- private final CompletionCallback mCompletionCallback;
+ @Nullable private final CompletionCallback mCompletionCallback;
private final AtomicLong mExecutionStartTimeAfterBindMillis = new AtomicLong();
@@ -49,7 +47,8 @@ public class SafeOneTimeExecuteAppFunctionCallback {
this(callback, /* completionCallback= */ null);
}
- public SafeOneTimeExecuteAppFunctionCallback(@NonNull IExecuteAppFunctionCallback callback,
+ public SafeOneTimeExecuteAppFunctionCallback(
+ @NonNull IExecuteAppFunctionCallback callback,
@Nullable CompletionCallback completionCallback) {
mCallback = Objects.requireNonNull(callback);
mCompletionCallback = completionCallback;
@@ -64,8 +63,8 @@ public class SafeOneTimeExecuteAppFunctionCallback {
try {
mCallback.onSuccess(result);
if (mCompletionCallback != null) {
- mCompletionCallback.finalizeOnSuccess(result,
- mExecutionStartTimeAfterBindMillis.get());
+ mCompletionCallback.finalizeOnSuccess(
+ result, mExecutionStartTimeAfterBindMillis.get());
}
} catch (RemoteException ex) {
// Failed to notify the other end. Ignore.
@@ -82,8 +81,8 @@ public class SafeOneTimeExecuteAppFunctionCallback {
try {
mCallback.onError(error);
if (mCompletionCallback != null) {
- mCompletionCallback.finalizeOnError(error,
- mExecutionStartTimeAfterBindMillis.get());
+ mCompletionCallback.finalizeOnError(
+ error, mExecutionStartTimeAfterBindMillis.get());
}
} catch (RemoteException ex) {
// Failed to notify the other end. Ignore.
@@ -103,9 +102,10 @@ public class SafeOneTimeExecuteAppFunctionCallback {
* Sets the execution start time of the request. Used to calculate the overhead latency of
* requests.
*/
- public void setExecutionStartTimeMillis() {
- if (!mExecutionStartTimeAfterBindMillis.compareAndSet(0, SystemClock.elapsedRealtime())) {
- Log.w(TAG, "Ignore subsequent calls to setExecutionStartTimeMillis()");
+ public void setExecutionStartTimeAfterBindMillis(long executionStartTimeAfterBindMillis) {
+ if (!mExecutionStartTimeAfterBindMillis.compareAndSet(
+ 0, executionStartTimeAfterBindMillis)) {
+ Log.w(TAG, "Ignore subsequent calls to setExecutionStartTimeAfterBindMillis()");
}
}
@@ -115,8 +115,8 @@ public class SafeOneTimeExecuteAppFunctionCallback {
*/
public interface CompletionCallback {
/** Called after {@link IExecuteAppFunctionCallback#onSuccess}. */
- void finalizeOnSuccess(@NonNull ExecuteAppFunctionResponse result,
- long executionStartTimeMillis);
+ void finalizeOnSuccess(
+ @NonNull ExecuteAppFunctionResponse result, long executionStartTimeMillis);
/** Called after {@link IExecuteAppFunctionCallback#onError}. */
void finalizeOnError(@NonNull AppFunctionException error, long executionStartTimeMillis);
diff --git a/core/java/android/credentials/flags.aconfig b/core/java/android/credentials/flags.aconfig
index 9c811fb84da3..2161e10337c9 100644
--- a/core/java/android/credentials/flags.aconfig
+++ b/core/java/android/credentials/flags.aconfig
@@ -13,6 +13,16 @@ flag {
flag {
namespace: "credential_manager"
+ name: "package_update_fix_enabled"
+ description: "Enable fix for removing package from settings if app is updated or component is modified"
+ bug: "384772470"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ namespace: "credential_manager"
name: "settings_activity_enabled"
is_exported: true
description: "Enable the Credential Manager Settings Activity APIs"
diff --git a/core/java/android/hardware/contexthub/HubEndpoint.java b/core/java/android/hardware/contexthub/HubEndpoint.java
index af92cffc57f4..6c669a3d7032 100644
--- a/core/java/android/hardware/contexthub/HubEndpoint.java
+++ b/core/java/android/hardware/contexthub/HubEndpoint.java
@@ -296,7 +296,7 @@ public class HubEndpoint {
}
if (activeSession == null || mMessageCallback == null) {
- if (message.getDeliveryParams().isResponseRequired()) {
+ if (message.isResponseRequired()) {
try {
mServiceToken.sendMessageDeliveryStatus(
sessionId,
@@ -313,7 +313,7 @@ public class HubEndpoint {
mMessageCallbackExecutor.execute(
() -> {
mMessageCallback.onMessageReceived(activeSession, message);
- if (message.getDeliveryParams().isResponseRequired()) {
+ if (message.isResponseRequired()) {
try {
mServiceToken.sendMessageDeliveryStatus(
sessionId,
diff --git a/core/java/android/hardware/contexthub/HubEndpointSession.java b/core/java/android/hardware/contexthub/HubEndpointSession.java
index f7f5636264e4..dd6e52f51df0 100644
--- a/core/java/android/hardware/contexthub/HubEndpointSession.java
+++ b/core/java/android/hardware/contexthub/HubEndpointSession.java
@@ -79,7 +79,7 @@ public class HubEndpointSession implements AutoCloseable {
throw new IllegalStateException("Session is already closed.");
}
- boolean isResponseRequired = message.getDeliveryParams().isResponseRequired();
+ boolean isResponseRequired = message.isResponseRequired();
ContextHubTransaction<Void> ret =
new ContextHubTransaction<>(
isResponseRequired
diff --git a/core/java/android/hardware/contexthub/HubMessage.java b/core/java/android/hardware/contexthub/HubMessage.java
index 6373bbad9f25..8a8617d6c70d 100644
--- a/core/java/android/hardware/contexthub/HubMessage.java
+++ b/core/java/android/hardware/contexthub/HubMessage.java
@@ -29,7 +29,8 @@ import java.util.Arrays;
import java.util.Objects;
/**
- * A class describing general messages send through the Context Hub Service.
+ * A class describing general messages send through the Context Hub Service through {@link
+ * HubEndpointSession#sendMessage}.
*
* @hide
*/
@@ -41,84 +42,14 @@ public final class HubMessage implements Parcelable {
private final int mMessageType;
private final byte[] mMessageBody;
- private final DeliveryParams mDeliveryParams;
+ private final boolean mResponseRequired;
private int mMessageSequenceNumber;
- /**
- * Configurable options for message delivery. This option can be passed into {@link
- * HubEndpointSession#sendMessage} to specify the behavior of message delivery.
- */
- public static class DeliveryParams {
- private final boolean mResponseRequired;
-
- /**
- * @param responseRequired If true, message sent with this option will have a {@link
- * android.hardware.location.ContextHubTransaction.Response} when the peer received the
- * message.
- */
- public DeliveryParams(boolean responseRequired) {
- mResponseRequired = responseRequired;
- }
-
- /** Get the acknowledgement requirement. */
- public boolean isResponseRequired() {
- return mResponseRequired;
- }
-
- @Override
- public String toString() {
- StringBuilder out = new StringBuilder();
- out.append("DeliveryParams[");
- out.append("responseRequired = ").append(mResponseRequired);
- out.append("]");
- return out.toString();
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mResponseRequired);
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj == this) {
- return true;
- }
-
- if (obj instanceof DeliveryParams other) {
- return other.mResponseRequired == mResponseRequired;
- }
-
- return false;
- }
- }
-
- /**
- * Default constructor for HubMessage with no response required.
- *
- * @param messageType the endpoint & service dependent message type
- * @param messageBody the byte array message contents
- */
- public HubMessage(int messageType, @NonNull byte[] messageBody) {
+ private HubMessage(int messageType, @NonNull byte[] messageBody, boolean responseRequired) {
Objects.requireNonNull(messageBody, "messageBody cannot be null");
mMessageType = messageType;
mMessageBody = messageBody;
- mDeliveryParams = new DeliveryParams(/* responseRequired= */ false);
- }
-
- /**
- * @param messageType the endpoint & service dependent message type
- * @param messageBody the byte array message contents
- * @param deliveryParams The message delivery parameters. See {@link HubMessage.DeliveryParams}
- * for more details.
- */
- public HubMessage(
- int messageType, @NonNull byte[] messageBody, @NonNull DeliveryParams deliveryParams) {
- Objects.requireNonNull(messageBody, "messageBody cannot be null");
- Objects.requireNonNull(deliveryParams, "deliveryParams cannot be null");
- mMessageType = messageType;
- mMessageBody = messageBody;
- mDeliveryParams = deliveryParams;
+ mResponseRequired = responseRequired;
}
/**
@@ -141,12 +72,10 @@ public final class HubMessage implements Parcelable {
}
/**
- * Retrieve the {@link DeliveryParams} object specifying the behavior of message delivery.
- *
- * @hide
+ * @return true if a response is required when the peer endpoint receives the message.
*/
- public DeliveryParams getDeliveryParams() {
- return mDeliveryParams;
+ public boolean isResponseRequired() {
+ return mResponseRequired;
}
/**
@@ -175,7 +104,7 @@ public final class HubMessage implements Parcelable {
mMessageBody = new byte[msgSize];
in.readByteArray(mMessageBody);
- mDeliveryParams = new DeliveryParams(in.readInt() == 1);
+ mResponseRequired = (in.readInt() == 1);
mMessageSequenceNumber = in.readInt();
}
@@ -191,7 +120,7 @@ public final class HubMessage implements Parcelable {
out.writeInt(mMessageBody.length);
out.writeByteArray(mMessageBody);
- out.writeInt(mDeliveryParams.isResponseRequired() ? 1 : 0);
+ out.writeInt(mResponseRequired ? 1 : 0);
out.writeInt(mMessageSequenceNumber);
}
@@ -217,7 +146,7 @@ public final class HubMessage implements Parcelable {
out.append("HubMessage[type = ").append(mMessageType);
out.append(", length = ").append(mMessageBody.length);
out.append(", messageSequenceNumber = ").append(mMessageSequenceNumber);
- out.append(", deliveryParams = ").append(mDeliveryParams);
+ out.append(", responseRequired = ").append(mResponseRequired);
out.append("](");
if (length > 0) {
@@ -249,7 +178,7 @@ public final class HubMessage implements Parcelable {
isEqual =
(other.getMessageType() == mMessageType)
&& Arrays.equals(other.getMessageBody(), mMessageBody)
- && (other.getDeliveryParams().equals(mDeliveryParams))
+ && (other.isResponseRequired() == mResponseRequired)
&& (other.getMessageSequenceNumber() == mMessageSequenceNumber);
}
@@ -265,7 +194,41 @@ public final class HubMessage implements Parcelable {
return Objects.hash(
mMessageType,
Arrays.hashCode(mMessageBody),
- mDeliveryParams,
+ mResponseRequired,
mMessageSequenceNumber);
}
+
+ public static final class Builder {
+ private int mMessageType;
+ private byte[] mMessageBody;
+ private boolean mResponseRequired = false;
+
+ /**
+ * Create a builder for {@link HubMessage} with a default delivery parameters.
+ *
+ * @param messageType the endpoint & service dependent message type
+ * @param messageBody the byte array message contents
+ */
+ public Builder(int messageType, @NonNull byte[] messageBody) {
+ mMessageType = messageType;
+ mMessageBody = messageBody;
+ }
+
+ /**
+ * @param responseRequired If true, message sent with this option will have a {@link
+ * android.hardware.location.ContextHubTransaction.Response} when the peer received the
+ * message. Default is false.
+ */
+ @NonNull
+ public Builder setResponseRequired(boolean responseRequired) {
+ mResponseRequired = responseRequired;
+ return this;
+ }
+
+ /** Build the {@link HubMessage} object. */
+ @NonNull
+ public HubMessage build() {
+ return new HubMessage(mMessageType, mMessageBody, mResponseRequired);
+ }
+ }
}
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 7054c37cbc3b..6716598f9e4c 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -578,73 +578,82 @@ public final class DisplayManager {
/**
* @hide
*/
- @LongDef(flag = true, prefix = {"EVENT_FLAG_"}, value = {
- EVENT_FLAG_DISPLAY_ADDED,
- EVENT_FLAG_DISPLAY_CHANGED,
- EVENT_FLAG_DISPLAY_REMOVED,
- EVENT_FLAG_DISPLAY_REFRESH_RATE,
- EVENT_FLAG_DISPLAY_STATE
+ @LongDef(flag = true, prefix = {"EVENT_TYPE_"}, value = {
+ EVENT_TYPE_DISPLAY_ADDED,
+ EVENT_TYPE_DISPLAY_CHANGED,
+ EVENT_TYPE_DISPLAY_REMOVED,
+ EVENT_TYPE_DISPLAY_REFRESH_RATE,
+ EVENT_TYPE_DISPLAY_STATE
})
@Retention(RetentionPolicy.SOURCE)
- public @interface EventFlag {}
+ public @interface EventType {}
/**
* @hide
*/
- @LongDef(flag = true, prefix = {"PRIVATE_EVENT_FLAG_"}, value = {
- PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS,
- PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED,
- PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+ @LongDef(flag = true, prefix = {"PRIVATE_EVENT_TYPE_"}, value = {
+ PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS,
+ PRIVATE_EVENT_TYPE_HDR_SDR_RATIO_CHANGED,
+ PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED,
})
@Retention(RetentionPolicy.SOURCE)
- public @interface PrivateEventFlag {}
+ public @interface PrivateEventType {}
/**
- * Event type for when a new display is added.
+ * Event type for when a new display is added. This notification is sent
+ * through the {@link DisplayListener#onDisplayAdded} callback method
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
*/
@FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public static final long EVENT_FLAG_DISPLAY_ADDED = 1L << 0;
+ public static final long EVENT_TYPE_DISPLAY_ADDED = 1L << 0;
/**
- * Event type for when a display is removed.
+ * Event type for when a display is removed. This notification is sent
+ * through the {@link DisplayListener#onDisplayRemoved} callback method
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
*/
@FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public static final long EVENT_FLAG_DISPLAY_REMOVED = 1L << 1;
+ public static final long EVENT_TYPE_DISPLAY_REMOVED = 1L << 1;
/**
- * Event type for when a display is changed.
+ * Event type for when a display is changed. {@link DisplayListener#onDisplayChanged} callback
+ * is triggered whenever the properties of a {@link android.view.Display}, such as size,
+ * state, density are modified.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*
*/
@FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public static final long EVENT_FLAG_DISPLAY_CHANGED = 1L << 2;
-
+ public static final long EVENT_TYPE_DISPLAY_CHANGED = 1L << 2;
/**
- * Event flag to register for a display's refresh rate changes.
+ * Event type for when a display's refresh rate changes.
+ * {@link DisplayListener#onDisplayChanged} callback is triggered whenever the refresh rate
+ * of the display changes. New refresh rate values can be retrieved via
+ * {@link Display#getRefreshRate()}.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*/
@FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public static final long EVENT_FLAG_DISPLAY_REFRESH_RATE = 1L << 3;
+ public static final long EVENT_TYPE_DISPLAY_REFRESH_RATE = 1L << 3;
/**
- * Event flag to register for a display state changes.
+ * Event type for when a display state changes.
+ * {@link DisplayListener#onDisplayChanged} callback is triggered whenever the state
+ * of the display changes. New state values can be retrieved via
+ * {@link Display#getState()}.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
*/
@FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public static final long EVENT_FLAG_DISPLAY_STATE = 1L << 4;
+ public static final long EVENT_TYPE_DISPLAY_STATE = 1L << 4;
/**
- * Event flag to register for a display's brightness changes. This notification is sent
+ * Event type to register for a display's brightness changes. This notification is sent
* through the {@link DisplayListener#onDisplayChanged} callback method. New brightness
* values can be retrieved via {@link android.view.Display#getBrightnessInfo()}.
*
@@ -652,10 +661,10 @@ public final class DisplayManager {
*
* @hide
*/
- public static final long PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS = 1L << 0;
+ public static final long PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS = 1L << 0;
/**
- * Event flag to register for a display's hdr/sdr ratio changes. This notification is sent
+ * Event type to register for a display's hdr/sdr ratio changes. This notification is sent
* through the {@link DisplayListener#onDisplayChanged} callback method. New hdr/sdr
* values can be retrieved via {@link Display#getHdrSdrRatio()}.
*
@@ -665,15 +674,15 @@ public final class DisplayManager {
*
* @hide
*/
- public static final long PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED = 1L << 1;
+ public static final long PRIVATE_EVENT_TYPE_HDR_SDR_RATIO_CHANGED = 1L << 1;
/**
- * Event flag to register for a display's connection changed.
+ * Event type to register for a display's connection changed.
*
* @see #registerDisplayListener(DisplayListener, Handler, long)
* @hide
*/
- public static final long PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED = 1L << 2;
+ public static final long PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED = 1L << 2;
/** @hide */
@@ -800,8 +809,8 @@ public final class DisplayManager {
* @see #unregisterDisplayListener
*/
public void registerDisplayListener(DisplayListener listener, Handler handler) {
- registerDisplayListener(listener, handler, EVENT_FLAG_DISPLAY_ADDED
- | EVENT_FLAG_DISPLAY_CHANGED | EVENT_FLAG_DISPLAY_REMOVED);
+ registerDisplayListener(listener, handler, EVENT_TYPE_DISPLAY_ADDED
+ | EVENT_TYPE_DISPLAY_CHANGED | EVENT_TYPE_DISPLAY_REMOVED);
}
/**
@@ -810,7 +819,7 @@ public final class DisplayManager {
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
- * @param eventFlags A bitmask of the event types for which this listener is subscribed.
+ * @param eventFilter A bitmask of the event types for which this listener is subscribed.
*
* @see #registerDisplayListener(DisplayListener, Handler)
* @see #unregisterDisplayListener
@@ -818,9 +827,9 @@ public final class DisplayManager {
* @hide
*/
public void registerDisplayListener(@NonNull DisplayListener listener,
- @Nullable Handler handler, @EventFlag long eventFlags) {
+ @Nullable Handler handler, @EventType long eventFilter) {
mGlobal.registerDisplayListener(listener, handler,
- mGlobal.mapFlagsToInternalEventFlag(eventFlags, 0),
+ mGlobal.mapFiltersToInternalEventFlag(eventFilter, 0),
ActivityThread.currentPackageName());
}
@@ -829,17 +838,17 @@ public final class DisplayManager {
*
* @param listener The listener to register.
* @param executor Executor for the thread that will be receiving the callbacks. Cannot be null.
- * @param eventFlags A bitmask of the event types for which this listener is subscribed.
+ * @param eventFilter A bitmask of the event types for which this listener is subscribed.
*
* @see #registerDisplayListener(DisplayListener, Handler)
* @see #unregisterDisplayListener
*
*/
@FlaggedApi(FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public void registerDisplayListener(@NonNull Executor executor, @EventFlag long eventFlags,
+ public void registerDisplayListener(@NonNull Executor executor, @EventType long eventFilter,
@NonNull DisplayListener listener) {
mGlobal.registerDisplayListener(listener, executor,
- mGlobal.mapFlagsToInternalEventFlag(eventFlags, 0),
+ mGlobal.mapFiltersToInternalEventFlag(eventFilter, 0),
ActivityThread.currentPackageName());
}
@@ -849,8 +858,8 @@ public final class DisplayManager {
* @param listener The listener to register.
* @param handler The handler on which the listener should be invoked, or null
* if the listener should be invoked on the calling thread's looper.
- * @param eventFlags A bitmask of the event types for which this listener is subscribed.
- * @param privateEventFlags A bitmask of the private event types for which this listener
+ * @param eventFilter A bitmask of the event types for which this listener is subscribed.
+ * @param privateEventFilter A bitmask of the private event types for which this listener
* is subscribed.
*
* @see #registerDisplayListener(DisplayListener, Handler)
@@ -859,10 +868,10 @@ public final class DisplayManager {
* @hide
*/
public void registerDisplayListener(@NonNull DisplayListener listener,
- @Nullable Handler handler, @EventFlag long eventFlags,
- @PrivateEventFlag long privateEventFlags) {
+ @Nullable Handler handler, @EventType long eventFilter,
+ @PrivateEventType long privateEventFilter) {
mGlobal.registerDisplayListener(listener, handler,
- mGlobal.mapFlagsToInternalEventFlag(eventFlags, privateEventFlags),
+ mGlobal.mapFiltersToInternalEventFlag(eventFilter, privateEventFilter),
ActivityThread.currentPackageName());
}
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 9030810a1c1a..b5715ed25bd9 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -18,7 +18,7 @@ package android.hardware.display;
import static android.app.PropertyInvalidatedCache.MODULE_SYSTEM;
-import static android.hardware.display.DisplayManager.EventFlag;
+import static android.hardware.display.DisplayManager.EventType;
import static android.Manifest.permission.MANAGE_DISPLAYS;
import static android.view.Display.HdrCapabilities.HdrType;
@@ -1737,35 +1737,35 @@ public final class DisplayManagerGlobal {
* @return returns the bitmask of both public and private event flags unified to
* InternalEventFlag
*/
- public @InternalEventFlag long mapFlagsToInternalEventFlag(@EventFlag long eventFlags,
- @DisplayManager.PrivateEventFlag long privateEventFlags) {
+ public @InternalEventFlag long mapFiltersToInternalEventFlag(@EventType long eventFlags,
+ @DisplayManager.PrivateEventType long privateEventFlags) {
return mapPrivateEventFlags(privateEventFlags) | mapPublicEventFlags(eventFlags);
}
- private long mapPrivateEventFlags(@DisplayManager.PrivateEventFlag long privateEventFlags) {
+ private long mapPrivateEventFlags(@DisplayManager.PrivateEventType long privateEventFlags) {
long baseEventMask = 0;
- if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS) != 0) {
+ if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED;
}
- if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED) != 0) {
+ if ((privateEventFlags & DisplayManager.PRIVATE_EVENT_TYPE_HDR_SDR_RATIO_CHANGED) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED;
}
if ((privateEventFlags
- & DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED) != 0) {
+ & DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED;
}
return baseEventMask;
}
- private long mapPublicEventFlags(@EventFlag long eventFlags) {
+ private long mapPublicEventFlags(@EventType long eventFlags) {
long baseEventMask = 0;
- if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_ADDED) != 0) {
+ if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_ADDED) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_ADDED;
}
- if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_CHANGED) != 0) {
+ if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_CHANGED) != 0) {
// For backward compatibility, a client subscribing to
// DisplayManager.EVENT_FLAG_DISPLAY_CHANGED will be enrolled to both Basic and
// RR changes
@@ -1774,16 +1774,16 @@ public final class DisplayManagerGlobal {
}
if ((eventFlags
- & DisplayManager.EVENT_FLAG_DISPLAY_REMOVED) != 0) {
+ & DisplayManager.EVENT_TYPE_DISPLAY_REMOVED) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REMOVED;
}
if (Flags.displayListenerPerformanceImprovements()) {
- if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE) != 0) {
+ if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE;
}
- if ((eventFlags & DisplayManager.EVENT_FLAG_DISPLAY_STATE) != 0) {
+ if ((eventFlags & DisplayManager.EVENT_TYPE_DISPLAY_STATE) != 0) {
baseEventMask |= INTERNAL_EVENT_FLAG_DISPLAY_STATE;
}
}
diff --git a/core/java/android/hardware/input/InputManagerGlobal.java b/core/java/android/hardware/input/InputManagerGlobal.java
index 5c11346df1c3..3ef90e4b8a5f 100644
--- a/core/java/android/hardware/input/InputManagerGlobal.java
+++ b/core/java/android/hardware/input/InputManagerGlobal.java
@@ -63,6 +63,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -76,8 +77,9 @@ import java.util.concurrent.Executor;
public final class InputManagerGlobal {
private static final String TAG = "InputManagerGlobal";
// To enable these logs, run: 'adb shell setprop log.tag.InputManagerGlobal DEBUG'
- // (requires restart)
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ private boolean debug() {
+ return Log.isLoggable(TAG, Log.DEBUG);
+ }
@GuardedBy("mInputDeviceListeners")
@Nullable private SparseArray<InputDevice> mInputDevices;
@@ -269,16 +271,19 @@ public final class InputManagerGlobal {
}
private void onInputDevicesChanged(int[] deviceIdAndGeneration) {
- if (DEBUG) {
- Log.d(TAG, "Received input devices changed.");
+ final boolean enableDebugLogs = debug();
+ if (enableDebugLogs) {
+ Log.d(TAG, "Received input devices changed: " + Arrays.toString(deviceIdAndGeneration));
}
synchronized (mInputDeviceListeners) {
for (int i = mInputDevices.size(); --i > 0; ) {
final int deviceId = mInputDevices.keyAt(i);
if (!containsDeviceId(deviceIdAndGeneration, deviceId)) {
- if (DEBUG) {
- Log.d(TAG, "Device removed: " + deviceId);
+ if (enableDebugLogs) {
+ final InputDevice device = mInputDevices.valueAt(i);
+ final String name = device != null ? device.getName() : "<null>";
+ Log.d(TAG, "Device removed: " + deviceId + " (" + name + ")");
}
mInputDevices.removeAt(i);
if (mInputDeviceSensorManager != null) {
@@ -297,8 +302,9 @@ public final class InputManagerGlobal {
if (device != null) {
final int generation = deviceIdAndGeneration[i + 1];
if (device.getGeneration() != generation) {
- if (DEBUG) {
- Log.d(TAG, "Device changed: " + deviceId);
+ if (enableDebugLogs) {
+ Log.d(TAG, "Device changed: " + deviceId + " ("
+ + device.getName() + ")");
}
mInputDevices.setValueAt(index, null);
if (mInputDeviceSensorManager != null) {
@@ -309,7 +315,7 @@ public final class InputManagerGlobal {
}
}
} else {
- if (DEBUG) {
+ if (enableDebugLogs) {
Log.d(TAG, "Device added: " + deviceId);
}
mInputDevices.put(deviceId, null);
@@ -517,7 +523,7 @@ public final class InputManagerGlobal {
}
private void onTabletModeChanged(long whenNanos, boolean inTabletMode) {
- if (DEBUG) {
+ if (debug()) {
Log.d(TAG, "Received tablet mode changed: "
+ "whenNanos=" + whenNanos + ", inTabletMode=" + inTabletMode);
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index d54dbad9286c..c51ad9e986ef 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -431,13 +431,8 @@ public class Build {
* android.os.Build.VERSION_CODES_FULL}.
*/
@FlaggedApi(Flags.FLAG_MAJOR_MINOR_VERSIONING_SCHEME)
- public static final int SDK_INT_FULL;
-
- static {
- SDK_INT_FULL = VERSION_CODES_FULL.SDK_INT_MULTIPLIER
- * SystemProperties.getInt("ro.build.version.sdk", 0)
- + SystemProperties.getInt("ro.build.version.sdk_minor", 0);
- }
+ public static final int SDK_INT_FULL = parseFullVersion(SystemProperties.get(
+ "ro.build.version.sdk_full", ""));
/**
* The SDK version of the software that <em>initially</em> shipped on
diff --git a/core/java/android/os/IHintManager.aidl b/core/java/android/os/IHintManager.aidl
index 56a089aff78a..5128e9173358 100644
--- a/core/java/android/os/IHintManager.aidl
+++ b/core/java/android/os/IHintManager.aidl
@@ -39,12 +39,18 @@ interface IHintManager {
* Throws UnsupportedOperationException if ADPF is not supported, and IllegalStateException
* if creation is supported but fails.
*/
- IHintSession createHintSessionWithConfig(in IBinder token, in SessionTag tag,
+ SessionCreationReturn createHintSessionWithConfig(in IBinder token, in SessionTag tag,
in SessionCreationConfig creationConfig, out SessionConfig config);
void setHintSessionThreads(in IHintSession hintSession, in int[] tids);
int[] getHintSessionThreadIds(in IHintSession hintSession);
+ parcelable SessionCreationReturn {
+ IHintSession session;
+ // True if the graphics pipeline thread limit is being exceeded
+ boolean pipelineThreadLimitExceeded = false;
+ }
+
/**
* Returns FMQ channel information for the caller, which it associates to a binder token.
*
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 507bcb8c2717..08f68f1874e7 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -4206,12 +4206,16 @@ public class UserManager {
private boolean getUserRestrictionFromQuery(@NonNull Pair<String, Integer> restrictionPerUser) {
return UserManagerCache.getUserRestrictionFromQuery(
(Pair<String, Integer> q) -> mService.hasUserRestriction(q.first, q.second),
+ // bypass cache if the flag is disabled
+ (Pair<String, Integer> q) -> !android.multiuser.Flags.cacheUserRestrictionsReadOnly(),
restrictionPerUser);
}
/** @hide */
public static final void invalidateUserRestriction() {
- UserManagerCache.invalidateUserRestrictionFromQuery();
+ if (android.multiuser.Flags.cacheUserRestrictionsReadOnly()) {
+ UserManagerCache.invalidateUserRestrictionFromQuery();
+ }
}
/**
diff --git a/core/java/com/android/internal/display/BrightnessSynchronizer.java b/core/java/com/android/internal/display/BrightnessSynchronizer.java
index a50dbb0223b7..50f10002f7bc 100644
--- a/core/java/com/android/internal/display/BrightnessSynchronizer.java
+++ b/core/java/com/android/internal/display/BrightnessSynchronizer.java
@@ -601,7 +601,7 @@ public class BrightnessSynchronizer {
cr.registerContentObserver(BRIGHTNESS_URI, false,
createBrightnessContentObserver(handler), UserHandle.USER_ALL);
mDisplayManager.registerDisplayListener(mListener, handler, /* eventFlags */ 0,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS);
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS);
mIsObserving = true;
}
}
diff --git a/core/java/com/android/internal/widget/NotificationExpandButton.java b/core/java/com/android/internal/widget/NotificationExpandButton.java
index d4dd1e705653..751cfde70164 100644
--- a/core/java/com/android/internal/widget/NotificationExpandButton.java
+++ b/core/java/com/android/internal/widget/NotificationExpandButton.java
@@ -16,6 +16,8 @@
package com.android.internal.widget;
+import static android.app.Flags.notificationsRedesignTemplates;
+
import android.annotation.ColorInt;
import android.annotation.Nullable;
import android.content.Context;
@@ -130,10 +132,18 @@ public class NotificationExpandButton extends FrameLayout {
int drawableId;
int contentDescriptionId;
if (mExpanded) {
- drawableId = R.drawable.ic_collapse_notification;
+ if (notificationsRedesignTemplates()) {
+ drawableId = R.drawable.ic_notification_2025_collapse;
+ } else {
+ drawableId = R.drawable.ic_collapse_notification;
+ }
contentDescriptionId = R.string.expand_button_content_description_expanded;
} else {
- drawableId = R.drawable.ic_expand_notification;
+ if (notificationsRedesignTemplates()) {
+ drawableId = R.drawable.ic_notification_2025_expand;
+ } else {
+ drawableId = R.drawable.ic_expand_notification;
+ }
contentDescriptionId = R.string.expand_button_content_description_collapsed;
}
setContentDescription(mContext.getText(contentDescriptionId));
diff --git a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
index fb560a568a9c..26b0d11955d2 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/CoreDocument.java
@@ -62,7 +62,7 @@ public class CoreDocument {
// We also keep a more fine-grained BUILD number, exposed as
// ID_API_LEVEL = DOCUMENT_API_LEVEL + BUILD
- static final float BUILD = 0.1f;
+ static final float BUILD = 0.2f;
@NonNull ArrayList<Operation> mOperations = new ArrayList<>();
@@ -1058,7 +1058,7 @@ public class CoreDocument {
* @param theme the theme we want to use for this document.
*/
public void paint(@NonNull RemoteContext context, int theme) {
- context.getLastOpCount();
+ context.clearLastOpCount();
context.getPaintContext().clearNeedsRepaint();
context.loadFloat(RemoteContext.ID_DENSITY, context.getDensity());
context.mMode = RemoteContext.ContextMode.UNSET;
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
index cd26198caf2e..43f8ea7dc78f 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteComposeState.java
@@ -528,6 +528,7 @@ public class RemoteComposeState implements CollectionsAccess {
public void setContext(@NonNull RemoteContext context) {
mRemoteContext = context;
+ mRemoteContext.clearLastOpCount();
}
public void updateObject(int id, @NonNull Object value) {
diff --git a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
index ec336633e960..23c362830713 100644
--- a/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
+++ b/core/java/com/android/internal/widget/remotecompose/core/RemoteContext.java
@@ -743,4 +743,9 @@ public abstract class RemoteContext {
mOpCount = 0;
return count;
}
+
+ /** Explicitly clear the operation counter */
+ public void clearLastOpCount() {
+ mOpCount = 0;
+ }
}
diff --git a/core/res/res/drawable/ic_notification_2025_collapse.xml b/core/res/res/drawable/ic_notification_2025_collapse.xml
new file mode 100644
index 000000000000..1b40c555f84d
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_2025_collapse.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M480,432L296,616L240,560L480,320L720,560L664,616L480,432Z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_notification_2025_expand.xml b/core/res/res/drawable/ic_notification_2025_expand.xml
new file mode 100644
index 000000000000..ea5e0f09d2ef
--- /dev/null
+++ b/core/res/res/drawable/ic_notification_2025_expand.xml
@@ -0,0 +1,25 @@
+<!--
+ ~ 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.
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M480,616L240,376L296,320L480,504L664,320L720,376L480,616Z"/>
+</vector>
diff --git a/core/res/res/drawable/notification_2025_expand_button_pill_bg.xml b/core/res/res/drawable/notification_2025_expand_button_pill_bg.xml
new file mode 100644
index 000000000000..74f697a176f3
--- /dev/null
+++ b/core/res/res/drawable/notification_2025_expand_button_pill_bg.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ 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.
+ ~ 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.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:id="@+id/expand_button_pill_colorized_layer">
+ <shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/notification_2025_expand_button_pill_height" />
+ <solid android:color="@android:color/white" />
+ </shape>
+ </item>
+ <item>
+ <shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <corners android:radius="@dimen/notification_2025_expand_button_pill_height" />
+ <solid android:color="@color/notification_expand_button_state_tint" />
+ </shape>
+ </item>
+</layer-list>
diff --git a/core/res/res/layout/notification_2025_expand_button.xml b/core/res/res/layout/notification_2025_expand_button.xml
new file mode 100644
index 000000000000..c8263c26f38f
--- /dev/null
+++ b/core/res/res/layout/notification_2025_expand_button.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ ~ 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
+ -->
+
+<!-- extends FrameLayout -->
+<com.android.internal.widget.NotificationExpandButton
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/expand_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="top|end"
+ android:contentDescription="@string/expand_button_content_description_collapsed"
+ >
+
+ <LinearLayout
+ android:id="@+id/expand_button_pill"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="@dimen/notification_2025_expand_button_pill_height"
+ android:minWidth="@dimen/notification_2025_expand_button_pill_width"
+ android:paddingVertical="@dimen/notification_2025_expand_button_vertical_icon_padding"
+ android:paddingHorizontal="@dimen/notification_2025_expand_button_horizontal_icon_padding"
+ android:orientation="horizontal"
+ android:background="@drawable/notification_2025_expand_button_pill_bg"
+ android:gravity="center"
+ android:layout_gravity="center_vertical"
+ android:duplicateParentState="true"
+ >
+
+ <TextView
+ android:id="@+id/expand_button_number"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Info"
+ android:gravity="center_vertical"
+ android:visibility="gone"
+ />
+
+ <ImageView
+ android:id="@+id/expand_button_icon"
+ android:layout_width="@dimen/notification_2025_expand_button_icon_size"
+ android:layout_height="@dimen/notification_2025_expand_button_icon_size"
+ android:scaleType="fitCenter"
+ android:importantForAccessibility="no"
+ />
+
+ </LinearLayout>
+
+</com.android.internal.widget.NotificationExpandButton>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_base.xml b/core/res/res/layout/notification_2025_template_collapsed_base.xml
index e91e1115ac1c..c827dcb16584 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_base.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_base.xml
@@ -164,10 +164,11 @@
android:minWidth="@dimen/notification_content_margin_end"
>
- <include layout="@layout/notification_expand_button"
+ <include layout="@layout/notification_2025_expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
+ android:layout_gravity="top|end"
+ android:layout_margin="@dimen/notification_2025_margin"
/>
</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_call.xml b/core/res/res/layout/notification_2025_template_collapsed_call.xml
index c4bca1142ece..ce38c1645fb1 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_call.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_call.xml
@@ -66,10 +66,11 @@
>
<include
- layout="@layout/notification_expand_button"
+ layout="@layout/notification_2025_expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
+ android:layout_gravity="top|end"
+ android:layout_margin="@dimen/notification_2025_margin"
/>
</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_media.xml b/core/res/res/layout/notification_2025_template_collapsed_media.xml
index 2d367337bb6f..0021b8384847 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_media.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_media.xml
@@ -185,10 +185,11 @@
android:minWidth="@dimen/notification_content_margin_end"
>
- <include layout="@layout/notification_expand_button"
+ <include layout="@layout/notification_2025_expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
+ android:layout_gravity="top|end"
+ android:layout_margin="@dimen/notification_2025_margin"
/>
</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
index fbecb8c30b9c..f3e4ce13ff4b 100644
--- a/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
+++ b/core/res/res/layout/notification_2025_template_collapsed_messaging.xml
@@ -189,10 +189,11 @@
android:minWidth="@dimen/notification_content_margin_end"
>
- <include layout="@layout/notification_expand_button"
+ <include layout="@layout/notification_2025_expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center_vertical|end"
+ android:layout_gravity="top|end"
+ android:layout_margin="@dimen/notification_2025_margin"
/>
</FrameLayout>
diff --git a/core/res/res/layout/notification_2025_template_conversation.xml b/core/res/res/layout/notification_2025_template_conversation.xml
index f31f65e90950..6be5a1cee7f9 100644
--- a/core/res/res/layout/notification_2025_template_conversation.xml
+++ b/core/res/res/layout/notification_2025_template_conversation.xml
@@ -148,10 +148,11 @@
android:clipToPadding="false"
android:clipChildren="false"
/>
- <include layout="@layout/notification_expand_button"
+ <include layout="@layout/notification_2025_expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="center"
+ android:layout_gravity="top|end"
+ android:layout_margin="@dimen/notification_2025_margin"
/>
</LinearLayout>
</LinearLayout>
diff --git a/core/res/res/layout/notification_2025_template_expanded_base.xml b/core/res/res/layout/notification_2025_template_expanded_base.xml
index e480fe5eef1e..d364c659d0db 100644
--- a/core/res/res/layout/notification_2025_template_expanded_base.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_base.xml
@@ -40,13 +40,14 @@
<include layout="@layout/notification_2025_template_header" />
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/notification_2025_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:layout_marginTop="@dimen/notification_content_margin_top"
android:orientation="vertical"
>
diff --git a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
index 18bafe068fcb..12e11728f608 100644
--- a/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_big_picture.xml
@@ -32,11 +32,12 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_content_margin_top"
android:clipToPadding="false"
android:orientation="vertical"
>
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_2025_template_expanded_big_text.xml b/core/res/res/layout/notification_2025_template_expanded_big_text.xml
index 9ff141b7c946..c9dd868795de 100644
--- a/core/res/res/layout/notification_2025_template_expanded_big_text.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_big_text.xml
@@ -30,12 +30,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginBottom="@dimen/notification_content_margin"
android:clipToPadding="false"
android:orientation="vertical"
>
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<com.android.internal.widget.RemeasuringLinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_2025_template_expanded_call.xml b/core/res/res/layout/notification_2025_template_expanded_call.xml
index 2af0ec2972df..0be61253c917 100644
--- a/core/res/res/layout/notification_2025_template_expanded_call.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_call.xml
@@ -48,8 +48,8 @@
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:layout_marginStart="@dimen/notification_2025_content_margin_start"
+ android:layout_weight="1"
android:orientation="vertical"
android:minHeight="68dp"
>
diff --git a/core/res/res/layout/notification_2025_template_expanded_inbox.xml b/core/res/res/layout/notification_2025_template_expanded_inbox.xml
index 9fb44ccccfa0..8434b3644f81 100644
--- a/core/res/res/layout/notification_2025_template_expanded_inbox.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_inbox.xml
@@ -28,10 +28,11 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_content_margin_top"
android:clipToPadding="false"
android:orientation="vertical">
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_2025_template_expanded_media.xml b/core/res/res/layout/notification_2025_template_expanded_media.xml
index 578a0b2b6d0b..e90ab792581f 100644
--- a/core/res/res/layout/notification_2025_template_expanded_media.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_media.xml
@@ -34,11 +34,12 @@
android:id="@+id/notification_media_content"
>
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/notification_content_margin_top"
android:layout_marginStart="@dimen/notification_2025_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:orientation="vertical"
diff --git a/core/res/res/layout/notification_2025_template_expanded_messaging.xml b/core/res/res/layout/notification_2025_template_expanded_messaging.xml
index e3c201465eb0..7f5a36b5f865 100644
--- a/core/res/res/layout/notification_2025_template_expanded_messaging.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_messaging.xml
@@ -33,10 +33,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
- android:layout_marginTop="@dimen/notification_2025_header_height"
android:clipChildren="false"
android:orientation="vertical">
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<com.android.internal.widget.RemeasuringLinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
diff --git a/core/res/res/layout/notification_2025_template_expanded_progress.xml b/core/res/res/layout/notification_2025_template_expanded_progress.xml
index afa4bc6dd7f8..5d4fc4c87fac 100644
--- a/core/res/res/layout/notification_2025_template_expanded_progress.xml
+++ b/core/res/res/layout/notification_2025_template_expanded_progress.xml
@@ -41,13 +41,14 @@
<include layout="@layout/notification_2025_template_header" />
+ <!-- Note: the top margin is being set in code based on the estimated space needed for
+ the header text. -->
<LinearLayout
android:id="@+id/notification_main_column"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/notification_2025_content_margin_start"
android:layout_marginEnd="@dimen/notification_content_margin_end"
- android:layout_marginTop="@dimen/notification_content_margin_top"
android:orientation="vertical"
>
diff --git a/core/res/res/layout/notification_2025_template_header.xml b/core/res/res/layout/notification_2025_template_header.xml
index 2d30d8a8bbb6..3f34eb3cbf0c 100644
--- a/core/res/res/layout/notification_2025_template_header.xml
+++ b/core/res/res/layout/notification_2025_template_header.xml
@@ -57,11 +57,11 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_top_line"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:layout_alignParentStart="true"
- android:layout_centerVertical="true"
android:layout_toStartOf="@id/expand_button"
android:layout_alignWithParentIfMissing="true"
+ android:layout_marginVertical="@dimen/notification_2025_margin"
android:clipChildren="false"
android:gravity="center_vertical"
android:paddingStart="@dimen/notification_2025_content_margin_start"
@@ -81,10 +81,11 @@
android:focusable="false"
/>
- <include layout="@layout/notification_expand_button"
+ <include layout="@layout/notification_2025_expand_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_centerVertical="true"
+ android:layout_gravity="top|end"
+ android:layout_margin="@dimen/notification_2025_margin"
android:layout_alignParentEnd="true" />
<include layout="@layout/notification_close_button"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index fb21c7532ea3..a4735fe6c7af 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -310,9 +310,15 @@
<!-- Size of the stroke with for the emphasized notification button style -->
<dimen name="emphasized_button_stroke_width">1dp</dimen>
- <!-- height of the content margin to accomodate for the header -->
+ <!-- height of the content margin to accommodate for the header -->
<dimen name="notification_content_margin_top">50dp</dimen>
+ <!-- The spacing between the content and the header text above it, scaling with text size.
+ This value is chosen so that, taking into account the text spacing for both the text in the
+ top line and the text in the content, the distance between them is 4dp with the default
+ screen configuration (and will grow accordingly for larger font sizes) -->
+ <dimen name="notification_2025_content_margin_top">10sp</dimen>
+
<!-- height of the content margin that is applied at the end of the notification content -->
<dimen name="notification_content_margin">20dp</dimen>
@@ -384,9 +390,24 @@
<!-- the height of the expand button pill -->
<dimen name="notification_expand_button_pill_height">24dp</dimen>
+ <!-- the height of the expand button pill (2025 redesign version) -->
+ <dimen name="notification_2025_expand_button_pill_height">20dp</dimen>
+
+ <!-- the width of the expand button pill (2025 redesign version) -->
+ <dimen name="notification_2025_expand_button_pill_width">28dp</dimen>
+
+ <!-- the size of the expand arrow (2025 redesign version) -->
+ <dimen name="notification_2025_expand_button_icon_size">16sp</dimen>
+
<!-- the padding of the expand icon in the notification header -->
<dimen name="notification_expand_button_icon_padding">2dp</dimen>
+ <!-- the padding of the expand icon in the notification header -->
+ <dimen name="notification_2025_expand_button_vertical_icon_padding">2dp</dimen>
+
+ <!-- the padding of the expand icon in the notification header -->
+ <dimen name="notification_2025_expand_button_horizontal_icon_padding">6dp</dimen>
+
<!-- the size of the notification close button -->
<dimen name="notification_close_button_size">16dp</dimen>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cfc3ddca27eb..33d3858562af 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -246,6 +246,8 @@
<string name="NetworkPreferenceSwitchSummary">Try changing preferred network. Tap to change.</string>
<!-- Displayed to tell the user that emergency calls might not be available. -->
<string name="EmergencyCallWarningTitle">Emergency calling unavailable</string>
+ <!-- Displayed to tell the user that the notification can be permanently turned off -->
+ <string name="emergency_calling_do_not_show_again">Do Not Show Again</string>
<!-- Displayed to tell the user that emergency calls might not be available; this is shown to
the user when only WiFi calling is available and the carrier does not support emergency
calls over WiFi calling. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8195d38993c8..6ee2839788af 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -640,6 +640,7 @@
<java-symbol type="string" name="auto_data_switch_title" />
<java-symbol type="string" name="auto_data_switch_content" />
<java-symbol type="string" name="RestrictedStateContentMsimTemplate" />
+ <java-symbol type="string" name="emergency_calling_do_not_show_again" />
<java-symbol type="string" name="notification_channel_network_alert" />
<java-symbol type="string" name="notification_channel_call_forward" />
<java-symbol type="string" name="notification_channel_emergency_callback" />
@@ -3229,6 +3230,8 @@
<java-symbol type="id" name="header_text_divider" />
<java-symbol type="id" name="header_text_secondary_divider" />
<java-symbol type="drawable" name="ic_expand_notification" />
+ <java-symbol type="drawable" name="ic_notification_2025_collapse" />
+ <java-symbol type="drawable" name="ic_notification_2025_expand" />
<java-symbol type="drawable" name="ic_collapse_notification" />
<java-symbol type="drawable" name="notification_close_button_icon" />
<java-symbol type="drawable" name="ic_expand_bundle" />
@@ -3241,6 +3244,8 @@
<java-symbol type="dimen" name="notification_heading_margin_end" />
<java-symbol type="dimen" name="notification_content_margin_top" />
<java-symbol type="dimen" name="notification_content_margin" />
+ <java-symbol type="dimen" name="notification_2025_margin" />
+ <java-symbol type="dimen" name="notification_2025_content_margin_top" />
<java-symbol type="dimen" name="notification_progress_margin_horizontal" />
<java-symbol type="dimen" name="notification_header_background_height" />
<java-symbol type="dimen" name="notification_header_touchable_height" />
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index a270848b98a3..8fa510381060 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -302,48 +302,48 @@ public class DisplayManagerGlobalTest {
@Test
@RequiresFlagsEnabled(Flags.FLAG_DISPLAY_LISTENER_PERFORMANCE_IMPROVEMENTS)
- public void testMapFlagsToInternalEventFlag() {
+ public void testMapFiltersToInternalEventFlag() {
// Test public flags mapping
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_ADDED,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_ADDED, 0));
+ .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_ADDED, 0));
assertEquals(DISPLAY_CHANGE_EVENTS, mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED, 0));
+ .mapFiltersToInternalEventFlag(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED, 0));
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_REMOVED,
- mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED, 0));
+ mDisplayManagerGlobal.mapFiltersToInternalEventFlag(
+ DisplayManager.EVENT_TYPE_DISPLAY_REMOVED, 0));
assertEquals(INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(
- DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE,
+ .mapFiltersToInternalEventFlag(
+ DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE,
0));
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_STATE,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(
- DisplayManager.EVENT_FLAG_DISPLAY_STATE,
+ .mapFiltersToInternalEventFlag(
+ DisplayManager.EVENT_TYPE_DISPLAY_STATE,
0));
// test private flags mapping
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(0,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED));
+ .mapFiltersToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED));
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_HDR_SDR_RATIO_CHANGED,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(0,
- DisplayManager.PRIVATE_EVENT_FLAG_HDR_SDR_RATIO_CHANGED));
+ .mapFiltersToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_TYPE_HDR_SDR_RATIO_CHANGED));
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(0,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ .mapFiltersToInternalEventFlag(0,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
// Test both public and private flags mapping
assertEquals(DisplayManagerGlobal.INTERNAL_EVENT_FLAG_DISPLAY_BRIGHTNESS_CHANGED
| INTERNAL_EVENT_FLAG_DISPLAY_REFRESH_RATE,
mDisplayManagerGlobal
- .mapFlagsToInternalEventFlag(
- DisplayManager.EVENT_FLAG_DISPLAY_REFRESH_RATE,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ .mapFiltersToInternalEventFlag(
+ DisplayManager.EVENT_TYPE_DISPLAY_REFRESH_RATE,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
}
private void waitForHandler() {
diff --git a/graphics/java/android/graphics/BlendModeColorFilter.java b/graphics/java/android/graphics/BlendModeColorFilter.java
index 7caeb4267ad2..d4e23732bdc3 100644
--- a/graphics/java/android/graphics/BlendModeColorFilter.java
+++ b/graphics/java/android/graphics/BlendModeColorFilter.java
@@ -71,7 +71,7 @@ public final class BlendModeColorFilter extends ColorFilter {
return false;
}
final BlendModeColorFilter other = (BlendModeColorFilter) object;
- return other.mMode == mMode;
+ return (other.mMode == mMode && other.mColor == mColor);
}
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/RearDisplayPresentationRequestCallback.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/RearDisplayPresentationRequestCallback.java
index ea33426d0bdf..9f978e000493 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/RearDisplayPresentationRequestCallback.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/area/RearDisplayPresentationRequestCallback.java
@@ -43,10 +43,7 @@ public class RearDisplayPresentationRequestCallback implements DeviceStateReques
public RearDisplayPresentationRequestCallback(@NonNull Context context,
@NonNull RearDisplayPresentationController rearDisplayPresentationController) {
mDisplayManager = context.getSystemService(DisplayManager.class);
- mDisplayManager.registerDisplayListener(mRearDisplayListener,
- context.getMainThreadHandler(), DisplayManager.EVENT_FLAG_DISPLAY_ADDED
- | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
-
+ registerDisplayListener(context);
mRearDisplayPresentationController = rearDisplayPresentationController;
}
@@ -112,4 +109,10 @@ public class RearDisplayPresentationRequestCallback implements DeviceStateReques
mRearDisplayPresentationController.startSession(rearDisplay);
}
}
+
+ private void registerDisplayListener(Context context) {
+ mDisplayManager.registerDisplayListener(mRearDisplayListener,
+ context.getMainThreadHandler(), DisplayManager.EVENT_TYPE_DISPLAY_ADDED
+ | DisplayManager.EVENT_TYPE_DISPLAY_CHANGED);
+ }
}
diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml b/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml
index f8f8338e5f04..fd578a959e3b 100644
--- a/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml
+++ b/libs/WindowManager/Shell/multivalentTests/AndroidManifest.xml
@@ -3,6 +3,8 @@
<application android:debuggable="true" android:supportsRtl="true" >
<uses-library android:name="android.test.runner" />
+ <activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarAnimationHelperTest$TestActivity"
+ android:exported="true"/>
</application>
<instrumentation
diff --git a/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml b/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml
index ffcd7d46fbae..bb111dbeffff 100644
--- a/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml
+++ b/libs/WindowManager/Shell/multivalentTests/AndroidManifestRobolectric.xml
@@ -1,3 +1,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.wm.shell.multivalenttests">
+ <application>
+ <activity android:name="com.android.wm.shell.bubbles.bar.BubbleBarAnimationHelperTest$TestActivity"
+ android:exported="true"/>
+ </application>
</manifest>
+
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
index 2b4e5417f188..c62d2a06bad5 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleControllerBubbleBarTest.kt
@@ -35,11 +35,11 @@ import com.android.internal.statusbar.IStatusBarService
import com.android.wm.shell.Flags
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.WindowManagerShellWrapper
import com.android.wm.shell.bubbles.Bubbles.SysuiProxy
import com.android.wm.shell.bubbles.properties.ProdBubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayImeController
import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
@@ -268,7 +268,8 @@ class BubbleControllerBubbleBarTest {
bubbleDataRepository,
mock<IStatusBarService>(),
mock<WindowManager>(),
- WindowManagerShellWrapper(mainExecutor),
+ mock<DisplayInsetsController>(),
+ mock<DisplayImeController>(),
mock<UserManager>(),
mock<LauncherApps>(),
bubbleLogger,
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt
index 680d015dfd2f..3043e2bcb0be 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/BubbleViewInfoTaskTest.kt
@@ -36,10 +36,10 @@ import com.android.internal.statusbar.IStatusBarService
import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.WindowManagerShellWrapper
import com.android.wm.shell.bubbles.properties.BubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayImeController
import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
@@ -141,7 +141,8 @@ class BubbleViewInfoTaskTest {
bubbleDataRepository,
mock<IStatusBarService>(),
windowManager,
- WindowManagerShellWrapper(mainExecutor),
+ mock<DisplayInsetsController>(),
+ mock<DisplayImeController>(),
mock<UserManager>(),
mock<LauncherApps>(),
bubbleLogger,
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
index 3e01256fd67c..957f0ca502a1 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelperTest.kt
@@ -17,14 +17,19 @@
package com.android.wm.shell.bubbles.bar
import android.animation.AnimatorTestRule
+import android.app.Activity
import android.app.ActivityManager
import android.content.Context
import android.graphics.Insets
+import android.graphics.Outline
import android.graphics.Rect
+import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import android.widget.FrameLayout
+import android.widget.FrameLayout.LayoutParams
+import androidx.test.core.app.ActivityScenario
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -63,6 +68,7 @@ import org.mockito.kotlin.whenever
class BubbleBarAnimationHelperTest {
@get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
+ private lateinit var activityScenario: ActivityScenario<TestActivity>
companion object {
const val SCREEN_WIDTH = 2000
@@ -83,6 +89,8 @@ class BubbleBarAnimationHelperTest {
fun setUp() {
ProtoLog.REQUIRE_PROTOLOGTOOL = false
ProtoLog.init()
+ activityScenario = ActivityScenario.launch(TestActivity::class.java)
+ activityScenario.onActivity { activity -> container = activity.container }
val windowManager = context.getSystemService(WindowManager::class.java)
bubblePositioner = BubblePositioner(context, windowManager)
bubblePositioner.setShowingInBubbleBar(true)
@@ -102,8 +110,6 @@ class BubbleBarAnimationHelperTest {
mainExecutor = TestShellExecutor()
bgExecutor = TestShellExecutor()
- container = FrameLayout(context)
-
animationHelper = BubbleBarAnimationHelper(context, bubblePositioner)
}
@@ -121,7 +127,7 @@ class BubbleBarAnimationHelperTest {
val semaphore = Semaphore(0)
val after = Runnable { semaphore.release() }
- getInstrumentation().runOnMainSync {
+ activityScenario.onActivity {
animationHelper.animateSwitch(fromBubble, toBubble, after)
animatorTestRule.advanceTimeBy(1000)
}
@@ -145,7 +151,7 @@ class BubbleBarAnimationHelperTest {
.updateHandleColor(/* isRegionDark= */ true, /* animated= */ false)
val toBubble = createBubble(key = "to").initialize(container)
- getInstrumentation().runOnMainSync {
+ activityScenario.onActivity {
animationHelper.animateSwitch(fromBubble, toBubble, /* afterAnimation= */ null)
animatorTestRule.advanceTimeBy(1000)
}
@@ -161,7 +167,7 @@ class BubbleBarAnimationHelperTest {
val toBubbleTaskController = mock<TaskViewTaskController>()
val toBubble = createBubble("to", toBubbleTaskController).initialize(container)
- getInstrumentation().runOnMainSync {
+ activityScenario.onActivity {
animationHelper.animateSwitch(fromBubble, toBubble) {}
// Start the animation, but don't finish
animatorTestRule.advanceTimeBy(100)
@@ -183,7 +189,7 @@ class BubbleBarAnimationHelperTest {
val semaphore = Semaphore(0)
val after = Runnable { semaphore.release() }
- getInstrumentation().runOnMainSync {
+ activityScenario.onActivity {
animationHelper.animateSwitch(fromBubble, overflow, after)
animatorTestRule.advanceTimeBy(1000)
}
@@ -206,7 +212,7 @@ class BubbleBarAnimationHelperTest {
val semaphore = Semaphore(0)
val after = Runnable { semaphore.release() }
- getInstrumentation().runOnMainSync {
+ activityScenario.onActivity {
animationHelper.animateSwitch(overflow, toBubble, after)
animatorTestRule.advanceTimeBy(1000)
}
@@ -226,7 +232,7 @@ class BubbleBarAnimationHelperTest {
val taskController = mock<TaskViewTaskController>()
val bubble = createBubble("key", taskController).initialize(container)
- getInstrumentation().runOnMainSync {
+ activityScenario.onActivity {
animationHelper.animateExpansion(bubble) {}
animatorTestRule.advanceTimeBy(1000)
}
@@ -243,6 +249,80 @@ class BubbleBarAnimationHelperTest {
verify(taskController).setWindowBounds(any())
}
+ @Test
+ fun animateExpansion() {
+ val bubble = createBubble(key = "b1").initialize(container)
+ val bbev = bubble.bubbleBarExpandedView!!
+
+ val semaphore = Semaphore(0)
+ val after = Runnable { semaphore.release() }
+
+ activityScenario.onActivity {
+ bbev.onTaskCreated()
+ animationHelper.animateExpansion(bubble, after)
+ animatorTestRule.advanceTimeBy(1000)
+ }
+ getInstrumentation().waitForIdleSync()
+
+ assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
+ assertThat(bbev.alpha).isEqualTo(1)
+ }
+
+ @Test
+ fun onImeTopChanged_noOverlap() {
+ val bubble = createBubble(key = "b1").initialize(container)
+ val bbev = bubble.bubbleBarExpandedView!!
+
+ val semaphore = Semaphore(0)
+ val after = Runnable { semaphore.release() }
+
+ activityScenario.onActivity {
+ bbev.onTaskCreated()
+ animationHelper.animateExpansion(bubble, after)
+ animatorTestRule.advanceTimeBy(1000)
+ }
+ getInstrumentation().waitForIdleSync()
+
+ assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
+
+ val bbevBottom = bbev.contentBottomOnScreen + bubblePositioner.insets.top
+ activityScenario.onActivity {
+ // notify that the IME top coordinate is greater than the bottom of the expanded view.
+ // there's no overlap so it should not be clipped.
+ animationHelper.onImeTopChanged(bbevBottom * 2)
+ }
+ val outline = Outline()
+ bbev.outlineProvider.getOutline(bbev, outline)
+ assertThat(outline.mRect.bottom).isEqualTo(bbev.height)
+ }
+
+ @Test
+ fun onImeTopChanged_overlapsWithExpandedView() {
+ val bubble = createBubble(key = "b1").initialize(container)
+ val bbev = bubble.bubbleBarExpandedView!!
+
+ val semaphore = Semaphore(0)
+ val after = Runnable { semaphore.release() }
+
+ activityScenario.onActivity {
+ bbev.onTaskCreated()
+ animationHelper.animateExpansion(bubble, after)
+ animatorTestRule.advanceTimeBy(1000)
+ }
+ getInstrumentation().waitForIdleSync()
+
+ assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
+
+ activityScenario.onActivity {
+ // notify that the IME top coordinate is less than the bottom of the expanded view,
+ // meaning it overlaps with it so we should be clipping the expanded view.
+ animationHelper.onImeTopChanged(bbev.contentBottomOnScreen - 10)
+ }
+ val outline = Outline()
+ bbev.outlineProvider.getOutline(bbev, outline)
+ assertThat(outline.mRect.bottom).isEqualTo(bbev.height - 10)
+ }
+
private fun createBubble(
key: String,
taskViewTaskController: TaskViewTaskController = mock<TaskViewTaskController>(),
@@ -273,14 +353,24 @@ class BubbleBarAnimationHelperTest {
}
private fun Bubble.initialize(container: ViewGroup): Bubble {
- getInstrumentation().runOnMainSync { container.addView(bubbleBarExpandedView) }
+ activityScenario.onActivity { container.addView(bubbleBarExpandedView) }
// Mark taskView's visible
bubbleBarExpandedView!!.onContentVisibilityChanged(true)
return this
}
private fun BubbleOverflow.initialize(container: ViewGroup): BubbleOverflow {
- getInstrumentation().runOnMainSync { container.addView(bubbleBarExpandedView) }
+ activityScenario.onActivity { container.addView(bubbleBarExpandedView) }
return this
}
+
+ class TestActivity : Activity() {
+ lateinit var container: FrameLayout
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ container = FrameLayout(applicationContext)
+ container.layoutParams = LayoutParams(50, 50)
+ setContentView(container)
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
index 5c86b321b60f..9b1645e9534c 100644
--- a/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
+++ b/libs/WindowManager/Shell/multivalentTests/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerViewTest.kt
@@ -37,7 +37,6 @@ import com.android.internal.statusbar.IStatusBarService
import com.android.wm.shell.R
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.WindowManagerShellWrapper
import com.android.wm.shell.bubbles.Bubble
import com.android.wm.shell.bubbles.BubbleController
import com.android.wm.shell.bubbles.BubbleData
@@ -54,6 +53,7 @@ import com.android.wm.shell.bubbles.animation.AnimatableScaleMatrix
import com.android.wm.shell.bubbles.properties.BubbleProperties
import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayImeController
import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.SyncTransactionQueue
@@ -180,7 +180,8 @@ class BubbleBarLayerViewTest {
bubbleDataRepository,
mock<IStatusBarService>(),
windowManager,
- WindowManagerShellWrapper(mainExecutor),
+ mock<DisplayInsetsController>(),
+ mock<DisplayImeController>(),
mock<UserManager>(),
mock<LauncherApps>(),
bubbleLogger,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 9aba3aaa3268..348f13a493b1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -90,13 +90,15 @@ import com.android.launcher3.icons.BubbleIconFactory;
import com.android.wm.shell.Flags;
import com.android.wm.shell.R;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.bubbles.properties.BubbleProperties;
import com.android.wm.shell.bubbles.shortcut.BubbleShortcutHelper;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ExternalInterfaceBinder;
import com.android.wm.shell.common.FloatingContentCoordinator;
+import com.android.wm.shell.common.ImeListener;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SingleInstanceRemoteListener;
@@ -106,7 +108,6 @@ import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
-import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.shared.annotations.ShellBackgroundThread;
import com.android.wm.shell.shared.annotations.ShellMainThread;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -182,7 +183,8 @@ public class BubbleController implements ConfigurationChangeListener,
@Nullable private final BubbleStackView.SurfaceSynchronizer mSurfaceSynchronizer;
private final FloatingContentCoordinator mFloatingContentCoordinator;
private final BubbleDataRepository mDataRepository;
- private final WindowManagerShellWrapper mWindowManagerShellWrapper;
+ private final DisplayInsetsController mDisplayInsetsController;
+ private final DisplayImeController mDisplayImeController;
private final UserManager mUserManager;
private final LauncherApps mLauncherApps;
private final IStatusBarService mBarService;
@@ -291,7 +293,8 @@ public class BubbleController implements ConfigurationChangeListener,
BubbleDataRepository dataRepository,
@Nullable IStatusBarService statusBarService,
WindowManager windowManager,
- WindowManagerShellWrapper windowManagerShellWrapper,
+ DisplayInsetsController displayInsetsController,
+ DisplayImeController displayImeController,
UserManager userManager,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
@@ -318,7 +321,8 @@ public class BubbleController implements ConfigurationChangeListener,
ServiceManager.getService(Context.STATUS_BAR_SERVICE))
: statusBarService;
mWindowManager = windowManager;
- mWindowManagerShellWrapper = windowManagerShellWrapper;
+ mDisplayInsetsController = displayInsetsController;
+ mDisplayImeController = displayImeController;
mUserManager = userManager;
mFloatingContentCoordinator = floatingContentCoordinator;
mDataRepository = dataRepository;
@@ -403,11 +407,15 @@ public class BubbleController implements ConfigurationChangeListener,
mMainExecutor.execute(() -> removeBubble(bubble.getKey(), DISMISS_INVALID_INTENT));
});
- try {
- mWindowManagerShellWrapper.addPinnedStackListener(new BubblesImeListener());
- } catch (RemoteException e) {
- e.printStackTrace();
- }
+ BubblesImeListener bubblesImeListener =
+ new BubblesImeListener(mDisplayController, mContext.getDisplayId());
+ // the insets controller is notified whenever the IME visibility changes whether the IME is
+ // requested by a bubbled task or non-bubbled task. in the latter case, we need to update
+ // the position of the stack to avoid overlapping with the IME.
+ mDisplayInsetsController.addInsetsChangedListener(mContext.getDisplayId(),
+ bubblesImeListener);
+ // the ime controller is notified when the IME is requested only by a bubbled task.
+ mDisplayImeController.addPositionProcessor(bubblesImeListener);
mBubbleData.setCurrentUserId(mCurrentUserId);
@@ -2515,16 +2523,57 @@ public class BubbleController implements ConfigurationChangeListener,
return contextForUser.getPackageManager();
}
- /** PinnedStackListener that dispatches IME visibility updates to the stack. */
- //TODO(b/170442945): Better way to do this / insets listener?
- private class BubblesImeListener extends PinnedStackListenerForwarder.PinnedTaskListener {
+ /** {@link ImeListener} that dispatches IME visibility updates to the stack. */
+ private class BubblesImeListener extends ImeListener implements
+ DisplayImeController.ImePositionProcessor {
+
+ BubblesImeListener(DisplayController displayController, int displayId) {
+ super(displayController, displayId);
+ }
+
@Override
- public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
- mBubblePositioner.setImeVisible(imeVisible, imeHeight);
+ protected void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
+ if (getDisplayId() != mContext.getDisplayId()) {
+ return;
+ }
+ // the imeHeight here is actually the ime inset; it only includes the part of the ime
+ // that overlaps with the Bubbles window. adjust it to include the bottom screen inset,
+ // so we have the total height of the ime.
+ int totalImeHeight = imeHeight + mBubblePositioner.getInsets().bottom;
+ mBubblePositioner.setImeVisible(imeVisible, totalImeHeight);
if (mStackView != null) {
mStackView.setImeVisible(imeVisible);
}
}
+
+ @Override
+ public int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
+ boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
+ if (mContext.getDisplayId() != displayId) {
+ return IME_ANIMATION_DEFAULT;
+ }
+
+ if (showing) {
+ mBubblePositioner.setImeVisible(true, hiddenTop - shownTop);
+ } else {
+ mBubblePositioner.setImeVisible(false, 0);
+ }
+ if (mStackView != null) {
+ mStackView.setImeVisible(showing);
+ }
+
+ return IME_ANIMATION_DEFAULT;
+ }
+
+ @Override
+ public void onImePositionChanged(int displayId, int imeTop, SurfaceControl.Transaction t) {
+ if (mContext.getDisplayId() != displayId) {
+ return;
+ }
+ if (mLayerView != null) {
+ mLayerView.onImeTopChanged(imeTop);
+ }
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index de85d9af127d..1a61793eab87 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -67,6 +67,11 @@ public class BubblePositioner {
private @Surface.Rotation int mRotation = Surface.ROTATION_0;
private Insets mInsets;
private boolean mImeVisible;
+ /**
+ * The height of the IME excluding the bottom inset. If the IME is 100 pixels tall and we have
+ * 20 pixels bottom inset, the IME height is adjusted to 80 to represent the overlap with the
+ * Bubbles window.
+ */
private int mImeHeight;
private Rect mPositionRect;
private int mDefaultMaxBubbles;
@@ -336,10 +341,16 @@ public class BubblePositioner {
return mImeVisible;
}
- /** Sets whether the IME is visible. **/
+ /**
+ * Sets whether the IME is visible and its height.
+ *
+ * @param visible whether the IME is visible
+ * @param height the total height of the IME from the bottom of the physical screen
+ **/
public void setImeVisible(boolean visible, int height) {
mImeVisible = visible;
- mImeHeight = height;
+ // adjust the IME to account for the height as seen by the Bubbles window
+ mImeHeight = visible ? Math.max(height - getInsets().bottom, 0) : 0;
}
private int getExpandedViewLargeScreenInsetFurthestEdge(boolean isOverflow) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 3188e5b9c6d2..de6d1f6c8852 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -30,6 +30,8 @@ import static com.android.wm.shell.bubbles.bar.BubbleBarExpandedView.TASK_VIEW_A
import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED;
import static com.android.wm.shell.shared.animation.Interpolators.EMPHASIZED_DECELERATE;
+import static java.lang.Math.max;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -375,7 +377,6 @@ public class BubbleBarAnimationHelper {
return animator;
}
-
/**
* Animate the expanded bubble when it is being dragged
*/
@@ -586,6 +587,18 @@ public class BubbleBarAnimationHelper {
}
}
+ /** Handles IME position changes. */
+ public void onImeTopChanged(int imeTop) {
+ BubbleBarExpandedView bbev = getExpandedView();
+ if (bbev == null) {
+ Log.w(TAG, "Bubble bar expanded view was null when IME top changed");
+ return;
+ }
+ int bbevBottom = bbev.getContentBottomOnScreen();
+ int clip = max(bbevBottom - imeTop, 0);
+ bbev.updateBottomClip(clip);
+ }
+
private @Nullable BubbleBarExpandedView getExpandedView() {
BubbleViewProvider bubble = mExpandedBubble;
if (bubble != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
index 65c929ab6fb4..e073b02dc630 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedView.java
@@ -137,6 +137,7 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
private Executor mBackgroundExecutor;
private final Rect mSampleRect = new Rect();
private final int[] mLoc = new int[2];
+ private final Rect mTempBounds = new Rect();
/** Height of the caption inset at the top of the TaskView */
private int mCaptionHeight;
@@ -161,6 +162,9 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
private boolean mIsAnimating;
private boolean mIsDragging;
+ private boolean mIsClipping = false;
+ private int mBottomClip = 0;
+
/** An enum value that tracks the visibility state of the task view */
private enum TaskViewVisibilityState {
/** The task view is going away, and we're waiting for the surface to be destroyed. */
@@ -203,7 +207,8 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
setOutlineProvider(new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mCurrentCornerRadius);
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight() - mBottomClip,
+ mCurrentCornerRadius);
}
});
// Set a touch sink to ensure that clicks on the caption area do not propagate to the parent
@@ -661,6 +666,52 @@ public class BubbleBarExpandedView extends FrameLayout implements BubbleTaskView
}
}
+ /** The y coordinate of the bottom of the expanded view. */
+ public int getContentBottomOnScreen() {
+ if (mOverflowView != null) {
+ mOverflowView.getBoundsOnScreen(mTempBounds);
+ }
+ if (mTaskView != null) {
+ mTaskView.getBoundsOnScreen(mTempBounds);
+ }
+ // return the bottom of the content rect, adjusted for insets so the result is in screen
+ // coordinate
+ return mTempBounds.bottom + mPositioner.getInsets().top;
+ }
+
+ /** Update the amount by which to clip the expanded view at the bottom. */
+ public void updateBottomClip(int bottomClip) {
+ mBottomClip = bottomClip;
+ onClipUpdate();
+ }
+
+ private void onClipUpdate() {
+ if (mBottomClip == 0) {
+ if (mIsClipping) {
+ mIsClipping = false;
+ if (mTaskView != null) {
+ mTaskView.setClipBounds(null);
+ mTaskView.setEnableSurfaceClipping(false);
+ }
+ invalidateOutline();
+ }
+ } else {
+ if (!mIsClipping) {
+ mIsClipping = true;
+ if (mTaskView != null) {
+ mTaskView.setEnableSurfaceClipping(true);
+ }
+ }
+ invalidateOutline();
+ if (mTaskView != null) {
+ Rect clipBounds = new Rect(0, 0,
+ mTaskView.getWidth(),
+ mTaskView.getHeight() - mBottomClip);
+ mTaskView.setClipBounds(clipBounds);
+ }
+ }
+ }
+
private void recreateRegionSamplingHelper() {
if (mRegionSamplingHelper != null) {
mRegionSamplingHelper.stopAndDestroy();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 88f34f3043e1..eaa0bd250fc4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -424,6 +424,13 @@ public class BubbleBarLayerView extends FrameLayout
}
}
+ /** Handles IME position changes. */
+ public void onImeTopChanged(int imeTop) {
+ if (mIsExpanded) {
+ mAnimationHelper.onImeTopChanged(imeTop);
+ }
+ }
+
/**
* Log the event only if {@link #mExpandedBubble} is a {@link Bubble}.
* <p>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
index 9ebb7f5aa270..eb1e72790a25 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayImeController.java
@@ -419,8 +419,12 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
// already (e.g., when focussing an editText in activity B, while and editText in
// activity A is focussed), we will not get a call of #insetsControlChanged, and
// therefore have to start the show animation from here
- startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */,
- statsToken);
+ if (visible || mImeShowing) {
+ // only start the animation if we're either already showing or becoming visible.
+ // otherwise starting another hide animation causes flickers.
+ startAnimation(mImeRequestedVisible /* show */, false /* forceRestart */,
+ statsToken);
+ }
// In case of a hide, the statsToken should not been send yet (as the animation
// is still ongoing). It will be sent at the end of the animation
@@ -723,6 +727,10 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
* Allows other things to synchronize with the ime position
*/
public interface ImePositionProcessor {
+
+ /** Default animation flags. */
+ int IME_ANIMATION_DEFAULT = 0;
+
/**
* Indicates that ime shouldn't animate alpha. It will always be opaque. Used when stuff
* behind the IME shouldn't be visible (for example during split-screen adjustment where
@@ -732,6 +740,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
/** @hide */
@IntDef(prefix = {"IME_ANIMATION_"}, value = {
+ IME_ANIMATION_DEFAULT,
IME_ANIMATION_NO_ALPHA,
})
@interface ImeAnimationFlags {
@@ -758,7 +767,7 @@ public class DisplayImeController implements DisplayController.OnDisplaysChanged
@ImeAnimationFlags
default int onImeStartPositioning(int displayId, int hiddenTop, int shownTop,
boolean showing, boolean isFloating, SurfaceControl.Transaction t) {
- return 0;
+ return IME_ANIMATION_DEFAULT;
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt
index a34d7bed497b..8851b6a2107d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/ImeListener.kt
@@ -22,8 +22,8 @@ import android.view.InsetsState
import com.android.wm.shell.common.DisplayInsetsController.OnInsetsChangedListener
abstract class ImeListener(
- private val mDisplayController: DisplayController,
- private val mDisplayId: Int
+ private val displayController: DisplayController,
+ val displayId: Int
) : OnInsetsChangedListener {
// The last insets state
private val mInsetsState = InsetsState()
@@ -36,17 +36,11 @@ abstract class ImeListener(
// Get the stable bounds that account for display cutout and system bars to calculate the
// relative IME height
- val layout = mDisplayController.getDisplayLayout(mDisplayId)
- if (layout == null) {
- return
- }
+ val layout = displayController.getDisplayLayout(displayId) ?: return
layout.getStableBounds(mTmpBounds)
- val wasVisible = getImeVisibilityAndHeight(mInsetsState).first
- val oldHeight = getImeVisibilityAndHeight(mInsetsState).second
-
- val isVisible = getImeVisibilityAndHeight(insetsState).first
- val newHeight = getImeVisibilityAndHeight(insetsState).second
+ val (wasVisible, oldHeight) = getImeVisibilityAndHeight(mInsetsState)
+ val (isVisible, newHeight) = getImeVisibilityAndHeight(insetsState)
mInsetsState.set(insetsState, true)
if (wasVisible != isVisible || oldHeight != newHeight) {
@@ -54,8 +48,7 @@ abstract class ImeListener(
}
}
- private fun getImeVisibilityAndHeight(
- insetsState: InsetsState): Pair<Boolean, Int> {
+ private fun getImeVisibilityAndHeight(insetsState: InsetsState): Pair<Boolean, Int> {
val source = insetsState.peekSource(InsetsSource.ID_IME)
val frame = if (source != null && source.isVisible) source.frame else null
val height = if (frame != null) mTmpBounds.bottom - frame.top else 0
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index d02c6b05e5b6..d8c7f4cbb698 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -47,7 +47,6 @@ import com.android.launcher3.icons.IconProvider;
import com.android.window.flags.Flags;
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.activityembedding.ActivityEmbeddingController;
import com.android.wm.shell.apptoweb.AppToWebGenericLinksParser;
import com.android.wm.shell.apptoweb.AssistContentRequester;
@@ -233,7 +232,8 @@ public abstract class WMShellModule {
FloatingContentCoordinator floatingContentCoordinator,
IStatusBarService statusBarService,
WindowManager windowManager,
- WindowManagerShellWrapper windowManagerShellWrapper,
+ DisplayInsetsController displayInsetsController,
+ DisplayImeController displayImeController,
UserManager userManager,
LauncherApps launcherApps,
TaskStackListenerImpl taskStackListener,
@@ -265,7 +265,8 @@ public abstract class WMShellModule {
new BubblePersistentRepository(context)),
statusBarService,
windowManager,
- windowManagerShellWrapper,
+ displayInsetsController,
+ displayImeController,
userManager,
launcherApps,
logger,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
index fd387d1811fb..37296531ee34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipMotionHelper.java
@@ -350,7 +350,7 @@ public class PipMotionHelper implements PipAppOpsListener.Callback,
}
cancelPhysicsAnimation();
mMenuController.hideMenu(ANIM_TYPE_DISMISS, false /* resize */);
- mPipScheduler.removePipAfterAnimation();
+ mPipScheduler.scheduleRemovePip();
}
/** Sets the movement bounds to use to constrain PIP position animations. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
index 4461a5c6a70c..7f673d2efc68 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipScheduler.java
@@ -122,34 +122,26 @@ public class PipScheduler {
* Schedules exit PiP via expand transition.
*/
public void scheduleExitPipViaExpand() {
- WindowContainerTransaction wct = getExitPipViaExpandTransaction();
- if (wct != null) {
- mMainExecutor.execute(() -> {
+ mMainExecutor.execute(() -> {
+ if (!mPipTransitionState.isInPip()) return;
+ WindowContainerTransaction wct = getExitPipViaExpandTransaction();
+ if (wct != null) {
mPipTransitionController.startExitTransition(TRANSIT_EXIT_PIP, wct,
null /* destinationBounds */);
- });
- }
- }
-
- // TODO: Optimize this by running the animation as part of the transition
- /** Runs remove PiP animation and schedules remove PiP transition after the animation ends. */
- public void removePipAfterAnimation() {
- SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
- PipAlphaAnimator animator = mPipAlphaAnimatorSupplier.get(mContext,
- mPipTransitionState.getPinnedTaskLeash(), tx, PipAlphaAnimator.FADE_OUT);
- animator.setAnimationEndCallback(this::scheduleRemovePipImmediately);
- animator.start();
+ }
+ });
}
/** Schedules remove PiP transition. */
- private void scheduleRemovePipImmediately() {
- WindowContainerTransaction wct = getRemovePipTransaction();
- if (wct != null) {
- mMainExecutor.execute(() -> {
+ public void scheduleRemovePip() {
+ mMainExecutor.execute(() -> {
+ if (!mPipTransitionState.isInPip()) return;
+ WindowContainerTransaction wct = getRemovePipTransaction();
+ if (wct != null) {
mPipTransitionController.startExitTransition(TRANSIT_REMOVE_PIP, wct,
null /* destinationBounds */);
- });
- }
+ }
+ });
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index acb5622b041c..2e38449d4584 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -278,7 +278,8 @@ public class PipTransition extends PipTransitionController implements
}
if (isRemovePipTransition(info)) {
- return removePipImmediately(info, startTransaction, finishTransaction, finishCallback);
+ mPipTransitionState.setState(PipTransitionState.EXITING_PIP);
+ return startRemoveAnimation(info, startTransaction, finishTransaction, finishCallback);
}
return false;
}
@@ -668,13 +669,18 @@ public class PipTransition extends PipTransitionController implements
return true;
}
- private boolean removePipImmediately(@NonNull TransitionInfo info,
+ private boolean startRemoveAnimation(@NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- startTransaction.apply();
- finishCallback.onTransitionFinished(null);
- mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
+ TransitionInfo.Change pipChange = getChangeByToken(info,
+ mPipTransitionState.getPipTaskToken());
+ mFinishCallback = finishCallback;
+ PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipChange.getLeash(),
+ startTransaction, PipAlphaAnimator.FADE_OUT);
+ finishTransaction.setAlpha(pipChange.getLeash(), 0f);
+ animator.setAnimationEndCallback(this::finishTransition);
+ animator.start();
return true;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 246760e361cd..535112f5124a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -746,6 +746,7 @@ public class StageCoordinator implements SplitLayout.SplitLayoutHandler,
ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "Reordering hide-task to bottom");
wct.reorder(hideTaskToken, false /* onTop */);
}
+ prepareTasksForSplitScreen(new int[] {taskId}, wct);
wct.startTask(taskId, options);
// If this should be mixed, send the task to avoid split handle transition directly.
if (mMixedHandler != null && mMixedHandler.isTaskInPip(taskId, mTaskOrganizer)) {
diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopViaMenuOfStaticOverviewTaskTest.kt
index f72f74e8b3b9..fac749be40f1 100644
--- a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.aidl
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/functional/EnterDesktopViaMenuOfStaticOverviewTaskTest.kt
@@ -14,7 +14,14 @@
* limitations under the License.
*/
-package android.nfc;
+package com.android.wm.shell.functional
-parcelable T4tNdefNfceeCcFileInfo;
+import android.platform.test.annotations.Postsubmit
+import com.android.wm.shell.scenarios.EnterDesktopViaMenuOfStaticOverviewTask
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+/* Functional test for [EnterDesktopViaMenuOfStaticOverviewTask]. */
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+class EnterDesktopViaMenuOfStaticOverviewTaskTest : EnterDesktopViaMenuOfStaticOverviewTask()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopViaMenuOfStaticOverviewTask.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopViaMenuOfStaticOverviewTask.kt
new file mode 100644
index 000000000000..57647d6aa5df
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopViaMenuOfStaticOverviewTask.kt
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ * 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.scenarios
+
+import android.app.Instrumentation
+import android.tools.NavBar
+import android.tools.Rotation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.MailAppHelper
+import com.android.window.flags.Flags
+import com.android.wm.shell.Utils
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+
+@Ignore("Base Test Class")
+abstract class EnterDesktopViaMenuOfStaticOverviewTask constructor() {
+
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val tapl = LauncherInstrumentation()
+ private val wmHelper = WindowManagerStateHelper(instrumentation)
+ private val device = UiDevice.getInstance(instrumentation)
+ private val mailApp = MailAppHelper(instrumentation)
+
+ @Rule
+ @JvmField
+ val testSetupRule = Utils.testSetupRule(NavBar.MODE_GESTURAL, Rotation.ROTATION_0)
+
+ @Before
+ fun setup() {
+ Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+ // Clear all tasks
+ val overview = tapl.goHome().switchToOverview()
+ if (overview.hasTasks()) {
+ overview.dismissAllTasks()
+ }
+ mailApp.open()
+ tapl.goHome().switchToOverview()
+ }
+
+ @Test
+ open fun desktopViaMenuOfStaticOverviewTask() {
+ tapl.overview.getCurrentTask().tapMenu().tapDesktopMenuItem()
+ }
+
+ @After
+ fun teardown() {
+ mailApp.exit()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
index f40edaebec5e..6e0dcdb21fa8 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
+++ b/libs/WindowManager/Shell/tests/flicker/pip/Android.bp
@@ -115,6 +115,11 @@ test_module_config {
"com.android.wm.shell.flicker.pip.PipPinchInTest",
"com.android.wm.shell.flicker.pip.SetRequestedOrientationWhilePinned",
"com.android.wm.shell.flicker.pip.ShowPipAndRotateDisplay",
+ "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfAutoEnterPipOnGoToHomeTest",
+ "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipOnUserLeaveHintTest",
+ "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipViaAppUiButtonTest",
+ "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfExitPipToAppViaExpandButtonTest",
+ "com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfExitPipToAppViaIntentTest",
],
test_suites: ["device-tests"],
}
@@ -266,12 +271,7 @@ test_module_config {
test_suites: ["device-tests"],
}
-test_module_config {
- name: "WMShellFlickerTestsPip-nonMatchParent",
- base: "WMShellFlickerTestsPip",
- include_filters: ["com.android.wm.shell.flicker.pip.nonmatchparent.*"],
- test_suites: ["device-tests"],
-}
+// Not-match Parent test cases
test_module_config {
name: "WMShellFlickerTestsPip-BottomHalfExitPipToAppViaExpandButtonTest",
@@ -287,5 +287,26 @@ test_module_config {
test_suites: ["device-tests"],
}
+test_module_config {
+ name: "WMShellFlickerTestsPip-BottomHalfAutoEnterPipOnGoToHomeTest",
+ base: "WMShellFlickerTestsPip",
+ include_filters: ["com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfAutoEnterPipOnGoToHomeTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "WMShellFlickerTestsPip-BottomHalfEnterPipOnUserLeaveHintTest",
+ base: "WMShellFlickerTestsPip",
+ include_filters: ["com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipOnUserLeaveHintTest"],
+ test_suites: ["device-tests"],
+}
+
+test_module_config {
+ name: "WMShellFlickerTestsPip-BottomHalfEnterPipViaAppUiButtonTest",
+ base: "WMShellFlickerTestsPip",
+ include_filters: ["com.android.wm.shell.flicker.pip.nonmatchparent.BottomHalfEnterPipViaAppUiButtonTest"],
+ test_suites: ["device-tests"],
+}
+
// End breakdowns for WMShellFlickerTestsPip module
////////////////////////////////////////////////////////////////////////////////
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
index 609a2849f915..84d53d59e7df 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/AutoEnterPipOnGoToHomeTest.kt
@@ -24,20 +24,16 @@ import android.platform.test.annotations.RequiresFlagsDisabled
import android.tools.flicker.junit.FlickerParametersRunnerFactory
import android.tools.flicker.legacy.FlickerBuilder
import android.tools.flicker.legacy.LegacyFlickerTest
-import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder
-import android.tools.flicker.subject.exceptions.IncorrectRegionException
-import android.tools.flicker.subject.layers.LayerSubject
import com.android.server.wm.flicker.helpers.PipAppHelper
import com.android.wm.shell.Flags
import com.android.wm.shell.flicker.pip.common.EnterPipTransition
+import com.android.wm.shell.flicker.pip.common.widthNotSmallerThan
import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
-import kotlin.math.abs
-
/**
* Test entering pip from an app via auto-enter property when navigating to home.
@@ -77,22 +73,6 @@ open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTran
}
}
- override val defaultTeardown: FlickerBuilder.() -> Unit = { teardown { pipApp.exit(wmHelper) } }
-
- private val widthNotSmallerThan: LayerSubject.(LayerSubject) -> Unit = {
- val width = visibleRegion.region.bounds.width()
- val otherWidth = it.visibleRegion.region.bounds.width()
- if (width < otherWidth && abs(width - otherWidth) > EPSILON) {
- val errorMsgBuilder =
- ExceptionMessageBuilder()
- .forSubject(this)
- .forIncorrectRegion("width. $width smaller than $otherWidth")
- .setExpected(width)
- .setActual(otherWidth)
- throw IncorrectRegionException(errorMsgBuilder)
- }
- }
-
@Postsubmit
@Test
override fun pipLayerReduces() {
@@ -161,9 +141,4 @@ open class AutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) : EnterPipTran
override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
super.visibleLayersShownMoreThanOneConsecutiveEntry()
}
-
- companion object {
- // TODO(b/363080056): A margin of error allowed on certain layer size calculations.
- const val EPSILON = 1
- }
}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
index 4399a237bcbb..38f37b4bc1d2 100644
--- a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/EnterPipOnUserLeaveHintTest.kt
@@ -88,6 +88,7 @@ class EnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) : EnterPipTransiti
super.pipOverlayLayerAppearThenDisappear()
}
+ // TODO(b/385086051): check if we can remove optional = true in the test.
@Presubmit
@Test
fun pipAppWindowVisibleChanges() {
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipUtils.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipUtils.kt
new file mode 100644
index 000000000000..3b98d9b99130
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/common/PipUtils.kt
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ * 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.flicker.pip.common
+
+import android.tools.flicker.subject.exceptions.ExceptionMessageBuilder
+import android.tools.flicker.subject.exceptions.IncorrectRegionException
+import android.tools.flicker.subject.layers.LayerSubject
+import kotlin.math.abs
+
+// TODO(b/363080056): A margin of error allowed on certain layer size calculations.
+const val EPSILON = 1
+
+internal val widthNotSmallerThan: LayerSubject.(LayerSubject) -> Unit = {
+ val width = visibleRegion.region.bounds.width()
+ val otherWidth = it.visibleRegion.region.bounds.width()
+ if (width < otherWidth && abs(width - otherWidth) > EPSILON) {
+ val errorMsgBuilder =
+ ExceptionMessageBuilder()
+ .forSubject(this)
+ .forIncorrectRegion("width. $width smaller than $otherWidth")
+ .setExpected(width)
+ .setActual(otherWidth)
+ throw IncorrectRegionException(errorMsgBuilder)
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfAutoEnterPipOnGoToHomeTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfAutoEnterPipOnGoToHomeTest.kt
new file mode 100644
index 000000000000..89f02266ce35
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfAutoEnterPipOnGoToHomeTest.kt
@@ -0,0 +1,170 @@
+/*
+ * 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.
+ * 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.flicker.pip.nonmatchparent
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import androidx.test.filters.FlakyTest
+import com.android.window.flags.Flags
+import com.android.wm.shell.flicker.pip.common.widthNotSmallerThan
+import org.junit.Assume
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test entering pip from an app with non-match parent layout via auto-enter property when
+ * navigating to home.
+ *
+ * To run this test: `atest WMShellFlickerTestsPip:BottomHalfAutoEnterPipOnGoToHomeTest`
+ *
+ * Actions:
+ * ```
+ * Launch [BottomHalfPipLaunchingActivity] in full screen
+ * Launch [BottomHalfPipActivity] with bottom half layout
+ * Select "Auto-enter PiP" radio button
+ * Press Home button or swipe up to go Home and put [BottomHalfPipActivity] in pip mode
+ * ```
+ *
+ * Notes:
+ * ```
+ * 1. All assertions are inherited from [EnterPipTest]
+ * 2. Part of the test setup occurs automatically via
+ * [android.tools.flicker.legacy.runner.TransitionRunner],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ * ```
+ */
+// TODO(b/380796448): re-enable tests after the support of non-match parent PIP animation for PIP2.
+@RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
+@RequiresFlagsEnabled(Flags.FLAG_BETTER_SUPPORT_NON_MATCH_PARENT_ACTIVITY)
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class BottomHalfAutoEnterPipOnGoToHomeTest(flicker: LegacyFlickerTest) :
+ BottomHalfEnterPipTransition(flicker) {
+
+ override val thisTransition: FlickerBuilder.() -> Unit = { transitions {
+ tapl.goHome()
+ pipApp.waitForPip(wmHelper)
+ } }
+
+ override val defaultEnterPip: FlickerBuilder.() -> Unit = {
+ setup {
+ pipApp.launchViaIntent(wmHelper)
+ pipApp.enableAutoEnterForPipActivity()
+ }
+ }
+
+ @FlakyTest(bugId = 289943985)
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ }
+
+ /* Gestural Navigation */
+
+ /**
+ * Checks that [pipApp] window's width is first decreasing then increasing.
+ *
+ * In gestural navigation mode, auto entering PiP can initially make the layer smaller before it
+ * gets larger.
+ * This tests verifies the width of the PiP layer first decreases and then increases due to
+ * size and scale animations going to different directions.
+ *
+ * Note that we still allow a margin of error of 1px, since around the time
+ * of handoff between gesture nav task view simulator and
+ * SwipePipToHomeAnimator, crop can get a bit smaller and scale can get a
+ * bit larger if swiped aggressively - this can produce off-by-1 errors for
+ * width too.
+ */
+ @Postsubmit
+ @Test
+ fun pipLayerWidthDecreasesThenIncreases() {
+ Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+ flicker.assertLayers {
+ val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
+ var previousLayer = pipLayerList[0]
+ var currentLayer = previousLayer
+ var i = 0
+ invoke("layer area is decreasing") {
+ if (i < pipLayerList.size - 1) {
+ previousLayer = currentLayer
+ currentLayer = pipLayerList[++i]
+ previousLayer.widthNotSmallerThan(currentLayer)
+ }
+ }.then().invoke("layer are is increasing", true /* isOptional */) {
+ if (i < pipLayerList.size - 1) {
+ previousLayer = currentLayer
+ currentLayer = pipLayerList[++i]
+ currentLayer.widthNotSmallerThan(previousLayer)
+ }
+ }
+ }
+ }
+
+ /* 3-button Navigation */
+
+ /**
+ * The PIP layer reduces continuously in 3-Button navigation mode.
+ */
+ @Postsubmit
+ @Test
+ override fun pipLayerReduces() {
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ flicker.assertLayers {
+ val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.notBiggerThan(previous.visibleRegion.region)
+ }
+ }
+ }
+
+ /** Checks that [pipApp] window is animated towards default position in right bottom corner */
+ @FlakyTest(bugId = 255578530)
+ @Test
+ fun pipLayerMovesTowardsRightBottomCorner() {
+ // in gestural nav the swipe makes PiP first go upwards
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ flicker.assertLayers {
+ val pipLayerList = this.layers { pipApp.layerMatchesAnyOf(it) && it.isVisible }
+ // Pip animates towards the right bottom corner, but because it is being resized at the
+ // same time, it is possible it shrinks first quickly below the default position and get
+ // moved up after that in just few last frames
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.isToTheRightBottom(previous.visibleRegion.region, 3)
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ override fun focusChanges() {
+ // in gestural nav the focus goes to different activity on swipe up
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.focusChanges()
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipOnUserLeaveHintTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipOnUserLeaveHintTest.kt
new file mode 100644
index 000000000000..8642b6c779e4
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipOnUserLeaveHintTest.kt
@@ -0,0 +1,168 @@
+/*
+ * 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.
+ * 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.flicker.pip.nonmatchparent
+
+import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.window.flags.Flags
+import org.junit.Assume
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test entering pip from an app with bottom half layout via [onUserLeaveHint] and by navigating to
+ * home.
+ *
+ * To run this test: `atest WMShellFlickerTestsPip:BottomHalfEnterPipOnUserLeaveHintTest`
+ *
+ * Actions:
+ * ```
+ * Launch [BottomHalfPipLaunchingActivity] in full screen
+ * Launch [BottomHalfPipActivity] with bottom half layout
+ * Select "Via code behind" radio button
+ * Press Home button or swipe up to go Home and put [pipApp] in pip mode
+ * ```
+ * Notes:
+ * ```
+ * 1. All assertions are inherited from [EnterPipTest]
+ * 2. Part of the test setup occurs automatically via
+ * [android.tools.flicker.legacy.runner.TransitionRunner],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ * ```
+ */
+// TODO(b/380796448): re-enable tests after the support of non-match parent PIP animation for PIP2.
+@RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
+@RequiresFlagsEnabled(Flags.FLAG_BETTER_SUPPORT_NON_MATCH_PARENT_ACTIVITY)
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class BottomHalfEnterPipOnUserLeaveHintTest(flicker: LegacyFlickerTest) :
+ BottomHalfEnterPipTransition(flicker)
+{
+ override val thisTransition: FlickerBuilder.() -> Unit = { transitions {
+ tapl.goHome()
+ pipApp.waitForPip(wmHelper)
+ } }
+
+ override val defaultEnterPip: FlickerBuilder.() -> Unit = {
+ setup {
+ pipApp.launchViaIntent(wmHelper)
+ pipApp.enableEnterPipOnUserLeaveHint()
+ }
+ }
+
+ // gestural navigation
+
+ // TODO(b/385086051): check if we can remove optional = true in the test.
+ @Presubmit
+ @Test
+ fun pipAppWindowVisibleChanges() {
+ // pip layer in gesture nav will disappear during transition
+ Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+ flicker.assertWm {
+ this.isAppWindowVisible(pipApp)
+ .then()
+ .isAppWindowInvisible(pipApp, isOptional = true)
+ .then()
+ .isAppWindowVisible(pipApp, isOptional = true)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipAppLayerVisibleChanges() {
+ Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+ // pip layer in gesture nav will disappear during transition
+ flicker.assertLayers {
+ this.isVisible(pipApp).then().isInvisible(pipApp).then().isVisible(pipApp)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun pipLayerRemainInsideVisibleBounds() {
+ // pip layer in gesture nav will disappear during transition
+ Assume.assumeTrue(flicker.scenario.isGesturalNavigation)
+ // pip layer in gesture nav will disappear during transition
+ flicker.assertLayersStart { this.visibleRegion(pipApp).coversAtMost(displayBounds) }
+ flicker.assertLayersEnd { this.visibleRegion(pipApp).coversAtMost(displayBounds) }
+ }
+
+ // 3-button navigation
+
+ @Presubmit
+ @Test
+ override fun pipAppWindowAlwaysVisible() {
+ // In gestural nav the pip will first move behind home and then above home. The visual
+ // appearance visible->invisible->visible is asserted by pipAppLayerAlwaysVisible().
+ // But the internal states of activity don't need to follow that, such as a temporary
+ // visibility state can be changed quickly outside a transaction so the test doesn't
+ // detect that. Hence, skip the case to avoid restricting the internal implementation.
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipAppWindowAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ override fun pipAppLayerAlwaysVisible() {
+ // pip layer in gesture nav will disappear during transition
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipAppLayerAlwaysVisible()
+ }
+
+ @Presubmit
+ @Test
+ override fun pipOverlayLayerAppearThenDisappear() {
+ // no overlay in gesture nav for non-auto enter PiP transition
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipOverlayLayerAppearThenDisappear()
+ }
+
+ @Presubmit
+ @Test
+ override fun pipLayerReduces() {
+ // in gestural nav the pip enters through alpha animation
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipLayerReduces()
+ }
+
+ @Presubmit
+ @Test
+ override fun focusChanges() {
+ // in gestural nav the focus goes to different activity on swipe up
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.focusChanges()
+ }
+
+ @Presubmit
+ @Test
+ override fun pipLayerOrOverlayRemainInsideVisibleBounds() {
+ // pip layer in gesture nav will disappear during transition
+ Assume.assumeFalse(flicker.scenario.isGesturalNavigation)
+ super.pipLayerOrOverlayRemainInsideVisibleBounds()
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipTransition.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipTransition.kt
new file mode 100644
index 000000000000..a455de96b25d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipTransition.kt
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ * 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.flicker.pip.nonmatchparent
+
+import android.platform.test.annotations.Presubmit
+import android.tools.flicker.legacy.LegacyFlickerTest
+import com.android.server.wm.flicker.helpers.BottomHalfPipAppHelper
+import com.android.server.wm.flicker.helpers.PipAppHelper
+import com.android.wm.shell.flicker.pip.common.EnterPipTransition
+import org.junit.Test
+
+/**
+ * The base class to test enter PIP animation on bottom half activity.
+ */
+abstract class BottomHalfEnterPipTransition(flicker: LegacyFlickerTest) :
+ EnterPipTransition(flicker)
+{
+ override val pipApp: PipAppHelper = BottomHalfPipAppHelper(
+ instrumentation,
+ useLaunchingActivity = true
+ )
+
+ @Presubmit
+ @Test
+ override fun pipWindowRemainInsideVisibleBounds() {
+ // We only verify the start and end because we update the layout when
+ // the BottomHalfPipActivity goes to PIP mode, which may lead to intermediate state that
+ // the window frame may be out of the display frame.
+ flicker.assertWmStart { visibleRegion(pipApp).coversAtMost(displayBounds) }
+ flicker.assertLayersEnd { visibleRegion(pipApp).coversAtMost(displayBounds) }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipViaAppUiButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipViaAppUiButtonTest.kt
new file mode 100644
index 000000000000..cfdd4e550504
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/pip/src/com/android/wm/shell/flicker/pip/nonmatchparent/BottomHalfEnterPipViaAppUiButtonTest.kt
@@ -0,0 +1,101 @@
+/*
+ * 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.
+ * 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.flicker.pip.nonmatchparent
+
+import android.platform.test.annotations.Presubmit
+import android.platform.test.annotations.RequiresDevice
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.tools.flicker.junit.FlickerParametersRunnerFactory
+import android.tools.flicker.legacy.FlickerBuilder
+import android.tools.flicker.legacy.LegacyFlickerTest
+import android.tools.traces.parsers.toFlickerComponent
+import com.android.server.wm.flicker.testapp.ActivityOptions.BottomHalfPip.LAUNCHING_APP_COMPONENT
+import com.android.window.flags.Flags
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test entering pip from an app by interacting with the app UI
+ *
+ * To run this test: `atest WMShellFlickerTestsPip:BottomHalfEnterPipViaAppUiButtonTest`
+ *
+ * Actions:
+ * ```
+ * Launch [BottomHalfPipLaunchingActivity] in full screen
+ * Launch [BottomHalfPipActivity] with bottom half layout
+ * Press an "enter pip" button to put [pipApp] in pip mode
+ * ```
+ *
+ * Notes:
+ * ```
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited from [PipTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [android.tools.flicker.legacy.runner.TransitionRunner],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
+ * ```
+ */
+// TODO(b/380796448): re-enable tests after the support of non-match parent PIP animation for PIP2.
+@RequiresFlagsDisabled(com.android.wm.shell.Flags.FLAG_ENABLE_PIP2)
+@RequiresFlagsEnabled(Flags.FLAG_BETTER_SUPPORT_NON_MATCH_PARENT_ACTIVITY)
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+class BottomHalfEnterPipViaAppUiButtonTest(flicker: LegacyFlickerTest) :
+ BottomHalfEnterPipTransition(flicker)
+{
+ override val thisTransition: FlickerBuilder.() -> Unit = {
+ transitions { pipApp.clickEnterPipButton(wmHelper) }
+ }
+
+ /**
+ * Checks if the focus changes to the launching activity behind when the bottom half [pipApp]
+ * goes to PIP mode.
+ */
+ @Presubmit
+ @Test
+ override fun focusChanges() {
+ flicker.assertEventLog {
+ this.focusChanges(
+ pipApp.packageName,
+ LAUNCHING_APP_COMPONENT.packageName
+ )
+ }
+ }
+
+ @Presubmit
+ @Test
+ override fun launcherLayerBecomesVisible() {
+ // Disable the test since the background activity is BottomHalfPipLaunchingActivity.
+ }
+
+ /**
+ * Checks if the launching activity behind the bottom half [pipApp] is always visible during
+ * the transition.
+ */
+ @Presubmit
+ @Test
+ fun launchingAppLayerAlwaysVisible() {
+ flicker.assertLayers { isVisible(LAUNCHING_APP_COMPONENT.toFlickerComponent()) }
+ }
+} \ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt
index 1f2eaa6757e8..eeb83df48ab5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleViewInfoTest.kt
@@ -33,10 +33,10 @@ import com.android.launcher3.icons.BubbleIconFactory
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
-import com.android.wm.shell.WindowManagerShellWrapper
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView
import com.android.wm.shell.bubbles.properties.BubbleProperties
import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.common.DisplayImeController
import com.android.wm.shell.common.DisplayInsetsController
import com.android.wm.shell.common.FloatingContentCoordinator
import com.android.wm.shell.common.ShellExecutor
@@ -123,7 +123,8 @@ class BubbleViewInfoTest : ShellTestCase() {
mock<BubbleDataRepository>(),
mock<IStatusBarService>(),
windowManager,
- WindowManagerShellWrapper(mainExecutor),
+ mock<DisplayInsetsController>(),
+ mock<DisplayImeController>(),
mock<UserManager>(),
mock<LauncherApps>(),
bubbleLogger,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
index 3fe8c109807a..a8aa25700c7e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipSchedulerTest.java
@@ -120,15 +120,22 @@ public class PipSchedulerTest {
@Test
public void scheduleExitPipViaExpand_nullTaskToken_noop() {
setNullPipTaskToken();
+ when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleExitPipViaExpand();
- verify(mMockMainExecutor, never()).execute(any());
+ verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
+ assertNotNull(mRunnableArgumentCaptor.getValue());
+ mRunnableArgumentCaptor.getValue().run();
+
+ verify(mMockPipTransitionController, never())
+ .startExitTransition(eq(TRANSIT_EXIT_PIP), any(), isNull());
}
@Test
public void scheduleExitPipViaExpand_exitTransitionCalled() {
setMockPipTaskToken();
+ when(mMockPipTransitionState.isInPip()).thenReturn(true);
mPipScheduler.scheduleExitPipViaExpand();
@@ -142,20 +149,13 @@ public class PipSchedulerTest {
@Test
public void removePipAfterAnimation() {
- //TODO: Update once this is changed to run animation as part of transition
setMockPipTaskToken();
+ when(mMockPipTransitionState.isInPip()).thenReturn(true);
- mPipScheduler.removePipAfterAnimation();
- verify(mMockAlphaAnimator, times(1))
- .setAnimationEndCallback(mRunnableArgumentCaptor.capture());
- assertNotNull(mRunnableArgumentCaptor.getValue());
- verify(mMockAlphaAnimator, times(1)).start();
-
- mRunnableArgumentCaptor.getValue().run();
+ mPipScheduler.scheduleRemovePip();
verify(mMockMainExecutor, times(1)).execute(mRunnableArgumentCaptor.capture());
assertNotNull(mRunnableArgumentCaptor.getValue());
-
mRunnableArgumentCaptor.getValue().run();
verify(mMockPipTransitionController, times(1))
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index f7f10df5786a..4f7132ad9ab2 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -324,6 +324,19 @@ public final class MediaProjection {
}
/**
+ * Stops projection.
+ * @hide
+ */
+ public void stop(@StopReason int stopReason) {
+ try {
+ Log.d(TAG, "Content Recording: stopping projection");
+ mImpl.stop(stopReason);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to stop projection", e);
+ }
+ }
+
+ /**
* Get the underlying IMediaProjection.
* @hide
*/
diff --git a/native/android/OWNERS b/native/android/OWNERS
index 1fde7d268517..3ea2d3506f31 100644
--- a/native/android/OWNERS
+++ b/native/android/OWNERS
@@ -29,6 +29,7 @@ per-file surface_texture.cpp = file:/graphics/java/android/graphics/OWNERS
# Input
per-file input.cpp = file:/INPUT_OWNERS
-# PerformanceHint
+# ADPF
per-file performance_hint.cpp = file:/ADPF_OWNERS
+per-file system_health.cpp = file:/ADPF_OWNERS
per-file thermal.cpp = file:/ADPF_OWNERS
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 1ccadf90c2a9..f629c8802aef 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -396,6 +396,7 @@ LIBANDROID {
APerformanceHint_notifyWorkloadSpike; # introduced=36
APerformanceHint_borrowSessionFromJava; # introduced=36
APerformanceHint_setNativeSurfaces; # introduced=36
+ APerformanceHint_isFeatureSupported; # introduced=36
AWorkDuration_create; # introduced=VanillaIceCream
AWorkDuration_release; # introduced=VanillaIceCream
AWorkDuration_setWorkPeriodStartTimestampNanos; # introduced=VanillaIceCream
@@ -419,7 +420,6 @@ LIBANDROID_PLATFORM {
AThermal_setIThermalServiceForTesting;
APerformanceHint_setIHintManagerForTesting;
APerformanceHint_sendHint;
- APerformanceHint_setUseGraphicsPipelineForTesting;
APerformanceHint_getThreadIds;
APerformanceHint_createSessionInternal;
APerformanceHint_createSessionUsingConfigInternal;
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 9257901bcd1f..7e655235732f 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -71,26 +71,31 @@ using android::base::StringPrintf;
struct APerformanceHintSession;
-constexpr int64_t SEND_HINT_TIMEOUT = std::chrono::nanoseconds(100ms).count();
struct AWorkDuration : public hal::WorkDuration {};
struct ASessionCreationConfig : public SessionCreationConfig {
std::vector<wp<IBinder>> layers{};
- bool hasMode(hal::SessionMode&& mode) {
+ bool hasMode(hal::SessionMode mode) {
return std::find(modesToEnable.begin(), modesToEnable.end(), mode) != modesToEnable.end();
}
+ void setMode(hal::SessionMode mode, bool enabled) {
+ if (hasMode(mode)) {
+ if (!enabled) {
+ std::erase(modesToEnable, mode);
+ }
+ } else if (enabled) {
+ modesToEnable.push_back(mode);
+ }
+ }
};
-bool kForceGraphicsPipeline = false;
-
-bool useGraphicsPipeline() {
- return android::os::adpf_graphics_pipeline() || kForceGraphicsPipeline;
-}
-
// A pair of values that determine the behavior of the
// load hint rate limiter, to only allow "X hints every Y seconds"
-constexpr double kLoadHintInterval = std::chrono::nanoseconds(2s).count();
+constexpr int64_t kLoadHintInterval = std::chrono::nanoseconds(2s).count();
constexpr double kMaxLoadHintsPerInterval = 20;
-constexpr double kReplenishRate = kMaxLoadHintsPerInterval / kLoadHintInterval;
+// Replenish rate is used for new rate limiting behavior, it currently replenishes at a rate of
+// 20 / 2s = 1 per 100us, which is the same limit as before, just enforced differently
+constexpr double kReplenishRate = kMaxLoadHintsPerInterval / static_cast<double>(kLoadHintInterval);
+constexpr int64_t kSendHintTimeout = kLoadHintInterval / kMaxLoadHintsPerInterval;
bool kForceNewHintBehavior = false;
template <class T>
@@ -149,9 +154,7 @@ private:
std::future<bool> mChannelCreationFinished;
};
-class SupportInfoWrapper {
-public:
- SupportInfoWrapper(hal::SupportInfo& info);
+struct SupportInfoWrapper : public hal::SupportInfo {
bool isSessionModeSupported(hal::SessionMode mode);
bool isSessionHintSupported(hal::SessionHint hint);
@@ -162,7 +165,6 @@ private:
// over that much and cutting off any extra values
return (supportBitfield >> static_cast<int>(enumValue)) % 2;
}
- hal::SupportInfo mSupportInfo;
};
class HintManagerClient : public IHintManager::BnHintManagerClient {
@@ -188,9 +190,9 @@ public:
bool isJava = false);
APerformanceHintSession* getSessionFromJava(JNIEnv* _Nonnull env, jobject _Nonnull sessionObj);
- APerformanceHintSession* createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
- hal::SessionTag tag = hal::SessionTag::APP,
- bool isJava = false);
+ int createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
+ APerformanceHintSession** sessionPtr,
+ hal::SessionTag tag = hal::SessionTag::APP, bool isJava = false);
int64_t getPreferredRateNanos() const;
int32_t getMaxGraphicsPipelineThreadsCount();
FMQWrapper& getFMQWrapper();
@@ -202,6 +204,7 @@ public:
std::vector<T>& out);
ndk::SpAIBinder& getToken();
SupportInfoWrapper& getSupportInfo();
+ bool isFeatureSupported(APerformanceHintFeature feature);
private:
static APerformanceHintManager* create(std::shared_ptr<IHintManager> iHintManager);
@@ -239,8 +242,8 @@ public:
int setPreferPowerEfficiency(bool enabled);
int reportActualWorkDuration(AWorkDuration* workDuration);
bool isJava();
- status_t setNativeSurfaces(ANativeWindow** windows, int numWindows, ASurfaceControl** controls,
- int numSurfaceControls);
+ status_t setNativeSurfaces(ANativeWindow** windows, size_t numWindows,
+ ASurfaceControl** controls, size_t numSurfaceControls);
private:
friend struct APerformanceHintManager;
@@ -294,14 +297,12 @@ static FMQWrapper& getFMQ() {
// ===================================== SupportInfoWrapper implementation
-SupportInfoWrapper::SupportInfoWrapper(hal::SupportInfo& info) : mSupportInfo(info) {}
-
bool SupportInfoWrapper::isSessionHintSupported(hal::SessionHint hint) {
- return getEnumSupportFromBitfield(hint, mSupportInfo.sessionHints);
+ return getEnumSupportFromBitfield(hint, sessionHints);
}
bool SupportInfoWrapper::isSessionModeSupported(hal::SessionMode mode) {
- return getEnumSupportFromBitfield(mode, mSupportInfo.sessionModes);
+ return getEnumSupportFromBitfield(mode, sessionModes);
}
// ===================================== APerformanceHintManager implementation
@@ -386,12 +387,14 @@ APerformanceHintSession* APerformanceHintManager::createSession(
.targetWorkDurationNanos = initialTargetWorkDurationNanos,
}};
- return APerformanceHintManager::createSessionUsingConfig(&creationConfig, tag, isJava);
+ APerformanceHintSession* sessionOut;
+ APerformanceHintManager::createSessionUsingConfig(&creationConfig, &sessionOut, tag, isJava);
+ return sessionOut;
}
-APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
- ASessionCreationConfig* sessionCreationConfig, hal::SessionTag tag, bool isJava) {
- std::shared_ptr<IHintSession> session;
+int APerformanceHintManager::createSessionUsingConfig(ASessionCreationConfig* sessionCreationConfig,
+ APerformanceHintSession** sessionOut,
+ hal::SessionTag tag, bool isJava) {
hal::SessionConfig sessionConfig{.id = -1};
ndk::ScopedAStatus ret;
@@ -411,31 +414,65 @@ APerformanceHintSession* APerformanceHintManager::createSessionUsingConfig(
}
}
+ bool autoCpu = sessionCreationConfig->hasMode(hal::SessionMode::AUTO_CPU);
+ bool autoGpu = sessionCreationConfig->hasMode(hal::SessionMode::AUTO_GPU);
+
+ if (autoCpu || autoGpu) {
+ LOG_ALWAYS_FATAL_IF(!sessionCreationConfig->hasMode(hal::SessionMode::GRAPHICS_PIPELINE),
+ "Automatic session timing enabled without graphics pipeline mode");
+ }
+
+ if (autoCpu && !mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_CPU)) {
+ ALOGE("Automatic CPU timing enabled but not supported");
+ return ENOTSUP;
+ }
+
+ if (autoGpu && !mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_GPU)) {
+ ALOGE("Automatic GPU timing enabled but not supported");
+ return ENOTSUP;
+ }
+
+ IHintManager::SessionCreationReturn returnValue;
ret = mHintManager->createHintSessionWithConfig(mToken, tag,
*static_cast<SessionCreationConfig*>(
sessionCreationConfig),
- &sessionConfig, &session);
+ &sessionConfig, &returnValue);
sessionCreationConfig->layerTokens.clear();
- if (!ret.isOk() || !session) {
+ if (!ret.isOk() || !returnValue.session) {
ALOGE("%s: PerformanceHint cannot create session. %s", __FUNCTION__, ret.getMessage());
- return nullptr;
+ switch (ret.getExceptionCode()) {
+ case binder::Status::EX_UNSUPPORTED_OPERATION:
+ return ENOTSUP;
+ case binder::Status::EX_ILLEGAL_ARGUMENT:
+ return EINVAL;
+ default:
+ return EPIPE;
+ }
}
- auto out = new APerformanceHintSession(mHintManager, std::move(session),
+ auto out = new APerformanceHintSession(mHintManager, std::move(returnValue.session),
mClientData.preferredRateNanos,
sessionCreationConfig->targetWorkDurationNanos, isJava,
sessionConfig.id == -1
? std::nullopt
: std::make_optional<hal::SessionConfig>(
std::move(sessionConfig)));
+
+ *sessionOut = out;
+
std::scoped_lock lock(sHintMutex);
out->traceThreads(sessionCreationConfig->tids);
out->traceTargetDuration(sessionCreationConfig->targetWorkDurationNanos);
out->traceModes(sessionCreationConfig->modesToEnable);
- return out;
+ if (returnValue.pipelineThreadLimitExceeded) {
+ ALOGE("Graphics pipeline session thread limit exceeded!");
+ return EBUSY;
+ }
+
+ return 0;
}
APerformanceHintSession* APerformanceHintManager::getSessionFromJava(JNIEnv* env,
@@ -480,6 +517,25 @@ SupportInfoWrapper& APerformanceHintManager::getSupportInfo() {
return mSupportInfoWrapper;
}
+bool APerformanceHintManager::isFeatureSupported(APerformanceHintFeature feature) {
+ switch (feature) {
+ case (APERF_HINT_SESSIONS):
+ return mSupportInfoWrapper.usesSessions;
+ case (APERF_HINT_POWER_EFFICIENCY):
+ return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::POWER_EFFICIENCY);
+ case (APERF_HINT_SURFACE_BINDING):
+ return mSupportInfoWrapper.compositionData.isSupported;
+ case (APERF_HINT_GRAPHICS_PIPELINE):
+ return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::GRAPHICS_PIPELINE);
+ case (APERF_HINT_AUTO_CPU):
+ return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_CPU);
+ case (APERF_HINT_AUTO_GPU):
+ return mSupportInfoWrapper.isSessionModeSupported(hal::SessionMode::AUTO_GPU);
+ default:
+ return false;
+ }
+}
+
// ===================================== APerformanceHintSession implementation
constexpr int kNumEnums = enum_size<hal::SessionHint>();
@@ -512,10 +568,6 @@ APerformanceHintSession::~APerformanceHintSession() {
}
int APerformanceHintSession::updateTargetWorkDuration(int64_t targetDurationNanos) {
- if (targetDurationNanos <= 0) {
- ALOGE("%s: targetDurationNanos must be positive", __FUNCTION__);
- return EINVAL;
- }
std::scoped_lock lock(sHintMutex);
if (mTargetDurationNanos == targetDurationNanos) {
return 0;
@@ -546,7 +598,6 @@ int APerformanceHintSession::reportActualWorkDuration(int64_t actualDurationNano
.workPeriodStartTimestampNanos = 0,
.cpuDurationNanos = actualDurationNanos,
.gpuDurationNanos = 0};
-
return reportActualWorkDurationInternal(static_cast<AWorkDuration*>(&workDuration));
}
@@ -556,17 +607,24 @@ bool APerformanceHintSession::isJava() {
int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int64_t now,
const char*) {
- std::scoped_lock lock(sHintMutex);
+ auto& supportInfo = APerformanceHintManager::getInstance()->getSupportInfo();
+
+ // Drop all unsupported hints, there's not much point reporting errors or warnings for this
+ std::erase_if(hints,
+ [&](hal::SessionHint hint) { return !supportInfo.isSessionHintSupported(hint); });
+
if (hints.empty()) {
- return EINVAL;
+ // We successfully sent all hints we were able to, technically
+ return 0;
}
+
for (auto&& hint : hints) {
- if (static_cast<int32_t>(hint) < 0 || static_cast<int32_t>(hint) >= kNumEnums) {
- ALOGE("%s: invalid session hint %d", __FUNCTION__, hint);
- return EINVAL;
- }
+ LOG_ALWAYS_FATAL_IF(static_cast<int32_t>(hint) < 0 ||
+ static_cast<int32_t>(hint) >= kNumEnums,
+ "%s: invalid session hint %d", __FUNCTION__, hint);
}
+ std::scoped_lock lock(sHintMutex);
if (useNewLoadHintBehavior()) {
if (!APerformanceHintManager::getInstance()->canSendLoadHints(hints, now)) {
return EBUSY;
@@ -575,7 +633,7 @@ int APerformanceHintSession::sendHints(std::vector<hal::SessionHint>& hints, int
// keep old rate limiter behavior for legacy flag
else {
for (auto&& hint : hints) {
- if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + SEND_HINT_TIMEOUT)) {
+ if (now < (mLastHintSentTimestamp[static_cast<int32_t>(hint)] + kSendHintTimeout)) {
return EBUSY;
}
}
@@ -651,7 +709,9 @@ int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
}
std::vector<int32_t> tids(threadIds, threadIds + size);
ndk::ScopedAStatus ret = mHintManager->setHintSessionThreads(mHintSession, tids);
- if (!ret.isOk()) {
+
+ // Illegal state means there were too many graphics pipeline threads
+ if (!ret.isOk() && ret.getExceptionCode() != EX_SERVICE_SPECIFIC) {
ALOGE("%s: failed: %s", __FUNCTION__, ret.getMessage());
if (ret.getExceptionCode() == EX_ILLEGAL_ARGUMENT) {
return EINVAL;
@@ -663,8 +723,10 @@ int APerformanceHintSession::setThreads(const int32_t* threadIds, size_t size) {
std::scoped_lock lock(sHintMutex);
traceThreads(tids);
+ bool tooManyThreads =
+ ret.getExceptionCode() == EX_SERVICE_SPECIFIC && ret.getServiceSpecificError() == 5;
- return 0;
+ return tooManyThreads ? EBUSY : 0;
}
int APerformanceHintSession::getThreadIds(int32_t* const threadIds, size_t* size) {
@@ -711,10 +773,16 @@ int APerformanceHintSession::reportActualWorkDuration(AWorkDuration* workDuratio
int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* workDuration) {
int64_t actualTotalDurationNanos = workDuration->durationNanos;
- traceActualDuration(workDuration->durationNanos);
int64_t now = uptimeNanos();
workDuration->timeStampNanos = now;
std::scoped_lock lock(sHintMutex);
+
+ if (mTargetDurationNanos <= 0) {
+ ALOGE("Cannot report work durations if the target duration is not positive.");
+ return EINVAL;
+ }
+
+ traceActualDuration(actualTotalDurationNanos);
mActualWorkDurations.push_back(std::move(*workDuration));
if (actualTotalDurationNanos >= mTargetDurationNanos) {
@@ -757,9 +825,9 @@ int APerformanceHintSession::reportActualWorkDurationInternal(AWorkDuration* wor
return 0;
}
-status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, int numWindows,
+status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, size_t numWindows,
ASurfaceControl** controls,
- int numSurfaceControls) {
+ size_t numSurfaceControls) {
if (!mSessionConfig.has_value()) {
return ENOTSUP;
}
@@ -774,7 +842,10 @@ status_t APerformanceHintSession::setNativeSurfaces(ANativeWindow** windows, int
ndkLayerHandles.emplace_back(ndk::SpAIBinder(AIBinder_fromPlatformBinder(handle)));
}
- mHintSession->associateToLayers(ndkLayerHandles);
+ auto ret = mHintSession->associateToLayers(ndkLayerHandles);
+ if (!ret.isOk()) {
+ return EPIPE;
+ }
return 0;
}
@@ -857,6 +928,11 @@ bool FMQWrapper::startChannel(IHintManager* manager) {
}
return true;
});
+
+ // If we're unit testing the FMQ, we should block for it to finish completing
+ if (gForceFMQEnabled.has_value()) {
+ mChannelCreationFinished.wait();
+ }
}
return isActive();
}
@@ -1029,7 +1105,8 @@ void APerformanceHintSession::traceTargetDuration(int64_t targetDuration) {
ATrace_setCounter((mSessionName + " target duration").c_str(), targetDuration);
}
-// ===================================== C API
+// ===================================== Start of C API
+
APerformanceHintManager* APerformanceHint_getManager() {
return APerformanceHintManager::getInstance();
}
@@ -1037,10 +1114,16 @@ APerformanceHintManager* APerformanceHint_getManager() {
#define VALIDATE_PTR(ptr) \
LOG_ALWAYS_FATAL_IF(ptr == nullptr, "%s: " #ptr " is nullptr", __FUNCTION__);
+#define HARD_VALIDATE_INT(value, cmp) \
+ LOG_ALWAYS_FATAL_IF(!(value cmp), \
+ "%s: Invalid value. Check failed: (" #value " " #cmp \
+ ") with value: %" PRIi64, \
+ __FUNCTION__, static_cast<int64_t>(value));
+
#define VALIDATE_INT(value, cmp) \
if (!(value cmp)) { \
ALOGE("%s: Invalid value. Check failed: (" #value " " #cmp ") with value: %" PRIi64, \
- __FUNCTION__, value); \
+ __FUNCTION__, static_cast<int64_t>(value)); \
return EINVAL; \
}
@@ -1058,19 +1141,27 @@ APerformanceHintSession* APerformanceHint_createSession(APerformanceHintManager*
return manager->createSession(threadIds, size, initialTargetWorkDurationNanos);
}
-APerformanceHintSession* APerformanceHint_createSessionUsingConfig(
- APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig) {
+int APerformanceHint_createSessionUsingConfig(APerformanceHintManager* manager,
+ ASessionCreationConfig* sessionCreationConfig,
+ APerformanceHintSession** sessionOut) {
VALIDATE_PTR(manager);
VALIDATE_PTR(sessionCreationConfig);
- return manager->createSessionUsingConfig(sessionCreationConfig);
+ VALIDATE_PTR(sessionOut);
+ *sessionOut = nullptr;
+
+ return manager->createSessionUsingConfig(sessionCreationConfig, sessionOut);
}
-APerformanceHintSession* APerformanceHint_createSessionUsingConfigInternal(
- APerformanceHintManager* manager, ASessionCreationConfig* sessionCreationConfig,
- SessionTag tag) {
+int APerformanceHint_createSessionUsingConfigInternal(APerformanceHintManager* manager,
+ ASessionCreationConfig* sessionCreationConfig,
+ APerformanceHintSession** sessionOut,
+ SessionTag tag) {
VALIDATE_PTR(manager);
VALIDATE_PTR(sessionCreationConfig);
- return manager->createSessionUsingConfig(sessionCreationConfig,
+ VALIDATE_PTR(sessionOut);
+ *sessionOut = nullptr;
+
+ return manager->createSessionUsingConfig(sessionCreationConfig, sessionOut,
static_cast<hal::SessionTag>(tag));
}
@@ -1111,6 +1202,7 @@ int APerformanceHint_getMaxGraphicsPipelineThreadsCount(APerformanceHintManager*
int APerformanceHint_updateTargetWorkDuration(APerformanceHintSession* session,
int64_t targetDurationNanos) {
VALIDATE_PTR(session)
+ VALIDATE_INT(targetDurationNanos, >= 0)
return session->updateTargetWorkDuration(targetDurationNanos);
}
@@ -1204,13 +1296,23 @@ int APerformanceHint_notifyWorkloadSpike(APerformanceHintSession* session, bool
}
int APerformanceHint_setNativeSurfaces(APerformanceHintSession* session,
- ANativeWindow** nativeWindows, int nativeWindowsSize,
- ASurfaceControl** surfaceControls, int surfaceControlsSize) {
+ ANativeWindow** nativeWindows, size_t nativeWindowsSize,
+ ASurfaceControl** surfaceControls,
+ size_t surfaceControlsSize) {
VALIDATE_PTR(session)
return session->setNativeSurfaces(nativeWindows, nativeWindowsSize, surfaceControls,
surfaceControlsSize);
}
+bool APerformanceHint_isFeatureSupported(APerformanceHintFeature feature) {
+ APerformanceHintManager* manager = APerformanceHintManager::getInstance();
+ if (manager == nullptr) {
+ // Clearly whatever it is isn't supported in this case
+ return false;
+ }
+ return manager->isFeatureSupported(feature);
+}
+
AWorkDuration* AWorkDuration_create() {
return new AWorkDuration();
}
@@ -1265,78 +1367,32 @@ ASessionCreationConfig* ASessionCreationConfig_create() {
void ASessionCreationConfig_release(ASessionCreationConfig* config) {
VALIDATE_PTR(config)
-
delete config;
}
-int ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids, size_t size) {
+void ASessionCreationConfig_setTids(ASessionCreationConfig* config, const pid_t* tids,
+ size_t size) {
VALIDATE_PTR(config)
VALIDATE_PTR(tids)
+ HARD_VALIDATE_INT(size, > 0)
- if (!useGraphicsPipeline()) {
- return ENOTSUP;
- }
-
- if (size <= 0) {
- LOG_ALWAYS_FATAL_IF(size <= 0,
- "%s: Invalid value. Thread id list size should be greater than zero.",
- __FUNCTION__);
- return EINVAL;
- }
config->tids = std::vector<int32_t>(tids, tids + size);
- return 0;
}
-int ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
- int64_t targetWorkDurationNanos) {
+void ASessionCreationConfig_setTargetWorkDurationNanos(ASessionCreationConfig* config,
+ int64_t targetWorkDurationNanos) {
VALIDATE_PTR(config)
- VALIDATE_INT(targetWorkDurationNanos, >= 0)
-
- if (!useGraphicsPipeline()) {
- return ENOTSUP;
- }
-
config->targetWorkDurationNanos = targetWorkDurationNanos;
- return 0;
}
-int ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
+void ASessionCreationConfig_setPreferPowerEfficiency(ASessionCreationConfig* config, bool enabled) {
VALIDATE_PTR(config)
-
- if (!useGraphicsPipeline()) {
- return ENOTSUP;
- }
-
- if (enabled) {
- config->modesToEnable.push_back(hal::SessionMode::POWER_EFFICIENCY);
- } else {
- std::erase(config->modesToEnable, hal::SessionMode::POWER_EFFICIENCY);
- }
- return 0;
+ config->setMode(hal::SessionMode::POWER_EFFICIENCY, enabled);
}
-int ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
+void ASessionCreationConfig_setGraphicsPipeline(ASessionCreationConfig* config, bool enabled) {
VALIDATE_PTR(config)
-
- if (!useGraphicsPipeline()) {
- return ENOTSUP;
- }
-
- if (enabled) {
- config->modesToEnable.push_back(hal::SessionMode::GRAPHICS_PIPELINE);
- } else {
- std::erase(config->modesToEnable, hal::SessionMode::GRAPHICS_PIPELINE);
-
- // Remove automatic timing modes if we turn off GRAPHICS_PIPELINE,
- // as it is a strict pre-requisite for these to run
- std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU);
- std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU);
- }
- return 0;
-}
-
-void APerformanceHint_setUseGraphicsPipelineForTesting(bool enabled) {
- kForceGraphicsPipeline = enabled;
+ config->setMode(hal::SessionMode::GRAPHICS_PIPELINE, enabled);
}
void APerformanceHint_getRateLimiterPropertiesForTesting(int32_t* maxLoadHintsPerInterval,
@@ -1349,47 +1405,21 @@ void APerformanceHint_setUseNewLoadHintBehaviorForTesting(bool newBehavior) {
kForceNewHintBehavior = newBehavior;
}
-int ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config,
- ANativeWindow** nativeWindows, int nativeWindowsSize,
- ASurfaceControl** surfaceControls,
- int surfaceControlsSize) {
+void ASessionCreationConfig_setNativeSurfaces(ASessionCreationConfig* config,
+ ANativeWindow** nativeWindows,
+ size_t nativeWindowsSize,
+ ASurfaceControl** surfaceControls,
+ size_t surfaceControlsSize) {
VALIDATE_PTR(config)
-
APerformanceHintManager::layersFromNativeSurfaces<wp<IBinder>>(nativeWindows, nativeWindowsSize,
surfaceControls,
surfaceControlsSize,
config->layers);
-
- if (config->layers.empty()) {
- return EINVAL;
- }
-
- return 0;
}
-int ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig* _Nonnull config, bool cpu,
- bool gpu) {
+void ASessionCreationConfig_setUseAutoTiming(ASessionCreationConfig* _Nonnull config, bool cpu,
+ bool gpu) {
VALIDATE_PTR(config)
- if ((cpu || gpu) && !config->hasMode(hal::SessionMode::GRAPHICS_PIPELINE)) {
- ALOGE("Automatic timing is not supported unless graphics pipeline mode is enabled first");
- return ENOTSUP;
- }
-
- if (config->hasMode(hal::SessionMode::AUTO_CPU)) {
- if (!cpu) {
- std::erase(config->modesToEnable, hal::SessionMode::AUTO_CPU);
- }
- } else if (cpu) {
- config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_CPU));
- }
-
- if (config->hasMode(hal::SessionMode::AUTO_GPU)) {
- if (!gpu) {
- std::erase(config->modesToEnable, hal::SessionMode::AUTO_GPU);
- }
- } else if (gpu) {
- config->modesToEnable.push_back(static_cast<hal::SessionMode>(hal::SessionMode::AUTO_GPU));
- }
-
- return 0;
+ config->setMode(hal::SessionMode::AUTO_CPU, cpu);
+ config->setMode(hal::SessionMode::AUTO_GPU, gpu);
}
diff --git a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
index e3c10f63abb4..f68fa1a89540 100644
--- a/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
+++ b/native/android/tests/performance_hint/PerformanceHintNativeTest.cpp
@@ -49,12 +49,87 @@ using HalFlagQueue = ::android::AidlMessageQueue<int8_t, SynchronizedReadWrite>;
using namespace android;
using namespace testing;
+constexpr int64_t DEFAULT_TARGET_NS = 16666666L;
+
+template <class T, void (*D)(T*)>
+std::shared_ptr<T> wrapSP(T* incoming) {
+ return incoming == nullptr ? nullptr : std::shared_ptr<T>(incoming, [](T* ptr) { D(ptr); });
+}
+constexpr auto&& wrapSession = wrapSP<APerformanceHintSession, APerformanceHint_closeSession>;
+constexpr auto&& wrapConfig = wrapSP<ASessionCreationConfig, ASessionCreationConfig_release>;
+constexpr auto&& wrapWorkDuration = wrapSP<AWorkDuration, AWorkDuration_release>;
+
+std::shared_ptr<ASessionCreationConfig> createConfig() {
+ return wrapConfig(ASessionCreationConfig_create());
+}
+
+struct ConfigCreator {
+ std::vector<int32_t> tids{1, 2};
+ int64_t targetDuration = DEFAULT_TARGET_NS;
+ bool powerEfficient = false;
+ bool graphicsPipeline = false;
+ std::vector<ANativeWindow*> nativeWindows{};
+ std::vector<ASurfaceControl*> surfaceControls{};
+ bool autoCpu = false;
+ bool autoGpu = false;
+};
+
+struct SupportHelper {
+ bool hintSessions : 1;
+ bool powerEfficiency : 1;
+ bool bindToSurface : 1;
+ bool graphicsPipeline : 1;
+ bool autoCpu : 1;
+ bool autoGpu : 1;
+};
+
+SupportHelper getSupportHelper() {
+ return {
+ .hintSessions = APerformanceHint_isFeatureSupported(APERF_HINT_SESSIONS),
+ .powerEfficiency = APerformanceHint_isFeatureSupported(APERF_HINT_POWER_EFFICIENCY),
+ .bindToSurface = APerformanceHint_isFeatureSupported(APERF_HINT_SURFACE_BINDING),
+ .graphicsPipeline = APerformanceHint_isFeatureSupported(APERF_HINT_GRAPHICS_PIPELINE),
+ .autoCpu = APerformanceHint_isFeatureSupported(APERF_HINT_AUTO_CPU),
+ .autoGpu = APerformanceHint_isFeatureSupported(APERF_HINT_AUTO_GPU),
+ };
+}
+
+SupportHelper getFullySupportedSupportHelper() {
+ return {
+ .hintSessions = true,
+ .powerEfficiency = true,
+ .graphicsPipeline = true,
+ .autoCpu = true,
+ .autoGpu = true,
+ };
+}
+
+std::shared_ptr<ASessionCreationConfig> configFromCreator(ConfigCreator&& creator) {
+ auto config = createConfig();
+
+ ASessionCreationConfig_setTids(config.get(), creator.tids.data(), creator.tids.size());
+ ASessionCreationConfig_setTargetWorkDurationNanos(config.get(), creator.targetDuration);
+ ASessionCreationConfig_setPreferPowerEfficiency(config.get(), creator.powerEfficient);
+ ASessionCreationConfig_setGraphicsPipeline(config.get(), creator.graphicsPipeline);
+ ASessionCreationConfig_setNativeSurfaces(config.get(),
+ creator.nativeWindows.size() > 0
+ ? creator.nativeWindows.data()
+ : nullptr,
+ creator.nativeWindows.size(),
+ creator.surfaceControls.size() > 0
+ ? creator.surfaceControls.data()
+ : nullptr,
+ creator.surfaceControls.size());
+ ASessionCreationConfig_setUseAutoTiming(config.get(), creator.autoCpu, creator.autoGpu);
+ return config;
+}
+
class MockIHintManager : public IHintManager {
public:
MOCK_METHOD(ScopedAStatus, createHintSessionWithConfig,
(const SpAIBinder& token, hal::SessionTag tag,
const SessionCreationConfig& creationConfig, hal::SessionConfig* config,
- std::shared_ptr<IHintSession>* _aidl_return),
+ IHintManager::SessionCreationReturn* _aidl_return),
(override));
MOCK_METHOD(ScopedAStatus, setHintSessionThreads,
(const std::shared_ptr<IHintSession>& hintSession,
@@ -115,8 +190,9 @@ public:
APerformanceHint_getRateLimiterPropertiesForTesting(&mMaxLoadHintsPerInterval,
&mLoadHintInterval);
APerformanceHint_setIHintManagerForTesting(&mMockIHintManager);
- APerformanceHint_setUseGraphicsPipelineForTesting(true);
APerformanceHint_setUseNewLoadHintBehaviorForTesting(true);
+ mTids.push_back(1);
+ mTids.push_back(2);
}
void TearDown() override {
@@ -130,20 +206,22 @@ public:
ON_CALL(*mMockIHintManager, registerClient(_, _))
.WillByDefault(
DoAll(SetArgPointee<1>(mClientData), [] { return ScopedAStatus::ok(); }));
+ ON_CALL(*mMockIHintManager, isRemote()).WillByDefault(Return(true));
return APerformanceHint_getManager();
}
- APerformanceHintSession* createSession(APerformanceHintManager* manager,
- int64_t targetDuration = 56789L, bool isHwui = false) {
+ void prepareSessionMock() {
mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
const int64_t sessionId = 123;
- std::vector<int32_t> tids;
- tids.push_back(1);
- tids.push_back(2);
+
+ mSessionCreationReturn = IHintManager::SessionCreationReturn{
+ .session = mMockSession,
+ .pipelineThreadLimitExceeded = false,
+ };
ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _))
.WillByDefault(DoAll(SetArgPointee<3>(hal::SessionConfig({.id = sessionId})),
- SetArgPointee<4>(std::shared_ptr<IHintSession>(mMockSession)),
+ SetArgPointee<4>(mSessionCreationReturn),
[] { return ScopedAStatus::ok(); }));
ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
@@ -161,48 +239,36 @@ public:
ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] {
return ScopedAStatus::ok();
});
+ }
+
+ std::shared_ptr<APerformanceHintSession> createSession(APerformanceHintManager* manager,
+ int64_t targetDuration = 56789L,
+ bool isHwui = false) {
+ prepareSessionMock();
if (isHwui) {
- return APerformanceHint_createSessionInternal(manager, tids.data(), tids.size(),
- targetDuration, SessionTag::HWUI);
+ return wrapSession(APerformanceHint_createSessionInternal(manager, mTids.data(),
+ mTids.size(), targetDuration,
+ SessionTag::HWUI));
}
- return APerformanceHint_createSession(manager, tids.data(), tids.size(), targetDuration);
+ return wrapSession(APerformanceHint_createSession(manager, mTids.data(), mTids.size(),
+ targetDuration));
}
- APerformanceHintSession* createSessionUsingConfig(APerformanceHintManager* manager,
- SessionCreationConfig config,
- bool isHwui = false) {
- mMockSession = ndk::SharedRefBase::make<NiceMock<MockIHintSession>>();
- const int64_t sessionId = 123;
-
- ON_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _))
- .WillByDefault(DoAll(SetArgPointee<3>(hal::SessionConfig({.id = sessionId})),
- SetArgPointee<4>(std::shared_ptr<IHintSession>(mMockSession)),
- [] { return ScopedAStatus::ok(); }));
-
- ON_CALL(*mMockIHintManager, setHintSessionThreads(_, _)).WillByDefault([] {
- return ScopedAStatus::ok();
- });
- ON_CALL(*mMockSession, sendHint(_)).WillByDefault([] { return ScopedAStatus::ok(); });
- ON_CALL(*mMockSession, setMode(_, true)).WillByDefault([] { return ScopedAStatus::ok(); });
- ON_CALL(*mMockSession, close()).WillByDefault([] { return ScopedAStatus::ok(); });
- ON_CALL(*mMockSession, updateTargetWorkDuration(_)).WillByDefault([] {
- return ScopedAStatus::ok();
- });
- ON_CALL(*mMockSession, reportActualWorkDuration(_, _)).WillByDefault([] {
- return ScopedAStatus::ok();
- });
- ON_CALL(*mMockSession, reportActualWorkDuration2(_)).WillByDefault([] {
- return ScopedAStatus::ok();
- });
-
+ std::shared_ptr<APerformanceHintSession> createSessionUsingConfig(
+ APerformanceHintManager* manager, std::shared_ptr<ASessionCreationConfig>& config,
+ bool isHwui = false) {
+ prepareSessionMock();
+ APerformanceHintSession* session;
+ int out = 0;
if (isHwui) {
- return APerformanceHint_createSessionUsingConfigInternal(
- manager, reinterpret_cast<ASessionCreationConfig*>(&config), SessionTag::HWUI);
+ out = APerformanceHint_createSessionUsingConfigInternal(manager, config.get(), &session,
+ SessionTag::HWUI);
}
- return APerformanceHint_createSessionUsingConfig(manager,
- reinterpret_cast<ASessionCreationConfig*>(
- &config));
+ out = APerformanceHint_createSessionUsingConfig(manager, config.get(), &session);
+ EXPECT_EQ(out, 0);
+
+ return wrapSession(session);
}
void setFMQEnabled(bool enabled) {
@@ -233,11 +299,13 @@ public:
uint32_t mWriteBits = 0x00000002;
std::shared_ptr<NiceMock<MockIHintManager>> mMockIHintManager = nullptr;
std::shared_ptr<NiceMock<MockIHintSession>> mMockSession = nullptr;
+ IHintManager::SessionCreationReturn mSessionCreationReturn;
std::shared_ptr<AidlMessageQueue<hal::ChannelMessage, SynchronizedReadWrite>> mMockFMQ;
std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> mMockFlagQueue;
hardware::EventFlag* mEventFlag;
int kMockQueueSize = 20;
bool mUsingFMQ = false;
+ std::vector<int> mTids;
IHintManager::HintManagerClientData mClientData{
.powerHalVersion = 6,
@@ -273,107 +341,109 @@ bool equalsWithoutTimestamp(hal::WorkDuration lhs, hal::WorkDuration rhs) {
TEST_F(PerformanceHintTest, TestSession) {
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
ASSERT_TRUE(session);
int64_t targetDurationNanos = 10;
EXPECT_CALL(*mMockSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1));
- int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
+ int result = APerformanceHint_updateTargetWorkDuration(session.get(), targetDurationNanos);
EXPECT_EQ(0, result);
// subsequent call with same target should be ignored but return no error
- result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
+ result = APerformanceHint_updateTargetWorkDuration(session.get(), targetDurationNanos);
EXPECT_EQ(0, result);
+ Mock::VerifyAndClearExpectations(mMockSession.get());
+
usleep(2); // Sleep for longer than preferredUpdateRateNanos.
int64_t actualDurationNanos = 20;
std::vector<int64_t> actualDurations;
actualDurations.push_back(20);
EXPECT_CALL(*mMockSession, reportActualWorkDuration2(_)).Times(Exactly(1));
- result = APerformanceHint_reportActualWorkDuration(session, actualDurationNanos);
+ EXPECT_CALL(*mMockSession, updateTargetWorkDuration(_)).Times(Exactly(1));
+ result = APerformanceHint_reportActualWorkDuration(session.get(), actualDurationNanos);
EXPECT_EQ(0, result);
- result = APerformanceHint_updateTargetWorkDuration(session, -1L);
+ result = APerformanceHint_reportActualWorkDuration(session.get(), -1L);
EXPECT_EQ(EINVAL, result);
- result = APerformanceHint_reportActualWorkDuration(session, -1L);
+ result = APerformanceHint_updateTargetWorkDuration(session.get(), 0);
+ EXPECT_EQ(0, result);
+ result = APerformanceHint_updateTargetWorkDuration(session.get(), -2);
+ EXPECT_EQ(EINVAL, result);
+ result = APerformanceHint_reportActualWorkDuration(session.get(), 12L);
EXPECT_EQ(EINVAL, result);
SessionHint hintId = SessionHint::CPU_LOAD_RESET;
EXPECT_CALL(*mMockSession, sendHint(Eq(hintId))).Times(Exactly(1));
- result = APerformanceHint_sendHint(session, hintId);
+ result = APerformanceHint_sendHint(session.get(), hintId);
EXPECT_EQ(0, result);
EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_UP))).Times(Exactly(1));
- result = APerformanceHint_notifyWorkloadIncrease(session, true, false, "Test hint");
+ result = APerformanceHint_notifyWorkloadIncrease(session.get(), true, false, "Test hint");
EXPECT_EQ(0, result);
EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_RESET))).Times(Exactly(1));
EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_RESET))).Times(Exactly(1));
- result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint");
+ result = APerformanceHint_notifyWorkloadReset(session.get(), true, true, "Test hint");
EXPECT_EQ(0, result);
EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::CPU_LOAD_SPIKE))).Times(Exactly(1));
EXPECT_CALL(*mMockSession, sendHint(Eq(SessionHint::GPU_LOAD_SPIKE))).Times(Exactly(1));
- result = APerformanceHint_notifyWorkloadSpike(session, true, true, "Test hint");
+ result = APerformanceHint_notifyWorkloadSpike(session.get(), true, true, "Test hint");
EXPECT_EQ(0, result);
- result = APerformanceHint_sendHint(session, static_cast<SessionHint>(-1));
- EXPECT_EQ(EINVAL, result);
+ EXPECT_DEATH(
+ { APerformanceHint_sendHint(session.get(), static_cast<SessionHint>(-1)); },
+ "invalid session hint");
Mock::VerifyAndClearExpectations(mMockSession.get());
for (int i = 0; i < mMaxLoadHintsPerInterval; ++i) {
- APerformanceHint_sendHint(session, hintId);
+ APerformanceHint_sendHint(session.get(), hintId);
}
// Expect to get rate limited if we try to send faster than the limiter allows
EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0));
- result = APerformanceHint_notifyWorkloadIncrease(session, true, true, "Test hint");
+ result = APerformanceHint_notifyWorkloadIncrease(session.get(), true, true, "Test hint");
EXPECT_EQ(result, EBUSY);
EXPECT_CALL(*mMockSession, sendHint(_)).Times(Exactly(0));
- result = APerformanceHint_notifyWorkloadReset(session, true, true, "Test hint");
+ result = APerformanceHint_notifyWorkloadReset(session.get(), true, true, "Test hint");
EXPECT_CALL(*mMockSession, close()).Times(Exactly(1));
- APerformanceHint_closeSession(session);
}
TEST_F(PerformanceHintTest, TestUpdatedSessionCreation) {
EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _)).Times(1);
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
ASSERT_TRUE(session);
- APerformanceHint_closeSession(session);
}
TEST_F(PerformanceHintTest, TestSessionCreationUsingConfig) {
EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, _, _, _, _)).Times(1);
- SessionCreationConfig config{.tids = std::vector<int32_t>(1, 2),
- .targetWorkDurationNanos = 5678,
- .modesToEnable = std::vector<hal::SessionMode>(0)};
+ auto&& config = configFromCreator({.tids = mTids});
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSessionUsingConfig(manager, config);
+ auto&& session = createSessionUsingConfig(manager, config);
ASSERT_TRUE(session);
- APerformanceHint_closeSession(session);
}
TEST_F(PerformanceHintTest, TestHwuiSessionCreation) {
EXPECT_CALL(*mMockIHintManager, createHintSessionWithConfig(_, hal::SessionTag::HWUI, _, _, _))
.Times(1);
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager, 56789L, true);
+ auto&& session = createSession(manager, 56789L, true);
ASSERT_TRUE(session);
- APerformanceHint_closeSession(session);
}
TEST_F(PerformanceHintTest, SetThreads) {
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
ASSERT_TRUE(session);
int32_t emptyTids[2];
- int result = APerformanceHint_setThreads(session, emptyTids, 0);
+ int result = APerformanceHint_setThreads(session.get(), emptyTids, 0);
EXPECT_EQ(EINVAL, result);
std::vector<int32_t> newTids;
newTids.push_back(1);
newTids.push_back(3);
EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(newTids))).Times(Exactly(1));
- result = APerformanceHint_setThreads(session, newTids.data(), newTids.size());
+ result = APerformanceHint_setThreads(session.get(), newTids.data(), newTids.size());
EXPECT_EQ(0, result);
testing::Mock::VerifyAndClearExpectations(mMockIHintManager.get());
@@ -383,27 +453,27 @@ TEST_F(PerformanceHintTest, SetThreads) {
EXPECT_CALL(*mMockIHintManager, setHintSessionThreads(_, Eq(invalidTids)))
.Times(Exactly(1))
.WillOnce(Return(ByMove(ScopedAStatus::fromExceptionCode(EX_SECURITY))));
- result = APerformanceHint_setThreads(session, invalidTids.data(), invalidTids.size());
+ result = APerformanceHint_setThreads(session.get(), invalidTids.data(), invalidTids.size());
EXPECT_EQ(EPERM, result);
}
TEST_F(PerformanceHintTest, SetPowerEfficient) {
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
ASSERT_TRUE(session);
EXPECT_CALL(*mMockSession, setMode(_, Eq(true))).Times(Exactly(1));
- int result = APerformanceHint_setPreferPowerEfficiency(session, true);
+ int result = APerformanceHint_setPreferPowerEfficiency(session.get(), true);
EXPECT_EQ(0, result);
EXPECT_CALL(*mMockSession, setMode(_, Eq(false))).Times(Exactly(1));
- result = APerformanceHint_setPreferPowerEfficiency(session, false);
+ result = APerformanceHint_setPreferPowerEfficiency(session.get(), false);
EXPECT_EQ(0, result);
}
TEST_F(PerformanceHintTest, CreateZeroTargetDurationSession) {
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager, 0);
+ auto&& session = createSession(manager, 0);
ASSERT_TRUE(session);
}
@@ -428,12 +498,12 @@ MATCHER_P(WorkDurationEq, expected, "") {
TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) {
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
ASSERT_TRUE(session);
int64_t targetDurationNanos = 10;
EXPECT_CALL(*mMockSession, updateTargetWorkDuration(Eq(targetDurationNanos))).Times(Exactly(1));
- int result = APerformanceHint_updateTargetWorkDuration(session, targetDurationNanos);
+ int result = APerformanceHint_updateTargetWorkDuration(session.get(), targetDurationNanos);
EXPECT_EQ(0, result);
usleep(2); // Sleep for longer than preferredUpdateRateNanos.
@@ -452,54 +522,53 @@ TEST_F(PerformanceHintTest, TestAPerformanceHint_reportActualWorkDuration2) {
EXPECT_CALL(*mMockSession, reportActualWorkDuration2(WorkDurationEq(actualWorkDurations)))
.Times(Exactly(pair.expectedResult == OK));
- result = APerformanceHint_reportActualWorkDuration2(session,
+ result = APerformanceHint_reportActualWorkDuration2(session.get(),
reinterpret_cast<AWorkDuration*>(
&pair.duration));
EXPECT_EQ(pair.expectedResult, result);
}
EXPECT_CALL(*mMockSession, close()).Times(Exactly(1));
- APerformanceHint_closeSession(session);
}
TEST_F(PerformanceHintTest, TestAWorkDuration) {
- AWorkDuration* aWorkDuration = AWorkDuration_create();
+ // AWorkDuration* aWorkDuration = AWorkDuration_create();
+ auto&& aWorkDuration = wrapWorkDuration(AWorkDuration_create());
ASSERT_NE(aWorkDuration, nullptr);
- AWorkDuration_setWorkPeriodStartTimestampNanos(aWorkDuration, 1);
- AWorkDuration_setActualTotalDurationNanos(aWorkDuration, 20);
- AWorkDuration_setActualCpuDurationNanos(aWorkDuration, 13);
- AWorkDuration_setActualGpuDurationNanos(aWorkDuration, 8);
- AWorkDuration_release(aWorkDuration);
+ AWorkDuration_setWorkPeriodStartTimestampNanos(aWorkDuration.get(), 1);
+ AWorkDuration_setActualTotalDurationNanos(aWorkDuration.get(), 20);
+ AWorkDuration_setActualCpuDurationNanos(aWorkDuration.get(), 13);
+ AWorkDuration_setActualGpuDurationNanos(aWorkDuration.get(), 8);
}
TEST_F(PerformanceHintTest, TestCreateUsingFMQ) {
setFMQEnabled(true);
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
ASSERT_TRUE(session);
}
TEST_F(PerformanceHintTest, TestUpdateTargetWorkDurationUsingFMQ) {
setFMQEnabled(true);
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
- APerformanceHint_updateTargetWorkDuration(session, 456);
+ auto&& session = createSession(manager);
+ APerformanceHint_updateTargetWorkDuration(session.get(), 456);
expectToReadFromFmq<HalChannelMessageContents::Tag::targetDuration>(456);
}
TEST_F(PerformanceHintTest, TestSendHintUsingFMQ) {
setFMQEnabled(true);
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
- APerformanceHint_sendHint(session, SessionHint::CPU_LOAD_UP);
+ auto&& session = createSession(manager);
+ APerformanceHint_sendHint(session.get(), SessionHint::CPU_LOAD_UP);
expectToReadFromFmq<HalChannelMessageContents::Tag::hint>(hal::SessionHint::CPU_LOAD_UP);
}
TEST_F(PerformanceHintTest, TestReportActualUsingFMQ) {
setFMQEnabled(true);
APerformanceHintManager* manager = createManager();
- APerformanceHintSession* session = createSession(manager);
+ auto&& session = createSession(manager);
hal::WorkDuration duration{.timeStampNanos = 3,
.durationNanos = 999999,
.workPeriodStartTimestampNanos = 1,
@@ -513,20 +582,91 @@ TEST_F(PerformanceHintTest, TestReportActualUsingFMQ) {
.gpuDurationNanos = duration.gpuDurationNanos,
};
- APerformanceHint_reportActualWorkDuration2(session,
+ APerformanceHint_reportActualWorkDuration2(session.get(),
reinterpret_cast<AWorkDuration*>(&duration));
expectToReadFromFmq<HalChannelMessageContents::Tag::workDuration>(durationExpected);
}
TEST_F(PerformanceHintTest, TestASessionCreationConfig) {
- ASessionCreationConfig* config = ASessionCreationConfig_create();
+ auto&& config = configFromCreator({
+ .tids = mTids,
+ .targetDuration = 20,
+ .powerEfficient = true,
+ .graphicsPipeline = true,
+ });
+
+ APerformanceHintManager* manager = createManager();
+ auto&& session = createSessionUsingConfig(manager, config);
+
+ ASSERT_NE(session, nullptr);
ASSERT_NE(config, nullptr);
+}
+
+TEST_F(PerformanceHintTest, TestSupportObject) {
+ // Disable GPU and Power Efficiency support to test partial enabling
+ mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU);
+ mClientData.supportInfo.sessionHints &= ~(1 << (int)hal::SessionHint::GPU_LOAD_UP);
+ mClientData.supportInfo.sessionHints &= ~(1 << (int)hal::SessionHint::POWER_EFFICIENCY);
+
+ APerformanceHintManager* manager = createManager();
+
+ union {
+ int expectedSupportInt;
+ SupportHelper expectedSupport;
+ };
+
+ union {
+ int actualSupportInt;
+ SupportHelper actualSupport;
+ };
+
+ expectedSupport = getFullySupportedSupportHelper();
+ actualSupport = getSupportHelper();
+
+ expectedSupport.autoGpu = false;
+
+ EXPECT_EQ(expectedSupportInt, actualSupportInt);
+}
+
+TEST_F(PerformanceHintTest, TestCreatingAutoSession) {
+ // Disable GPU capability for testing
+ mClientData.supportInfo.sessionModes &= ~(1 << (int)hal::SessionMode::AUTO_GPU);
+ APerformanceHintManager* manager = createManager();
- const int32_t testTids[2] = {1, 2};
- const size_t size = 2;
- EXPECT_EQ(ASessionCreationConfig_setTids(config, testTids, size), 0);
- EXPECT_EQ(ASessionCreationConfig_setTargetWorkDurationNanos(config, 20), 0);
- EXPECT_EQ(ASessionCreationConfig_setPreferPowerEfficiency(config, true), 0);
- EXPECT_EQ(ASessionCreationConfig_setGraphicsPipeline(config, true), 0);
- ASessionCreationConfig_release(config);
+ auto&& invalidConfig = configFromCreator({
+ .tids = mTids,
+ .targetDuration = 20,
+ .graphicsPipeline = false,
+ .autoCpu = true,
+ .autoGpu = true,
+ });
+
+ EXPECT_DEATH({ createSessionUsingConfig(manager, invalidConfig); }, "");
+
+ auto&& unsupportedConfig = configFromCreator({
+ .tids = mTids,
+ .targetDuration = 20,
+ .graphicsPipeline = true,
+ .autoCpu = true,
+ .autoGpu = true,
+ });
+
+ APerformanceHintSession* unsupportedSession = nullptr;
+
+ // Creating a session with auto timing but no graphics pipeline should fail
+ int out = APerformanceHint_createSessionUsingConfig(manager, unsupportedConfig.get(),
+ &unsupportedSession);
+ EXPECT_EQ(out, ENOTSUP);
+ EXPECT_EQ(wrapSession(unsupportedSession), nullptr);
+
+ auto&& validConfig = configFromCreator({
+ .tids = mTids,
+ .targetDuration = 20,
+ .graphicsPipeline = true,
+ .autoCpu = true,
+ .autoGpu = false,
+ });
+
+ auto&& validSession = createSessionUsingConfig(manager, validConfig);
+ EXPECT_NE(validSession, nullptr);
}
diff --git a/nfc/Android.bp b/nfc/Android.bp
deleted file mode 100644
index 0fdb3bd38db8..000000000000
--- a/nfc/Android.bp
+++ /dev/null
@@ -1,79 +0,0 @@
-package {
- default_team: "trendy_team_fwk_nfc",
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-filegroup {
- name: "framework-nfc-updatable-sources",
- path: "java",
- srcs: [
- "java/**/*.java",
- "java/**/*.aidl",
- ],
- visibility: [
- "//frameworks/base:__subpackages__",
- "//packages/apps/Nfc:__subpackages__",
- "//packages/modules/Nfc:__subpackages__",
- ],
-}
-
-java_sdk_library {
- name: "framework-nfc",
- libs: [
- "androidx.annotation_annotation",
- "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
- "framework-permission-s.stubs.module_lib",
- "framework-permission.stubs.module_lib",
- ],
- stub_only_libs: [
- // Needed for javadoc references.
- "framework-permission-s.stubs.module_lib",
- ],
- static_libs: [
- "android.nfc.flags-aconfig-java",
- "android.permission.flags-aconfig-java",
- ],
- srcs: [
- ":framework-nfc-updatable-sources",
- ":framework-nfc-javastream-protos",
- ],
- defaults: ["framework-module-defaults"],
- sdk_version: "module_current",
- min_sdk_version: "35", // Make it 36 once available.
- installable: true,
- optimize: {
- enabled: false,
- },
- hostdex: true, // for hiddenapi check
- permitted_packages: [
- "android.nfc",
- "com.android.nfc",
- ],
- impl_library_visibility: [
- "//frameworks/base:__subpackages__",
- "//cts:__subpackages__",
- "//packages/apps/Nfc:__subpackages__",
- "//packages/modules/Nfc:__subpackages__",
- ],
- jarjar_rules: ":nfc-jarjar-rules",
- lint: {
- baseline_filename: "lint-baseline.xml",
- },
- apex_available: [
- "//apex_available:platform",
- "com.android.nfcservices",
- ],
- aconfig_declarations: [
- "android.nfc.flags-aconfig",
- ],
-}
-
-filegroup {
- name: "nfc-jarjar-rules",
- srcs: ["jarjar-rules.txt"],
-}
diff --git a/nfc/OWNERS b/nfc/OWNERS
deleted file mode 100644
index f46dccd97974..000000000000
--- a/nfc/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 48448
-include platform/packages/apps/Nfc:/OWNERS \ No newline at end of file
diff --git a/nfc/TEST_MAPPING b/nfc/TEST_MAPPING
deleted file mode 100644
index 49c778d22038..000000000000
--- a/nfc/TEST_MAPPING
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "presubmit": [
- {
- "name": "NfcManagerTests"
- },
- {
- "name": "CtsNfcTestCases"
- },
- {
- "name": "CtsNdefTestCases"
- }
- ]
-}
diff --git a/nfc/api/current.txt b/nfc/api/current.txt
deleted file mode 100644
index c8c479a4d2ad..000000000000
--- a/nfc/api/current.txt
+++ /dev/null
@@ -1,495 +0,0 @@
-// 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_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean disable();
- method public void disableForegroundDispatch(android.app.Activity);
- method public void disableReaderMode(android.app.Activity);
- method @FlaggedApi("android.nfc.nfc_state_change") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean enable();
- 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.WlcListenerDeviceInfo getWlcListenerDeviceInfo();
- 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 isObserveModeEnabled();
- 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.nfc_check_tag_intent_preference") public boolean isTagIntentAllowed();
- method @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public boolean isTagIntentAppPreferenceSupported();
- 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);
- method @FlaggedApi("android.nfc.nfc_observe_mode") public boolean setObserveModeEnabled(boolean);
- field public static final String ACTION_ADAPTER_STATE_CHANGED = "android.nfc.action.ADAPTER_STATE_CHANGED";
- field @FlaggedApi("android.nfc.nfc_check_tag_intent_preference") public static final String ACTION_CHANGE_TAG_INTENT_PREFERENCE = "android.nfc.action.CHANGE_TAG_INTENT_PREFERENCE";
- 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 = -2147483648; // 0x80000000
- 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 = -2147483648; // 0x80000000
- 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 WlcListenerDeviceInfo implements android.os.Parcelable {
- ctor public WlcListenerDeviceInfo(int, double, double, int);
- method public int describeContents();
- method @FloatRange(from=0.0, to=100.0) public double getBatteryLevel();
- method public int getProductId();
- method public int getState();
- method public double getTemperature();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.WlcListenerDeviceInfo> CREATOR;
- field public static final int STATE_CONNECTED_CHARGING = 2; // 0x2
- field public static final int STATE_CONNECTED_DISCHARGING = 3; // 0x3
- field public static final int STATE_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 @FlaggedApi("android.nfc.enable_card_emulation_euicc") public int getDefaultNfcSubscriptionId();
- 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 @FlaggedApi("android.nfc.enable_card_emulation_euicc") public boolean isEuiccSupported();
- method public boolean registerAidsForService(android.content.ComponentName, String, java.util.List<java.lang.String>);
- method @FlaggedApi("android.nfc.nfc_event_listener") public void registerNfcEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.cardemulation.CardEmulation.NfcEventCallback);
- method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
- method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean registerPollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull String, boolean);
- method public boolean removeAidsForService(android.content.ComponentName, String);
- method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopFilterForService(@NonNull android.content.ComponentName, @NonNull String);
- method @FlaggedApi("android.nfc.nfc_read_polling_loop") public boolean removePollingLoopPatternFilterForService(@NonNull android.content.ComponentName, @NonNull 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 setShouldDefaultToObserveModeForService(@NonNull android.content.ComponentName, boolean);
- method public boolean supportsAidPrefixRegistration();
- method @FlaggedApi("android.nfc.nfc_event_listener") public void unregisterNfcEventCallback(@NonNull android.nfc.cardemulation.CardEmulation.NfcEventCallback);
- 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 @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_COMMAND_TIMEOUT = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_event_listener") public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_associated_role_services") public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY = "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
- field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_override_recover_routing_table") public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1; // 0xffffffff
- 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
- }
-
- @FlaggedApi("android.nfc.nfc_event_listener") public static interface CardEmulation.NfcEventCallback {
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onAidConflictOccurred(@NonNull String);
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onAidNotRouted(@NonNull String);
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onInternalErrorReported(int);
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onNfcStateChanged(int);
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onObserveModeStateChanged(boolean);
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onPreferredServiceChanged(boolean);
- method @FlaggedApi("android.nfc.nfc_event_listener") public default void onRemoteFieldChanged(boolean);
- }
-
- 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.nfc.cardemulation.PollingFrame>);
- 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 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";
- }
-
- @FlaggedApi("android.nfc.nfc_read_polling_loop") public final class PollingFrame implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public byte[] getData();
- method public long getTimestamp();
- method public boolean getTriggeredAutoTransact();
- method public int getType();
- method public int getVendorSpecificGain();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.cardemulation.PollingFrame> CREATOR;
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_A = 65; // 0x41
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_B = 66; // 0x42
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_F = 70; // 0x46
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_OFF = 88; // 0x58
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_ON = 79; // 0x4f
- field @FlaggedApi("android.nfc.nfc_read_polling_loop") public static final int POLLING_LOOP_TYPE_UNKNOWN = 85; // 0x55
- }
-
-}
-
-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
deleted file mode 100644
index ef9aab6e7641..000000000000
--- a/nfc/api/lint-baseline.txt
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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
deleted file mode 100644
index 5ebe91111ec0..000000000000
--- a/nfc/api/module-lib-current.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-// 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
deleted file mode 100644
index f7f8ee3ddda5..000000000000
--- a/nfc/api/module-lib-lint-baseline.txt
+++ /dev/null
@@ -1,93 +0,0 @@
-// 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/module-lib-removed.txt b/nfc/api/module-lib-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/nfc/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/nfc/api/removed.txt b/nfc/api/removed.txt
deleted file mode 100644
index fb82b5ddbb21..000000000000
--- a/nfc/api/removed.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-// 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
deleted file mode 100644
index 6e69da1c6daa..000000000000
--- a/nfc/api/system-current.txt
+++ /dev/null
@@ -1,256 +0,0 @@
-// 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(boolean);
- 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_mainline") public int getAdapterState();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.NfcOemExtension getNfcOemExtension();
- 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.NFC_SET_CONTROLLER_ALWAYS_ON) public void registerControllerAlwaysOnListener(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
- method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerNfcVendorNciCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
- 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 @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int sendVendorNciMessage(int, @IntRange(from=0, to=15) int, @IntRange(from=0) int, @NonNull byte[]);
- 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 setReaderModePollingEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setTagIntentAppPreferenceForUser(int, @NonNull String, boolean);
- method @FlaggedApi("android.nfc.enable_nfc_charging") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setWlcEnabled(boolean);
- method @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void unregisterControllerAlwaysOnListener(@NonNull android.nfc.NfcAdapter.ControllerAlwaysOnListener);
- method @FlaggedApi("android.nfc.nfc_vendor_cmd") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterNfcVendorNciCallback(@NonNull android.nfc.NfcAdapter.NfcVendorNciCallback);
- 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 @FlaggedApi("android.nfc.enable_nfc_mainline") @RequiresPermission(android.Manifest.permission.SHOW_CUSTOMIZED_RESOLVER) public static final String ACTION_SHOW_NFC_RESOLVER = "android.nfc.action.SHOW_NFC_RESOLVER";
- field @FlaggedApi("android.nfc.enable_nfc_mainline") public static final String EXTRA_RESOLVE_INFOS = "android.nfc.extra.RESOLVE_INFOS";
- field @FlaggedApi("android.nfc.nfc_set_default_disc_tech") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final int FLAG_SET_DEFAULT_TECH = 1073741824; // 0x40000000
- field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int MESSAGE_TYPE_COMMAND = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_vendor_cmd") public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0; // 0x0
- 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.nfc_vendor_cmd") public static interface NfcAdapter.NfcVendorNciCallback {
- method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciNotification(@IntRange(from=9, to=15) int, int, @NonNull byte[]);
- method @FlaggedApi("android.nfc.nfc_vendor_cmd") public void onVendorNciResponse(@IntRange(from=0, to=15) int, int, @NonNull byte[]);
- }
-
- @FlaggedApi("android.nfc.enable_nfc_charging") public static interface NfcAdapter.WlcStateListener {
- method public void onWlcStateChanged(@NonNull android.nfc.WlcListenerDeviceInfo);
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public final class NfcOemExtension {
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void clearPreference();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int forceRoutingTableCommit();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getActiveNfceeList();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public long getMaxPausePollingTimeoutMills();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public android.nfc.RoutingStatus getRoutingStatus();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public java.util.List<android.nfc.NfcRoutingTableEntry> getRoutingTable();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public android.nfc.T4tNdefNfcee getT4tNdefNfcee();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean hasUserEnabledNfc();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isAutoChangeEnabled();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isTagPresent();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void maybeTriggerFirmwareUpdate();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overwriteRoutingTable(int, int, int, int);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int pausePolling(long);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void registerCallback(@NonNull java.util.concurrent.Executor, @NonNull android.nfc.NfcOemExtension.Callback);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int resumePolling();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setAutoChangeEnabled(boolean);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON) public void setControllerAlwaysOnMode(int);
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void synchronizeScreenState();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void triggerInitialization();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void unregisterCallback(@NonNull android.nfc.NfcOemExtension.Callback);
- field public static final int COMMIT_ROUTING_STATUS_FAILED = 3; // 0x3
- field public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6; // 0x6
- field public static final int COMMIT_ROUTING_STATUS_OK = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int DISABLE = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_DEFAULT = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_EE = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int ENABLE_TRANSPARENT = 2; // 0x2
- field public static final int HCE_ACTIVATE = 1; // 0x1
- field public static final int HCE_DATA_TRANSFERRED = 2; // 0x2
- field public static final int HCE_DEACTIVATE = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_A = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_B = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_F = 4; // 0x4
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int NFCEE_TECH_NONE = 0; // 0x0
- field public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2; // 0x2
- field public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1; // 0x1
- field public static final int STATUS_OK = 0; // 0x0
- field public static final int STATUS_UNKNOWN_ERROR = 1; // 0x1
- }
-
- public static interface NfcOemExtension.Callback {
- method public void onApplyRouting(@NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onBootFinished(int);
- method public void onBootStarted();
- method public void onCardEmulationActivated(boolean);
- method public void onDisableFinished(int);
- method public void onDisableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onDisableStarted();
- method public void onEeListenActivated(boolean);
- method public void onEeUpdated();
- method public void onEnableFinished(int);
- method public void onEnableRequested(@NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onEnableStarted();
- method public void onExtractOemPackages(@NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.util.List<java.lang.String>>);
- method public void onGetOemAppSearchIntent(@NonNull java.util.List<java.lang.String>, @NonNull java.util.function.Consumer<android.content.Intent>);
- method public void onHceEventReceived(int);
- method public void onLaunchHceAppChooserActivity(@NonNull String, @NonNull java.util.List<android.nfc.cardemulation.ApduServiceInfo>, @NonNull android.content.ComponentName, @NonNull String);
- method public void onLaunchHceTapAgainDialog(@NonNull android.nfc.cardemulation.ApduServiceInfo, @NonNull String);
- method public void onLogEventNotified(@NonNull android.nfc.OemLogItems);
- method public void onNdefMessage(@NonNull android.nfc.Tag, @NonNull android.nfc.NdefMessage, @NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onNdefRead(@NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onReaderOptionChanged(boolean);
- method public void onRfDiscoveryStarted(boolean);
- method public void onRfFieldDetected(boolean);
- method public void onRoutingChanged(@NonNull java.util.function.Consumer<java.lang.Boolean>);
- method public void onRoutingTableFull();
- method public void onStateUpdated(int);
- method public void onTagConnected(boolean);
- method public void onTagDispatch(@NonNull java.util.function.Consumer<java.lang.Boolean>);
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public abstract class NfcRoutingTableEntry {
- method public int getNfceeId();
- method public int getRouteType();
- method public int getType();
- field public static final int TYPE_AID = 0; // 0x0
- field public static final int TYPE_PROTOCOL = 1; // 0x1
- field public static final int TYPE_SYSTEM_CODE = 3; // 0x3
- field public static final int TYPE_TECHNOLOGY = 2; // 0x2
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public final class OemLogItems implements android.os.Parcelable {
- method public int describeContents();
- method public int getAction();
- method public int getCallingPid();
- method @Nullable public byte[] getCommandApdu();
- method public int getEvent();
- method @Nullable public byte[] getResponseApdu();
- method @Nullable public java.time.Instant getRfFieldEventTimeMillis();
- method @Nullable public android.nfc.Tag getTag();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.OemLogItems> CREATOR;
- field public static final int EVENT_DISABLE = 2; // 0x2
- field public static final int EVENT_ENABLE = 1; // 0x1
- field public static final int EVENT_UNSET = 0; // 0x0
- field public static final int LOG_ACTION_HCE_DATA = 516; // 0x204
- field public static final int LOG_ACTION_NFC_TOGGLE = 513; // 0x201
- field public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 1; // 0x1
- field public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 518; // 0x206
- field public static final int LOG_ACTION_TAG_DETECTED = 3; // 0x3
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingStatus {
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultIsoDepRoute();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultOffHostRoute();
- method @FlaggedApi("android.nfc.nfc_oem_extension") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int getDefaultRoute();
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingTableAidEntry extends android.nfc.NfcRoutingTableEntry {
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public String getAid();
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingTableProtocolEntry extends android.nfc.NfcRoutingTableEntry {
- method @FlaggedApi("android.nfc.nfc_oem_extension") public int getProtocol();
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_ISO_DEP = 4; // 0x4
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_NDEF = 7; // 0x7
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_NFC_DEP = 5; // 0x5
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_T1T = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_T2T = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_T3T = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_T5T = 6; // 0x6
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_UNDETERMINED = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int PROTOCOL_UNSUPPORTED = -1; // 0xffffffff
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingTableSystemCodeEntry extends android.nfc.NfcRoutingTableEntry {
- method @FlaggedApi("android.nfc.nfc_oem_extension") @NonNull public byte[] getSystemCode();
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public class RoutingTableTechnologyEntry extends android.nfc.NfcRoutingTableEntry {
- method @FlaggedApi("android.nfc.nfc_oem_extension") public int getTechnology();
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_A = 0; // 0x0
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_B = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_F = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_UNSUPPORTED = -1; // 0xffffffff
- field @FlaggedApi("android.nfc.nfc_oem_extension") public static final int TECHNOLOGY_V = 3; // 0x3
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfcee {
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int clearData();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isOperationOngoing();
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean isSupported();
- method @Nullable @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public android.nfc.T4tNdefNfceeCcFileInfo readCcfile();
- method @NonNull @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public byte[] readData(@IntRange(from=0, to=65535) int);
- method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) @WorkerThread public int writeData(@IntRange(from=0, to=65535) int, @NonNull byte[]);
- field public static final int CLEAR_DATA_FAILED_DEVICE_BUSY = -1; // 0xffffffff
- field public static final int CLEAR_DATA_FAILED_INTERNAL = 0; // 0x0
- field public static final int CLEAR_DATA_SUCCESS = 1; // 0x1
- field public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6; // 0xfffffffa
- field public static final int WRITE_DATA_ERROR_DEVICE_BUSY = -9; // 0xfffffff7
- field public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7; // 0xfffffff9
- field public static final int WRITE_DATA_ERROR_INTERNAL = -1; // 0xffffffff
- field public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4; // 0xfffffffc
- field public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5; // 0xfffffffb
- field public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8; // 0xfffffff8
- field public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3; // 0xfffffffd
- field public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2; // 0xfffffffe
- field public static final int WRITE_DATA_SUCCESS = 0; // 0x0
- }
-
- @FlaggedApi("android.nfc.nfc_oem_extension") public final class T4tNdefNfceeCcFileInfo implements android.os.Parcelable {
- method public int describeContents();
- method @IntRange(from=15, to=32767) public int getCcFileLength();
- method @IntRange(from=0xffffffff, to=65535) public int getFileId();
- method @IntRange(from=5, to=32767) public int getMaxSize();
- method public int getVersion();
- method public boolean isReadAllowed();
- method public boolean isWriteAllowed();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.nfc.T4tNdefNfceeCcFileInfo> CREATOR;
- field public static final int VERSION_2_0 = 32; // 0x20
- field public static final int VERSION_3_0 = 48; // 0x30
- }
-
-}
-
-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 static android.content.ComponentName getPreferredPaymentService(@NonNull android.content.Context);
- method @FlaggedApi("android.nfc.enable_nfc_mainline") @NonNull public java.util.List<android.nfc.cardemulation.ApduServiceInfo> getServices(@NonNull String, int);
- method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void overrideRoutingTable(@NonNull android.app.Activity, int, int);
- method @FlaggedApi("android.nfc.nfc_override_recover_routing_table") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void recoverRoutingTable(@NonNull android.app.Activity);
- method @FlaggedApi("android.nfc.enable_card_emulation_euicc") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setDefaultNfcSubscriptionId(int);
- method @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public int setServiceEnabledForCategoryOther(@NonNull android.content.ComponentName, boolean);
- field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3; // 0x3
- field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1; // 0x1
- field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2; // 0x2
- field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4; // 0x4
- field @FlaggedApi("android.nfc.nfc_set_service_enabled_for_category_other") public static final int SET_SERVICE_ENABLED_STATUS_OK = 0; // 0x0
- field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2; // 0x2
- field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1; // 0x1
- field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3; // 0x3
- field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0; // 0x0
- field @FlaggedApi("android.nfc.enable_card_emulation_euicc") public static final int SET_SUBSCRIPTION_ID_STATUS_UNKNOWN = -1; // 0xffffffff
- }
-
-}
-
diff --git a/nfc/api/system-lint-baseline.txt b/nfc/api/system-lint-baseline.txt
deleted file mode 100644
index c7a618125add..000000000000
--- a/nfc/api/system-lint-baseline.txt
+++ /dev/null
@@ -1,119 +0,0 @@
-// 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
-
-
-CallbackMethodName: android.nfc.NfcOemExtension.Callback#shouldSkipRoutingChange():
- Callback method names must follow the on<Something> style: shouldSkipRoutingChange
-
-
-MethodNameTense: android.nfc.NfcOemExtension.Callback#onEnable():
- Unexpected tense; probably meant `enabled`, was `onEnable`
-
-
-MissingNullability: android.nfc.cardemulation.CardEmulation#overrideRoutingTable(android.app.Activity, String, String) parameter #1:
- Missing nullability on parameter `protocol` in method `overrideRoutingTable`
-MissingNullability: android.nfc.cardemulation.CardEmulation#overrideRoutingTable(android.app.Activity, String, String) parameter #2:
- Missing nullability on parameter `technology` in method `overrideRoutingTable`
-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
deleted file mode 100644
index c6eaa57b6b06..000000000000
--- a/nfc/api/system-removed.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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/api/test-current.txt b/nfc/api/test-current.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/nfc/api/test-current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/nfc/api/test-removed.txt b/nfc/api/test-removed.txt
deleted file mode 100644
index d802177e249b..000000000000
--- a/nfc/api/test-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/nfc/jarjar-rules.txt b/nfc/jarjar-rules.txt
deleted file mode 100644
index 63a6a58d8ce2..000000000000
--- a/nfc/jarjar-rules.txt
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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.content.UriRelativeFilter* 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.*Flags* 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/nfc/java/android/nfc/ApduList.aidl b/nfc/java/android/nfc/ApduList.aidl
deleted file mode 100644
index f6236b2bfb3b..000000000000
--- a/nfc/java/android/nfc/ApduList.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-parcelable ApduList; \ No newline at end of file
diff --git a/nfc/java/android/nfc/ApduList.java b/nfc/java/android/nfc/ApduList.java
deleted file mode 100644
index 027141d99c30..000000000000
--- a/nfc/java/android/nfc/ApduList.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package android.nfc;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @hide
- */
-public class ApduList implements Parcelable {
-
- private ArrayList<byte[]> commands = new ArrayList<byte[]>();
-
- public ApduList() {
- }
-
- public void add(byte[] command) {
- commands.add(command);
- }
-
- public List<byte[]> get() {
- return commands;
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<ApduList> CREATOR =
- new Parcelable.Creator<ApduList>() {
- @Override
- public ApduList createFromParcel(Parcel in) {
- return new ApduList(in);
- }
-
- @Override
- public ApduList[] newArray(int size) {
- return new ApduList[size];
- }
- };
-
- private ApduList(Parcel in) {
- int count = in.readInt();
-
- for (int i = 0 ; i < count ; i++) {
-
- int length = in.readInt();
- byte[] cmd = new byte[length];
- in.readByteArray(cmd);
- commands.add(cmd);
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(commands.size());
-
- for (byte[] cmd : commands) {
- dest.writeInt(cmd.length);
- dest.writeByteArray(cmd);
- }
- }
-}
-
-
diff --git a/nfc/java/android/nfc/AvailableNfcAntenna.aidl b/nfc/java/android/nfc/AvailableNfcAntenna.aidl
deleted file mode 100644
index 9d06e2d7d5eb..000000000000
--- a/nfc/java/android/nfc/AvailableNfcAntenna.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013 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.nfc;
-
-parcelable AvailableNfcAntenna;
diff --git a/nfc/java/android/nfc/AvailableNfcAntenna.java b/nfc/java/android/nfc/AvailableNfcAntenna.java
deleted file mode 100644
index e76aeb07f106..000000000000
--- a/nfc/java/android/nfc/AvailableNfcAntenna.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Represents a single available Nfc antenna
- * on an Android device.
- */
-public final class AvailableNfcAntenna implements Parcelable {
- /**
- * Location of the antenna on the Y axis in millimeters.
- * 0 is the top-left when the user is facing the screen
- * and the device orientation is Portrait.
- */
- private final int mLocationX;
- /**
- * Location of the antenna on the Y axis in millimeters.
- * 0 is the top-left when the user is facing the screen
- * and the device orientation is Portrait.
- */
- private final int mLocationY;
-
- public AvailableNfcAntenna(int locationX, int locationY) {
- this.mLocationX = locationX;
- this.mLocationY = locationY;
- }
-
- /**
- * Location of the antenna on the X axis in millimeters.
- * 0 is the top-left when the user is facing the screen
- * and the device orientation is Portrait.
- */
- public int getLocationX() {
- return mLocationX;
- }
-
- /**
- * Location of the antenna on the Y axis in millimeters.
- * 0 is the top-left when the user is facing the screen
- * and the device orientation is Portrait.
- */
- public int getLocationY() {
- return mLocationY;
- }
-
- private AvailableNfcAntenna(Parcel in) {
- this.mLocationX = in.readInt();
- this.mLocationY = in.readInt();
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<AvailableNfcAntenna>
- CREATOR = new Parcelable.Creator<AvailableNfcAntenna>() {
- @Override
- public AvailableNfcAntenna createFromParcel(Parcel in) {
- return new AvailableNfcAntenna(in);
- }
-
- @Override
- public AvailableNfcAntenna[] newArray(int size) {
- return new AvailableNfcAntenna[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mLocationX);
- dest.writeInt(mLocationY);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + mLocationX;
- result = prime * result + mLocationY;
- return result;
- }
-
- /**
- * Returns true if the specified AvailableNfcAntenna contains
- * identical specifications.
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- AvailableNfcAntenna other = (AvailableNfcAntenna) obj;
- if (this.mLocationX != other.mLocationX) return false;
- return this.mLocationY == other.mLocationY;
- }
-
- @Override
- public String toString() {
- return "AvailableNfcAntenna " + "x: " + mLocationX + " y: " + mLocationY;
- }
-}
diff --git a/nfc/java/android/nfc/ComponentNameAndUser.aidl b/nfc/java/android/nfc/ComponentNameAndUser.aidl
deleted file mode 100644
index e677998a7970..000000000000
--- a/nfc/java/android/nfc/ComponentNameAndUser.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-parcelable ComponentNameAndUser; \ No newline at end of file
diff --git a/nfc/java/android/nfc/ComponentNameAndUser.java b/nfc/java/android/nfc/ComponentNameAndUser.java
deleted file mode 100644
index 59e6c62926c9..000000000000
--- a/nfc/java/android/nfc/ComponentNameAndUser.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.UserIdInt;
-import android.content.ComponentName;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Objects;
-
-/**
- * @hide
- */
-public class ComponentNameAndUser implements Parcelable {
- @UserIdInt private final int mUserId;
- private ComponentName mComponentName;
-
- public ComponentNameAndUser(@UserIdInt int userId, ComponentName componentName) {
- mUserId = userId;
- mComponentName = componentName;
- }
-
- /**
- * @hide
- */
- public int describeContents() {
- return 0;
- }
-
- /**
- * @hide
- */
- public void writeToParcel(Parcel out, int flags) {
- out.writeInt(mUserId);
- out.writeParcelable(mComponentName, flags);
- }
-
- public static final Parcelable.Creator<ComponentNameAndUser> CREATOR =
- new Parcelable.Creator<ComponentNameAndUser>() {
- public ComponentNameAndUser createFromParcel(Parcel in) {
- return new ComponentNameAndUser(in);
- }
-
- public ComponentNameAndUser[] newArray(int size) {
- return new ComponentNameAndUser[size];
- }
- };
-
- private ComponentNameAndUser(Parcel in) {
- mUserId = in.readInt();
- mComponentName = in.readParcelable(null, ComponentName.class);
- }
-
- @UserIdInt
- public int getUserId() {
- return mUserId;
- }
-
- public ComponentName getComponentName() {
- return mComponentName;
- }
-
- @Override
- public String toString() {
- return mComponentName + " for user id: " + mUserId;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (obj != null && obj instanceof ComponentNameAndUser) {
- ComponentNameAndUser other = (ComponentNameAndUser) obj;
- return other.getUserId() == mUserId
- && Objects.equals(other.getComponentName(), mComponentName);
- }
- return false;
- }
-
- @Override
- public int hashCode() {
- if (mComponentName == null) {
- return mUserId;
- }
- return mComponentName.hashCode() + mUserId;
- }
-}
diff --git a/nfc/java/android/nfc/Constants.java b/nfc/java/android/nfc/Constants.java
deleted file mode 100644
index 9b11e2d30ed8..000000000000
--- a/nfc/java/android/nfc/Constants.java
+++ /dev/null
@@ -1,42 +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.nfc;
-
-import android.provider.Settings;
-
-/**
- * @hide
- * TODO(b/303286040): Holds @hide API constants. Formalize these APIs.
- */
-public final class Constants {
- private Constants() { }
-
- public static final String SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND = "nfc_payment_foreground";
- public static final String SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT = "nfc_payment_default_component";
- public static final String FEATURE_NFC_ANY = "android.hardware.nfc.any";
-
- /**
- * @hide constant copied from {@link Settings.Global}
- * TODO(b/274636414): Migrate to official API in Android V.
- */
- public static final String SETTINGS_SATELLITE_MODE_RADIOS = "satellite_mode_radios";
- /**
- * @hide constant copied from {@link Settings.Global}
- * TODO(b/274636414): Migrate to official API in Android V.
- */
- public static final String SETTINGS_SATELLITE_MODE_ENABLED = "satellite_mode_enabled";
-}
diff --git a/nfc/java/android/nfc/Entry.aidl b/nfc/java/android/nfc/Entry.aidl
deleted file mode 100644
index 148c4ec86845..000000000000
--- a/nfc/java/android/nfc/Entry.aidl
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-parcelable Entry; \ No newline at end of file
diff --git a/nfc/java/android/nfc/Entry.java b/nfc/java/android/nfc/Entry.java
deleted file mode 100644
index aa5ba58e7179..000000000000
--- a/nfc/java/android/nfc/Entry.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-
-/** @hide */
-public final class Entry implements Parcelable {
- private final byte mType;
- private final byte mNfceeId;
- private final String mEntry;
- private final String mRoutingType;
-
- public Entry(String entry, byte type, byte nfceeId, String routingType) {
- mEntry = entry;
- mType = type;
- mNfceeId = nfceeId;
- mRoutingType = routingType;
- }
-
- public byte getType() {
- return mType;
- }
-
- public byte getNfceeId() {
- return mNfceeId;
- }
-
- public String getEntry() {
- return mEntry;
- }
-
- public String getRoutingType() {
- return mRoutingType;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- private Entry(Parcel in) {
- this.mEntry = in.readString();
- this.mNfceeId = in.readByte();
- this.mType = in.readByte();
- this.mRoutingType = in.readString();
- }
-
- public static final @NonNull Parcelable.Creator<Entry> CREATOR =
- new Parcelable.Creator<Entry>() {
- @Override
- public Entry createFromParcel(Parcel in) {
- return new Entry(in);
- }
-
- @Override
- public Entry[] newArray(int size) {
- return new Entry[size];
- }
- };
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeString(mEntry);
- dest.writeByte(mNfceeId);
- dest.writeByte(mType);
- dest.writeString(mRoutingType);
- }
-}
diff --git a/nfc/java/android/nfc/ErrorCodes.java b/nfc/java/android/nfc/ErrorCodes.java
deleted file mode 100644
index d2c81cd27d90..000000000000
--- a/nfc/java/android/nfc/ErrorCodes.java
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (C) 2010, 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.nfc;
-
-import android.compat.annotation.UnsupportedAppUsage;
-
-/**
- * This class defines all the error codes that can be returned by the service
- * and producing an exception on the application level. These are needed since
- * binders does not support exceptions.
- *
- * @hide
- */
-public class ErrorCodes {
-
- @UnsupportedAppUsage
- public static boolean isError(int code) {
- if (code < 0) {
- return true;
- } else {
- return false;
- }
- }
-
- public static String asString(int code) {
- switch (code) {
- case SUCCESS: return "SUCCESS";
- case ERROR_IO: return "IO";
- case ERROR_CANCELLED: return "CANCELLED";
- case ERROR_TIMEOUT: return "TIMEOUT";
- case ERROR_BUSY: return "BUSY";
- case ERROR_CONNECT: return "CONNECT/DISCONNECT";
-// case ERROR_DISCONNECT: return "DISCONNECT";
- case ERROR_READ: return "READ";
- case ERROR_WRITE: return "WRITE";
- case ERROR_INVALID_PARAM: return "INVALID_PARAM";
- case ERROR_INSUFFICIENT_RESOURCES: return "INSUFFICIENT_RESOURCES";
- case ERROR_SOCKET_CREATION: return "SOCKET_CREATION";
- case ERROR_SOCKET_NOT_CONNECTED: return "SOCKET_NOT_CONNECTED";
- case ERROR_BUFFER_TO_SMALL: return "BUFFER_TO_SMALL";
- case ERROR_SAP_USED: return "SAP_USED";
- case ERROR_SERVICE_NAME_USED: return "SERVICE_NAME_USED";
- case ERROR_SOCKET_OPTIONS: return "SOCKET_OPTIONS";
- case ERROR_NFC_ON: return "NFC_ON";
- case ERROR_NOT_INITIALIZED: return "NOT_INITIALIZED";
- case ERROR_SE_ALREADY_SELECTED: return "SE_ALREADY_SELECTED";
- case ERROR_SE_CONNECTED: return "SE_CONNECTED";
- case ERROR_NO_SE_CONNECTED: return "NO_SE_CONNECTED";
- case ERROR_NOT_SUPPORTED: return "NOT_SUPPORTED";
- default: return "UNKNOWN ERROR";
- }
- }
-
- public static final int SUCCESS = 0;
-
- public static final int ERROR_IO = -1;
-
- public static final int ERROR_CANCELLED = -2;
-
- public static final int ERROR_TIMEOUT = -3;
-
- public static final int ERROR_BUSY = -4;
-
- public static final int ERROR_CONNECT = -5;
-
- public static final int ERROR_DISCONNECT = -5;
-
- public static final int ERROR_READ = -6;
-
- public static final int ERROR_WRITE = -7;
-
- public static final int ERROR_INVALID_PARAM = -8;
-
- public static final int ERROR_INSUFFICIENT_RESOURCES = -9;
-
- public static final int ERROR_SOCKET_CREATION = -10;
-
- public static final int ERROR_SOCKET_NOT_CONNECTED = -11;
-
- public static final int ERROR_BUFFER_TO_SMALL = -12;
-
- public static final int ERROR_SAP_USED = -13;
-
- public static final int ERROR_SERVICE_NAME_USED = -14;
-
- public static final int ERROR_SOCKET_OPTIONS = -15;
-
- public static final int ERROR_NFC_ON = -16;
-
- public static final int ERROR_NOT_INITIALIZED = -17;
-
- public static final int ERROR_SE_ALREADY_SELECTED = -18;
-
- public static final int ERROR_SE_CONNECTED = -19;
-
- public static final int ERROR_NO_SE_CONNECTED = -20;
-
- public static final int ERROR_NOT_SUPPORTED = -21;
-
-}
diff --git a/nfc/java/android/nfc/FormatException.java b/nfc/java/android/nfc/FormatException.java
deleted file mode 100644
index a57de1e0e21a..000000000000
--- a/nfc/java/android/nfc/FormatException.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2010, 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.nfc;
-
-public class FormatException extends Exception {
- public FormatException() {
- super();
- }
-
- public FormatException(String message) {
- super(message);
- }
-
- public FormatException(String message, Throwable e) {
- super(message, e);
- }
-}
diff --git a/nfc/java/android/nfc/IAppCallback.aidl b/nfc/java/android/nfc/IAppCallback.aidl
deleted file mode 100644
index b06bf06d5197..000000000000
--- a/nfc/java/android/nfc/IAppCallback.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-import android.nfc.Tag;
-
-/**
- * @hide
- */
-interface IAppCallback
-{
- oneway void onTagDiscovered(in Tag tag);
-}
diff --git a/nfc/java/android/nfc/INfcAdapter.aidl b/nfc/java/android/nfc/INfcAdapter.aidl
deleted file mode 100644
index ac0a5aaaa195..000000000000
--- a/nfc/java/android/nfc/INfcAdapter.aidl
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.app.PendingIntent;
-import android.content.IntentFilter;
-import android.nfc.Entry;
-import android.nfc.NdefMessage;
-import android.nfc.Tag;
-import android.nfc.TechListParcel;
-import android.nfc.IAppCallback;
-import android.nfc.INfcAdapterExtras;
-import android.nfc.INfcControllerAlwaysOnListener;
-import android.nfc.INfcVendorNciCallback;
-import android.nfc.INfcTag;
-import android.nfc.INfcCardEmulation;
-import android.nfc.INfcFCardEmulation;
-import android.nfc.INfcOemExtensionCallback;
-import android.nfc.INfcUnlockHandler;
-import android.nfc.IT4tNdefNfcee;
-import android.nfc.ITagRemovedCallback;
-import android.nfc.INfcDta;
-import android.nfc.INfcWlcStateListener;
-import android.nfc.NfcAntennaInfo;
-import android.nfc.WlcListenerDeviceInfo;
-import android.nfc.cardemulation.PollingFrame;
-import android.os.Bundle;
-
-/**
- * @hide
- */
-interface INfcAdapter
-{
- INfcTag getNfcTagInterface();
- INfcCardEmulation getNfcCardEmulationInterface();
- INfcFCardEmulation getNfcFCardEmulationInterface();
- INfcAdapterExtras getNfcAdapterExtrasInterface(in String pkg);
- INfcDta getNfcDtaInterface(in String pkg);
- int getState();
- boolean disable(boolean saveState, in String pkg);
- boolean enable(in String pkg);
- int pausePolling(long timeoutInMs);
- int resumePolling();
-
- void setForegroundDispatch(in PendingIntent intent,
- in IntentFilter[] filters, in TechListParcel techLists);
- void setAppCallback(in IAppCallback callback);
-
- boolean ignore(int nativeHandle, int debounceMs, ITagRemovedCallback callback);
-
- void dispatch(in Tag tag);
-
- void setReaderMode (IBinder b, IAppCallback callback, int flags, in Bundle extras, String pkg);
-
- void addNfcUnlockHandler(INfcUnlockHandler unlockHandler, in int[] techList);
- void removeNfcUnlockHandler(INfcUnlockHandler unlockHandler);
-
- void verifyNfcPermission();
- boolean isNfcSecureEnabled();
- boolean deviceSupportsNfcSecure();
- boolean setNfcSecure(boolean enable);
- NfcAntennaInfo getNfcAntennaInfo();
-
- void setControllerAlwaysOn(int mode);
- boolean isControllerAlwaysOn();
- boolean isControllerAlwaysOnSupported();
- void registerControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
- void unregisterControllerAlwaysOnListener(in INfcControllerAlwaysOnListener listener);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
- boolean isTagIntentAppPreferenceSupported();
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
- Map getTagIntentAppPreferenceForUser(int userId);
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
- int setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow);
-
- boolean isReaderOptionEnabled();
- boolean isReaderOptionSupported();
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
- boolean enableReaderOption(boolean enable, in String pkg);
- boolean isObserveModeSupported();
- boolean isObserveModeEnabled();
- boolean setObserveMode(boolean enabled, String pkg);
-
- @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)")
- boolean setWlcEnabled(boolean enable);
- boolean isWlcEnabled();
- void registerWlcStateListener(in INfcWlcStateListener listener);
- void unregisterWlcStateListener(in INfcWlcStateListener listener);
- WlcListenerDeviceInfo getWlcListenerDeviceInfo();
-
- void updateDiscoveryTechnology(IBinder b, int pollFlags, int listenFlags, String pkg);
-
- void notifyPollingLoop(in PollingFrame frame);
- void notifyHceDeactivated();
- void notifyTestHceData(in int technology, in byte[] data);
- int sendVendorNciMessage(int mt, int gid, int oid, in byte[] payload);
- void registerVendorExtensionCallback(in INfcVendorNciCallback callbacks);
- void unregisterVendorExtensionCallback(in INfcVendorNciCallback callbacks);
- void registerOemExtensionCallback(INfcOemExtensionCallback callbacks);
- void unregisterOemExtensionCallback(INfcOemExtensionCallback callbacks);
- void clearPreference();
- void setScreenState();
- void checkFirmware();
- Map fetchActiveNfceeList();
- void triggerInitialization();
- boolean getSettingStatus();
- boolean isTagPresent();
- List<Entry> getRoutingTableEntryList();
- void indicateDataMigration(boolean inProgress, String pkg);
- int commitRouting();
- boolean isTagIntentAllowed(in String pkg, in int Userid);
- IT4tNdefNfcee getT4tNdefNfceeInterface();
- long getMaxPausePollingTimeoutMs();
-}
diff --git a/nfc/java/android/nfc/INfcAdapterExtras.aidl b/nfc/java/android/nfc/INfcAdapterExtras.aidl
deleted file mode 100644
index cde57c58ca1f..000000000000
--- a/nfc/java/android/nfc/INfcAdapterExtras.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-import android.os.Bundle;
-
-
-/**
- * {@hide}
- */
-interface INfcAdapterExtras {
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- Bundle open(in String pkg, IBinder b);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- Bundle close(in String pkg, IBinder b);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- Bundle transceive(in String pkg, in byte[] data_in);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- int getCardEmulationRoute(in String pkg);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- void setCardEmulationRoute(in String pkg, int route);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- void authenticate(in String pkg, in byte[] token);
- @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- String getDriverName(in String pkg);
-}
diff --git a/nfc/java/android/nfc/INfcCardEmulation.aidl b/nfc/java/android/nfc/INfcCardEmulation.aidl
deleted file mode 100644
index 00ceaa9801d8..000000000000
--- a/nfc/java/android/nfc/INfcCardEmulation.aidl
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2013 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.nfc;
-
-import android.content.ComponentName;
-import android.nfc.INfcEventCallback;
-
-import android.nfc.cardemulation.AidGroup;
-import android.nfc.cardemulation.ApduServiceInfo;
-import android.os.RemoteCallback;
-
-/**
- * @hide
- */
-interface INfcCardEmulation
-{
- boolean isDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
- boolean isDefaultServiceForAid(int userHandle, in ComponentName service, String aid);
- boolean setDefaultServiceForCategory(int userHandle, in ComponentName service, String category);
- boolean setDefaultForNextTap(int userHandle, in ComponentName service);
- boolean setShouldDefaultToObserveModeForService(int userId, in android.content.ComponentName service, boolean enable);
- boolean registerAidGroupForService(int userHandle, in ComponentName service, in AidGroup aidGroup);
- boolean registerPollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter, boolean autoTransact);
- boolean registerPollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter, boolean autoTransact);
- boolean setOffHostForService(int userHandle, in ComponentName service, in String offHostSecureElement);
- boolean unsetOffHostForService(int userHandle, in ComponentName service);
- AidGroup getAidGroupForService(int userHandle, in ComponentName service, String category);
- boolean removeAidGroupForService(int userHandle, in ComponentName service, String category);
- boolean removePollingLoopFilterForService(int userHandle, in ComponentName service, in String pollingLoopFilter);
- boolean removePollingLoopPatternFilterForService(int userHandle, in ComponentName service, in String pollingLoopPatternFilter);
- List<ApduServiceInfo> getServices(int userHandle, in String category);
- boolean setPreferredService(in ComponentName service);
- boolean unsetPreferredService();
- boolean supportsAidPrefixRegistration();
- ApduServiceInfo getPreferredPaymentService(int userHandle);
- int setServiceEnabledForCategoryOther(int userHandle, in ComponentName app, boolean status);
- boolean isDefaultPaymentRegistered();
-
- void overrideRoutingTable(int userHandle, String protocol, String technology, in String pkg);
- void recoverRoutingTable(int userHandle);
- boolean isEuiccSupported();
- int getDefaultNfcSubscriptionId(in String pkg);
- int setDefaultNfcSubscriptionId(int subscriptionId, in String pkg);
- void setAutoChangeStatus(boolean state);
- boolean isAutoChangeEnabled();
- List<String> getRoutingStatus();
- void overwriteRoutingTable(int userHandle, String emptyAid, String protocol, String tech, String sc);
-
- void registerNfcEventCallback(in INfcEventCallback listener);
- void unregisterNfcEventCallback(in INfcEventCallback listener);
-}
diff --git a/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl b/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl
deleted file mode 100644
index 1bb7680d2fed..000000000000
--- a/nfc/java/android/nfc/INfcControllerAlwaysOnListener.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc;
-
-/**
- * @hide
- */
-oneway interface INfcControllerAlwaysOnListener {
- /**
- * Called whenever the controller always on state changes
- *
- * @param isEnabled true if the state is enabled, false otherwise
- */
- void onControllerAlwaysOnChanged(boolean isEnabled);
-}
diff --git a/nfc/java/android/nfc/INfcDta.aidl b/nfc/java/android/nfc/INfcDta.aidl
deleted file mode 100644
index 4cc59271362b..000000000000
--- a/nfc/java/android/nfc/INfcDta.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
- /*
- * Copyright (C) 2017 NXP Semiconductors
- *
- * 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.nfc;
-
-import android.os.Bundle;
-
-/**
- * {@hide}
- */
-interface INfcDta {
-
- void enableDta();
- void disableDta();
- boolean enableServer(String serviceName, int serviceSap, int miu,
- int rwSize,int testCaseId);
- void disableServer();
- boolean enableClient(String serviceName, int miu, int rwSize,
- int testCaseId);
- void disableClient();
- boolean registerMessageService(String msgServiceName);
-}
diff --git a/nfc/java/android/nfc/INfcEventCallback.aidl b/nfc/java/android/nfc/INfcEventCallback.aidl
deleted file mode 100644
index af1fa2fb2456..000000000000
--- a/nfc/java/android/nfc/INfcEventCallback.aidl
+++ /dev/null
@@ -1,16 +0,0 @@
-package android.nfc;
-
-import android.nfc.ComponentNameAndUser;
-
-/**
- * @hide
- */
-oneway interface INfcEventCallback {
- void onPreferredServiceChanged(in ComponentNameAndUser ComponentNameAndUser);
- void onObserveModeStateChanged(boolean isEnabled);
- void onAidConflictOccurred(in String aid);
- void onAidNotRouted(in String aid);
- void onNfcStateChanged(in int nfcState);
- void onRemoteFieldChanged(boolean isDetected);
- void onInternalErrorReported(in int errorType);
-} \ No newline at end of file
diff --git a/nfc/java/android/nfc/INfcFCardEmulation.aidl b/nfc/java/android/nfc/INfcFCardEmulation.aidl
deleted file mode 100644
index 124bfac4f0d0..000000000000
--- a/nfc/java/android/nfc/INfcFCardEmulation.aidl
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc;
-
-import android.content.ComponentName;
-import android.nfc.cardemulation.NfcFServiceInfo;
-
-/**
- * @hide
- */
-interface INfcFCardEmulation
-{
- String getSystemCodeForService(int userHandle, in ComponentName service);
- boolean registerSystemCodeForService(int userHandle, in ComponentName service, String systemCode);
- boolean removeSystemCodeForService(int userHandle, in ComponentName service);
- String getNfcid2ForService(int userHandle, in ComponentName service);
- boolean setNfcid2ForService(int userHandle, in ComponentName service, String nfcid2);
- boolean enableNfcFForegroundService(in ComponentName service);
- boolean disableNfcFForegroundService();
- List<NfcFServiceInfo> getNfcFServices(int userHandle);
- int getMaxNumOfRegisterableSystemCodes();
-}
diff --git a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl b/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
deleted file mode 100644
index 357d3229306c..000000000000
--- a/nfc/java/android/nfc/INfcOemExtensionCallback.aidl
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.nfc;
-
-import android.content.ComponentName;
-import android.nfc.cardemulation.ApduServiceInfo;
-import android.nfc.NdefMessage;
-import android.nfc.OemLogItems;
-import android.nfc.Tag;
-import android.os.ResultReceiver;
-
-import java.util.List;
-
-/**
- * @hide
- */
-interface INfcOemExtensionCallback {
- void onTagConnected(boolean connected);
- void onStateUpdated(int state);
- void onApplyRouting(in ResultReceiver isSkipped);
- void onNdefRead(in ResultReceiver isSkipped);
- void onEnable(in ResultReceiver isAllowed);
- void onDisable(in ResultReceiver isAllowed);
- void onBootStarted();
- void onEnableStarted();
- void onDisableStarted();
- void onBootFinished(int status);
- void onEnableFinished(int status);
- void onDisableFinished(int status);
- void onTagDispatch(in ResultReceiver isSkipped);
- void onRoutingChanged(in ResultReceiver isSkipped);
- void onHceEventReceived(int action);
- void onReaderOptionChanged(boolean enabled);
- void onCardEmulationActivated(boolean isActivated);
- void onRfFieldDetected(boolean isActive);
- void onRfDiscoveryStarted(boolean isDiscoveryStarted);
- void onEeListenActivated(boolean isActivated);
- void onEeUpdated();
- void onGetOemAppSearchIntent(in List<String> firstPackage, in ResultReceiver intentConsumer);
- void onNdefMessage(in Tag tag, in NdefMessage message, in ResultReceiver hasOemExecutableContent);
- void onLaunchHceAppChooserActivity(in String selectedAid, in List<ApduServiceInfo> services, in ComponentName failedComponent, in String category);
- void onLaunchHceTapAgainActivity(in ApduServiceInfo service, in String category);
- void onRoutingTableFull();
- void onLogEventNotified(in OemLogItems item);
- void onExtractOemPackages(in NdefMessage message, in ResultReceiver packageReceiver);
-}
diff --git a/nfc/java/android/nfc/INfcTag.aidl b/nfc/java/android/nfc/INfcTag.aidl
deleted file mode 100644
index 170df71385bb..000000000000
--- a/nfc/java/android/nfc/INfcTag.aidl
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.nfc.NdefMessage;
-import android.nfc.Tag;
-import android.nfc.TransceiveResult;
-
-/**
- * @hide
- */
-interface INfcTag
-{
- int connect(int nativeHandle, int technology);
- int reconnect(int nativeHandle);
- int[] getTechList(int nativeHandle);
- boolean isNdef(int nativeHandle);
- boolean isPresent(int nativeHandle);
- TransceiveResult transceive(int nativeHandle, in byte[] data, boolean raw);
-
- NdefMessage ndefRead(int nativeHandle);
- int ndefWrite(int nativeHandle, in NdefMessage msg);
- int ndefMakeReadOnly(int nativeHandle);
- boolean ndefIsWritable(int nativeHandle);
- int formatNdef(int nativeHandle, in byte[] key);
- Tag rediscover(int nativehandle);
-
- int setTimeout(int technology, int timeout);
- int getTimeout(int technology);
- void resetTimeouts();
- boolean canMakeReadOnly(int ndefType);
- int getMaxTransceiveLength(int technology);
- boolean getExtendedLengthApdusSupported();
-
- boolean isTagUpToDate(long cookie);
-}
diff --git a/nfc/java/android/nfc/INfcUnlockHandler.aidl b/nfc/java/android/nfc/INfcUnlockHandler.aidl
deleted file mode 100644
index e1cace987dc3..000000000000
--- a/nfc/java/android/nfc/INfcUnlockHandler.aidl
+++ /dev/null
@@ -1,12 +0,0 @@
-package android.nfc;
-
-import android.nfc.Tag;
-
-/**
- * @hide
- */
-interface INfcUnlockHandler {
-
- boolean onUnlockAttempted(in Tag tag);
-
-}
diff --git a/nfc/java/android/nfc/INfcVendorNciCallback.aidl b/nfc/java/android/nfc/INfcVendorNciCallback.aidl
deleted file mode 100644
index 821dc6f6c868..000000000000
--- a/nfc/java/android/nfc/INfcVendorNciCallback.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-/**
- * @hide
- */
-oneway interface INfcVendorNciCallback {
- void onVendorResponseReceived(int gid, int oid, in byte[] payload);
- void onVendorNotificationReceived(int gid, int oid, in byte[] payload);
-}
diff --git a/nfc/java/android/nfc/INfcWlcStateListener.aidl b/nfc/java/android/nfc/INfcWlcStateListener.aidl
deleted file mode 100644
index 584eb9a128b4..000000000000
--- a/nfc/java/android/nfc/INfcWlcStateListener.aidl
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright 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.nfc;
-
-import android.nfc.WlcListenerDeviceInfo;
-/**
- * @hide
- */
-oneway interface INfcWlcStateListener {
- /**
- * Called whenever NFC WLC state changes
- *
- * @param wlcListenerDeviceInfo NFC wlc listener information
- */
- void onWlcStateChanged(in WlcListenerDeviceInfo wlcListenerDeviceInfo);
-}
diff --git a/nfc/java/android/nfc/IT4tNdefNfcee.aidl b/nfc/java/android/nfc/IT4tNdefNfcee.aidl
deleted file mode 100644
index b4cda5b022fb..000000000000
--- a/nfc/java/android/nfc/IT4tNdefNfcee.aidl
+++ /dev/null
@@ -1,33 +0,0 @@
-/******************************************************************************
- *
- * 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.
- * 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.nfc;
-
-import android.nfc.T4tNdefNfceeCcFileInfo;
-
-/**
- * @hide
- */
-interface IT4tNdefNfcee {
- int writeData(in int fileId, in byte[] data);
- byte[] readData(in int fileId);
- int clearNdefData();
- boolean isNdefOperationOngoing();
- boolean isNdefNfceeEmulationSupported();
- T4tNdefNfceeCcFileInfo readCcfile();
-}
diff --git a/nfc/java/android/nfc/ITagRemovedCallback.aidl b/nfc/java/android/nfc/ITagRemovedCallback.aidl
deleted file mode 100644
index 2a06ff314b22..000000000000
--- a/nfc/java/android/nfc/ITagRemovedCallback.aidl
+++ /dev/null
@@ -1,8 +0,0 @@
-package android.nfc;
-
-/**
- * @hide
- */
-oneway interface ITagRemovedCallback {
- void onTagRemoved();
-}
diff --git a/nfc/java/android/nfc/NdefMessage.aidl b/nfc/java/android/nfc/NdefMessage.aidl
deleted file mode 100644
index 378b9d05b385..000000000000
--- a/nfc/java/android/nfc/NdefMessage.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-parcelable NdefMessage;
diff --git a/nfc/java/android/nfc/NdefMessage.java b/nfc/java/android/nfc/NdefMessage.java
deleted file mode 100644
index 553f6c01b016..000000000000
--- a/nfc/java/android/nfc/NdefMessage.java
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.annotation.Nullable;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.proto.ProtoOutputStream;
-
-import java.nio.ByteBuffer;
-import java.util.Arrays;
-
-/**
- * Represents an immutable NDEF Message.
- * <p>
- * NDEF (NFC Data Exchange Format) is a light-weight binary format,
- * used to encapsulate typed data. It is specified by the NFC Forum,
- * for transmission and storage with NFC, however it is transport agnostic.
- * <p>
- * NDEF defines messages and records. An NDEF Record contains
- * typed data, such as MIME-type media, a URI, or a custom
- * application payload. An NDEF Message is a container for
- * one or more NDEF Records.
- * <p>
- * When an Android device receives an NDEF Message
- * (for example by reading an NFC tag) it processes it through
- * a dispatch mechanism to determine an activity to launch.
- * The type of the <em>first</em> record in the message has
- * special importance for message dispatch, so design this record
- * carefully.
- * <p>
- * Use {@link #NdefMessage(byte[])} to construct an NDEF Message from
- * binary data, or {@link #NdefMessage(NdefRecord[])} to
- * construct from one or more {@link NdefRecord}s.
- * <p class="note">
- * {@link NdefMessage} and {@link NdefRecord} implementations are
- * always available, even on Android devices that do not have NFC hardware.
- * <p class="note">
- * {@link NdefRecord}s are intended to be immutable (and thread-safe),
- * however they may contain mutable fields. So take care not to modify
- * mutable fields passed into constructors, or modify mutable fields
- * obtained by getter methods, unless such modification is explicitly
- * marked as safe.
- *
- * @see NfcAdapter#ACTION_NDEF_DISCOVERED
- * @see NdefRecord
- */
-public final class NdefMessage implements Parcelable {
- private final NdefRecord[] mRecords;
-
- /**
- * Construct an NDEF Message by parsing raw bytes.<p>
- * Strict validation of the NDEF binary structure is performed:
- * there must be at least one record, every record flag must
- * be correct, and the total length of the message must match
- * the length of the input data.<p>
- * This parser can handle chunked records, and converts them
- * into logical {@link NdefRecord}s within the message.<p>
- * Once the input data has been parsed to one or more logical
- * records, basic validation of the tnf, type, id, and payload fields
- * of each record is performed, as per the documentation on
- * on {@link NdefRecord#NdefRecord(short, byte[], byte[], byte[])}<p>
- * If either strict validation of the binary format fails, or
- * basic validation during record construction fails, a
- * {@link FormatException} is thrown<p>
- * Deep inspection of the type, id and payload fields of
- * each record is not performed, so it is possible to parse input
- * that has a valid binary format and confirms to the basic
- * validation requirements of
- * {@link NdefRecord#NdefRecord(short, byte[], byte[], byte[])},
- * but fails more strict requirements as specified by the
- * NFC Forum.
- *
- * <p class="note">
- * It is safe to re-use the data byte array after construction:
- * this constructor will make an internal copy of all necessary fields.
- *
- * @param data raw bytes to parse
- * @throws FormatException if the data cannot be parsed
- */
- public NdefMessage(byte[] data) throws FormatException {
- if (data == null) throw new NullPointerException("data is null");
- ByteBuffer buffer = ByteBuffer.wrap(data);
-
- mRecords = NdefRecord.parse(buffer, false);
-
- if (buffer.remaining() > 0) {
- throw new FormatException("trailing data");
- }
- }
-
- /**
- * Construct an NDEF Message from one or more NDEF Records.
- *
- * @param record first record (mandatory)
- * @param records additional records (optional)
- */
- public NdefMessage(NdefRecord record, NdefRecord ... records) {
- // validate
- if (record == null) throw new NullPointerException("record cannot be null");
-
- for (NdefRecord r : records) {
- if (r == null) {
- throw new NullPointerException("record cannot be null");
- }
- }
-
- mRecords = new NdefRecord[1 + records.length];
- mRecords[0] = record;
- System.arraycopy(records, 0, mRecords, 1, records.length);
- }
-
- /**
- * Construct an NDEF Message from one or more NDEF Records.
- *
- * @param records one or more records
- */
- public NdefMessage(NdefRecord[] records) {
- // validate
- if (records.length < 1) {
- throw new IllegalArgumentException("must have at least one record");
- }
- for (NdefRecord r : records) {
- if (r == null) {
- throw new NullPointerException("records cannot contain null");
- }
- }
-
- mRecords = records;
- }
-
- /**
- * Get the NDEF Records inside this NDEF Message.<p>
- * An {@link NdefMessage} always has one or more NDEF Records: so the
- * following code to retrieve the first record is always safe
- * (no need to check for null or array length >= 1):
- * <pre>
- * NdefRecord firstRecord = ndefMessage.getRecords()[0];
- * </pre>
- *
- * @return array of one or more NDEF records.
- */
- public NdefRecord[] getRecords() {
- return mRecords;
- }
-
- /**
- * Return the length of this NDEF Message if it is written to a byte array
- * with {@link #toByteArray}.<p>
- * An NDEF Message can be formatted to bytes in different ways
- * depending on chunking, SR, and ID flags, so the length returned
- * by this method may not be equal to the length of the original
- * byte array used to construct this NDEF Message. However it will
- * always be equal to the length of the byte array produced by
- * {@link #toByteArray}.
- *
- * @return length of this NDEF Message when written to bytes with {@link #toByteArray}
- * @see #toByteArray
- */
- public int getByteArrayLength() {
- int length = 0;
- for (NdefRecord r : mRecords) {
- length += r.getByteLength();
- }
- return length;
- }
-
- /**
- * Return this NDEF Message as raw bytes.<p>
- * The NDEF Message is formatted as per the NDEF 1.0 specification,
- * and the byte array is suitable for network transmission or storage
- * in an NFC Forum NDEF compatible tag.<p>
- * This method will not chunk any records, and will always use the
- * short record (SR) format and omit the identifier field when possible.
- *
- * @return NDEF Message in binary format
- * @see #getByteArrayLength()
- */
- public byte[] toByteArray() {
- int length = getByteArrayLength();
- ByteBuffer buffer = ByteBuffer.allocate(length);
-
- for (int i=0; i<mRecords.length; i++) {
- boolean mb = (i == 0); // first record
- boolean me = (i == mRecords.length - 1); // last record
- mRecords[i].writeToByteBuffer(buffer, mb, me);
- }
-
- return buffer.array();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mRecords.length);
- dest.writeTypedArray(mRecords, flags);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<NdefMessage> CREATOR =
- new Parcelable.Creator<NdefMessage>() {
- @Override
- public NdefMessage createFromParcel(Parcel in) {
- int recordsLength = in.readInt();
- NdefRecord[] records = new NdefRecord[recordsLength];
- in.readTypedArray(records, NdefRecord.CREATOR);
- return new NdefMessage(records);
- }
- @Override
- public NdefMessage[] newArray(int size) {
- return new NdefMessage[size];
- }
- };
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(mRecords);
- }
-
- /**
- * Returns true if the specified NDEF Message contains
- * identical NDEF Records.
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- NdefMessage other = (NdefMessage) obj;
- return Arrays.equals(mRecords, other.mRecords);
- }
-
- @Override
- public String toString() {
- return "NdefMessage " + Arrays.toString(mRecords);
- }
-
- /**
- * Dump debugging information as a NdefMessageProto
- * @hide
- *
- * Note:
- * See proto definition in frameworks/base/core/proto/android/nfc/ndef.proto
- * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
- * {@link ProtoOutputStream#end(long)} after.
- * Never reuse a proto field number. When removing a field, mark it as reserved.
- */
- public void dumpDebug(ProtoOutputStream proto) {
- for (NdefRecord record : mRecords) {
- long token = proto.start(NdefMessageProto.NDEF_RECORDS);
- record.dumpDebug(proto);
- proto.end(token);
- }
- }
-} \ No newline at end of file
diff --git a/nfc/java/android/nfc/NdefRecord.aidl b/nfc/java/android/nfc/NdefRecord.aidl
deleted file mode 100644
index 10f89d0936e4..000000000000
--- a/nfc/java/android/nfc/NdefRecord.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-parcelable NdefRecord; \ No newline at end of file
diff --git a/nfc/java/android/nfc/NdefRecord.java b/nfc/java/android/nfc/NdefRecord.java
deleted file mode 100644
index 7bf4355d5b35..000000000000
--- a/nfc/java/android/nfc/NdefRecord.java
+++ /dev/null
@@ -1,1080 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.annotation.Nullable;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.proto.ProtoOutputStream;
-
-import java.nio.BufferUnderflowException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Represents an immutable NDEF Record.
- * <p>
- * NDEF (NFC Data Exchange Format) is a light-weight binary format,
- * used to encapsulate typed data. It is specified by the NFC Forum,
- * for transmission and storage with NFC, however it is transport agnostic.
- * <p>
- * NDEF defines messages and records. An NDEF Record contains
- * typed data, such as MIME-type media, a URI, or a custom
- * application payload. An NDEF Message is a container for
- * one or more NDEF Records.
- * <p>
- * This class represents logical (complete) NDEF Records, and can not be
- * used to represent chunked (partial) NDEF Records. However
- * {@link NdefMessage#NdefMessage(byte[])} can be used to parse a message
- * containing chunked records, and will return a message with unchunked
- * (complete) records.
- * <p>
- * A logical NDEF Record always contains a 3-bit TNF (Type Name Field)
- * that provides high level typing for the rest of the record. The
- * remaining fields are variable length and not always present:
- * <ul>
- * <li><em>type</em>: detailed typing for the payload</li>
- * <li><em>id</em>: identifier meta-data, not commonly used</li>
- * <li><em>payload</em>: the actual payload</li>
- * </ul>
- * <p>
- * Helpers such as {@link NdefRecord#createUri}, {@link NdefRecord#createMime}
- * and {@link NdefRecord#createExternal} are included to create well-formatted
- * NDEF Records with correctly set tnf, type, id and payload fields, please
- * use these helpers whenever possible.
- * <p>
- * Use the constructor {@link #NdefRecord(short, byte[], byte[], byte[])}
- * if you know what you are doing and what to set the fields individually.
- * Only basic validation is performed with this constructor, so it is possible
- * to create records that do not confirm to the strict NFC Forum
- * specifications.
- * <p>
- * The binary representation of an NDEF Record includes additional flags to
- * indicate location with an NDEF message, provide support for chunking of
- * NDEF records, and to pack optional fields. This class does not expose
- * those details. To write an NDEF Record as binary you must first put it
- * into an {@link NdefMessage}, then call {@link NdefMessage#toByteArray()}.
- * <p class="note">
- * {@link NdefMessage} and {@link NdefRecord} implementations are
- * always available, even on Android devices that do not have NFC hardware.
- * <p class="note">
- * {@link NdefRecord}s are intended to be immutable (and thread-safe),
- * however they may contain mutable fields. So take care not to modify
- * mutable fields passed into constructors, or modify mutable fields
- * obtained by getter methods, unless such modification is explicitly
- * marked as safe.
- *
- * @see NfcAdapter#ACTION_NDEF_DISCOVERED
- * @see NdefMessage
- */
-public final class NdefRecord implements Parcelable {
- /**
- * Indicates the record is empty.<p>
- * Type, id and payload fields are empty in a {@literal TNF_EMPTY} record.
- */
- public static final short TNF_EMPTY = 0x00;
-
- /**
- * Indicates the type field contains a well-known RTD type name.<p>
- * Use this tnf with RTD types such as {@link #RTD_TEXT}, {@link #RTD_URI}.
- * <p>
- * The RTD type name format is specified in NFCForum-TS-RTD_1.0.
- *
- * @see #RTD_URI
- * @see #RTD_TEXT
- * @see #RTD_SMART_POSTER
- * @see #createUri
- */
- public static final short TNF_WELL_KNOWN = 0x01;
-
- /**
- * Indicates the type field contains a media-type BNF
- * construct, defined by RFC 2046.<p>
- * Use this with MIME type names such as {@literal "image/jpeg"}, or
- * using the helper {@link #createMime}.
- *
- * @see #createMime
- */
- public static final short TNF_MIME_MEDIA = 0x02;
-
- /**
- * Indicates the type field contains an absolute-URI
- * BNF construct defined by RFC 3986.<p>
- * When creating new records prefer {@link #createUri},
- * since it offers more compact URI encoding
- * ({@literal #RTD_URI} allows compression of common URI prefixes).
- *
- * @see #createUri
- */
- public static final short TNF_ABSOLUTE_URI = 0x03;
-
- /**
- * Indicates the type field contains an external type name.<p>
- * Used to encode custom payloads. When creating new records
- * use the helper {@link #createExternal}.<p>
- * The external-type RTD format is specified in NFCForum-TS-RTD_1.0.<p>
- * <p>
- * Note this TNF should not be used with RTD_TEXT or RTD_URI constants.
- * Those are well known RTD constants, not external RTD constants.
- *
- * @see #createExternal
- */
- public static final short TNF_EXTERNAL_TYPE = 0x04;
-
- /**
- * Indicates the payload type is unknown.<p>
- * NFC Forum explains this should be treated similarly to the
- * "application/octet-stream" MIME type. The payload
- * type is not explicitly encoded within the record.
- * <p>
- * The type field is empty in an {@literal TNF_UNKNOWN} record.
- */
- public static final short TNF_UNKNOWN = 0x05;
-
- /**
- * Indicates the payload is an intermediate or final chunk of a chunked
- * NDEF Record.<p>
- * {@literal TNF_UNCHANGED} can not be used with this class
- * since all {@link NdefRecord}s are already unchunked, however they
- * may appear in the binary format.
- */
- public static final short TNF_UNCHANGED = 0x06;
-
- /**
- * Reserved TNF type.
- * <p>
- * The NFC Forum NDEF Specification v1.0 suggests for NDEF parsers to treat this
- * value like TNF_UNKNOWN.
- * @hide
- */
- public static final short TNF_RESERVED = 0x07;
-
- /**
- * RTD Text type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_TEXT = {0x54}; // "T"
-
- /**
- * RTD URI type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_URI = {0x55}; // "U"
-
- /**
- * RTD Smart Poster type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_SMART_POSTER = {0x53, 0x70}; // "Sp"
-
- /**
- * RTD Alternative Carrier type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_ALTERNATIVE_CARRIER = {0x61, 0x63}; // "ac"
-
- /**
- * RTD Handover Carrier type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_HANDOVER_CARRIER = {0x48, 0x63}; // "Hc"
-
- /**
- * RTD Handover Request type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_HANDOVER_REQUEST = {0x48, 0x72}; // "Hr"
-
- /**
- * RTD Handover Select type. For use with {@literal TNF_WELL_KNOWN}.
- * @see #TNF_WELL_KNOWN
- */
- public static final byte[] RTD_HANDOVER_SELECT = {0x48, 0x73}; // "Hs"
-
- /**
- * RTD Android app type. For use with {@literal TNF_EXTERNAL}.
- * <p>
- * The payload of a record with type RTD_ANDROID_APP
- * should be the package name identifying an application.
- * Multiple RTD_ANDROID_APP records may be included
- * in a single {@link NdefMessage}.
- * <p>
- * Use {@link #createApplicationRecord(String)} to create
- * RTD_ANDROID_APP records.
- * @hide
- */
- public static final byte[] RTD_ANDROID_APP = "android.com:pkg".getBytes();
-
- private static final byte FLAG_MB = (byte) 0x80;
- private static final byte FLAG_ME = (byte) 0x40;
- private static final byte FLAG_CF = (byte) 0x20;
- private static final byte FLAG_SR = (byte) 0x10;
- private static final byte FLAG_IL = (byte) 0x08;
-
- /**
- * NFC Forum "URI Record Type Definition"<p>
- * This is a mapping of "URI Identifier Codes" to URI string prefixes,
- * per section 3.2.2 of the NFC Forum URI Record Type Definition document.
- */
- private static final String[] URI_PREFIX_MAP = new String[] {
- "", // 0x00
- "http://www.", // 0x01
- "https://www.", // 0x02
- "http://", // 0x03
- "https://", // 0x04
- "tel:", // 0x05
- "mailto:", // 0x06
- "ftp://anonymous:anonymous@", // 0x07
- "ftp://ftp.", // 0x08
- "ftps://", // 0x09
- "sftp://", // 0x0A
- "smb://", // 0x0B
- "nfs://", // 0x0C
- "ftp://", // 0x0D
- "dav://", // 0x0E
- "news:", // 0x0F
- "telnet://", // 0x10
- "imap:", // 0x11
- "rtsp://", // 0x12
- "urn:", // 0x13
- "pop:", // 0x14
- "sip:", // 0x15
- "sips:", // 0x16
- "tftp:", // 0x17
- "btspp://", // 0x18
- "btl2cap://", // 0x19
- "btgoep://", // 0x1A
- "tcpobex://", // 0x1B
- "irdaobex://", // 0x1C
- "file://", // 0x1D
- "urn:epc:id:", // 0x1E
- "urn:epc:tag:", // 0x1F
- "urn:epc:pat:", // 0x20
- "urn:epc:raw:", // 0x21
- "urn:epc:", // 0x22
- "urn:nfc:", // 0x23
- };
-
- private static final int MAX_PAYLOAD_SIZE = 10 * (1 << 20); // 10 MB payload limit
-
- private static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
-
- private final short mTnf;
- private final byte[] mType;
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- private final byte[] mId;
- private final byte[] mPayload;
-
- /**
- * Create a new Android Application Record (AAR).
- * <p>
- * This record indicates to other Android devices the package
- * that should be used to handle the entire NDEF message.
- * You can embed this record anywhere into your message
- * to ensure that the intended package receives the message.
- * <p>
- * When an Android device dispatches an {@link NdefMessage}
- * containing one or more Android application records,
- * the applications contained in those records will be the
- * preferred target for the {@link NfcAdapter#ACTION_NDEF_DISCOVERED}
- * intent, in the order in which they appear in the message.
- * This dispatch behavior was first added to Android in
- * Ice Cream Sandwich.
- * <p>
- * If none of the applications have a are installed on the device,
- * a Market link will be opened to the first application.
- * <p>
- * Note that Android application records do not overrule
- * applications that have called
- * {@link NfcAdapter#enableForegroundDispatch}.
- *
- * @param packageName Android package name
- * @return Android application NDEF record
- */
- public static NdefRecord createApplicationRecord(String packageName) {
- if (packageName == null) throw new NullPointerException("packageName is null");
- if (packageName.length() == 0) throw new IllegalArgumentException("packageName is empty");
-
- return new NdefRecord(TNF_EXTERNAL_TYPE, RTD_ANDROID_APP, null,
- packageName.getBytes(StandardCharsets.UTF_8));
- }
-
- /**
- * Create a new NDEF Record containing a URI.<p>
- * Use this method to encode a URI (or URL) into an NDEF Record.<p>
- * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
- * and {@link #RTD_URI}. This is the most efficient encoding
- * of a URI into NDEF.<p>
- * The uri parameter will be normalized with
- * {@link Uri#normalizeScheme} to set the scheme to lower case to
- * follow Android best practices for intent filtering.
- * However the unchecked exception
- * {@link IllegalArgumentException} may be thrown if the uri
- * parameter has serious problems, for example if it is empty, so always
- * catch this exception if you are passing user-generated data into this
- * method.<p>
- *
- * Reference specification: NFCForum-TS-RTD_URI_1.0
- *
- * @param uri URI to encode.
- * @return an NDEF Record containing the URI
- * @throws IllegalArugmentException if the uri is empty or invalid
- */
- public static NdefRecord createUri(Uri uri) {
- if (uri == null) throw new NullPointerException("uri is null");
-
- uri = uri.normalizeScheme();
- String uriString = uri.toString();
- if (uriString.length() == 0) throw new IllegalArgumentException("uri is empty");
-
- byte prefix = 0;
- for (int i = 1; i < URI_PREFIX_MAP.length; i++) {
- if (uriString.startsWith(URI_PREFIX_MAP[i])) {
- prefix = (byte) i;
- uriString = uriString.substring(URI_PREFIX_MAP[i].length());
- break;
- }
- }
- byte[] uriBytes = uriString.getBytes(StandardCharsets.UTF_8);
- byte[] recordBytes = new byte[uriBytes.length + 1];
- recordBytes[0] = prefix;
- System.arraycopy(uriBytes, 0, recordBytes, 1, uriBytes.length);
- return new NdefRecord(TNF_WELL_KNOWN, RTD_URI, null, recordBytes);
- }
-
- /**
- * Create a new NDEF Record containing a URI.<p>
- * Use this method to encode a URI (or URL) into an NDEF Record.<p>
- * Uses the well known URI type representation: {@link #TNF_WELL_KNOWN}
- * and {@link #RTD_URI}. This is the most efficient encoding
- * of a URI into NDEF.<p>
- * The uriString parameter will be normalized with
- * {@link Uri#normalizeScheme} to set the scheme to lower case to
- * follow Android best practices for intent filtering.
- * However the unchecked exception
- * {@link IllegalArgumentException} may be thrown if the uriString
- * parameter has serious problems, for example if it is empty, so always
- * catch this exception if you are passing user-generated data into this
- * method.<p>
- *
- * Reference specification: NFCForum-TS-RTD_URI_1.0
- *
- * @param uriString string URI to encode.
- * @return an NDEF Record containing the URI
- * @throws IllegalArugmentException if the uriString is empty or invalid
- */
- public static NdefRecord createUri(String uriString) {
- return createUri(Uri.parse(uriString));
- }
-
- /**
- * Create a new NDEF Record containing MIME data.<p>
- * Use this method to encode MIME-typed data into an NDEF Record,
- * such as "text/plain", or "image/jpeg".<p>
- * The mimeType parameter will be normalized with
- * {@link Intent#normalizeMimeType} to follow Android best
- * practices for intent filtering, for example to force lower-case.
- * However the unchecked exception
- * {@link IllegalArgumentException} may be thrown
- * if the mimeType parameter has serious problems,
- * for example if it is empty, so always catch this
- * exception if you are passing user-generated data into this method.
- * <p>
- * For efficiency, This method might not make an internal copy of the
- * mimeData byte array, so take care not
- * to modify the mimeData byte array while still using the returned
- * NdefRecord.
- *
- * @param mimeType a valid MIME type
- * @param mimeData MIME data as bytes
- * @return an NDEF Record containing the MIME-typed data
- * @throws IllegalArugmentException if the mimeType is empty or invalid
- *
- */
- public static NdefRecord createMime(String mimeType, byte[] mimeData) {
- if (mimeType == null) throw new NullPointerException("mimeType is null");
-
- // We only do basic MIME type validation: trying to follow the
- // RFCs strictly only ends in tears, since there are lots of MIME
- // types in common use that are not strictly valid as per RFC rules
- mimeType = Intent.normalizeMimeType(mimeType);
- if (mimeType.length() == 0) throw new IllegalArgumentException("mimeType is empty");
- int slashIndex = mimeType.indexOf('/');
- if (slashIndex == 0) throw new IllegalArgumentException("mimeType must have major type");
- if (slashIndex == mimeType.length() - 1) {
- throw new IllegalArgumentException("mimeType must have minor type");
- }
- // missing '/' is allowed
-
- // MIME RFCs suggest ASCII encoding for content-type
- byte[] typeBytes = mimeType.getBytes(StandardCharsets.US_ASCII);
- return new NdefRecord(TNF_MIME_MEDIA, typeBytes, null, mimeData);
- }
-
- /**
- * Create a new NDEF Record containing external (application-specific) data.<p>
- * Use this method to encode application specific data into an NDEF Record.
- * The data is typed by a domain name (usually your Android package name) and
- * a domain-specific type. This data is packaged into a "NFC Forum External
- * Type" NDEF Record.<p>
- * NFC Forum requires that the domain and type used in an external record
- * are treated as case insensitive, however Android intent filtering is
- * always case sensitive. So this method will force the domain and type to
- * lower-case before creating the NDEF Record.<p>
- * The unchecked exception {@link IllegalArgumentException} will be thrown
- * if the domain and type have serious problems, for example if either field
- * is empty, so always catch this
- * exception if you are passing user-generated data into this method.<p>
- * There are no such restrictions on the payload data.<p>
- * For efficiency, This method might not make an internal copy of the
- * data byte array, so take care not
- * to modify the data byte array while still using the returned
- * NdefRecord.
- *
- * Reference specification: NFCForum-TS-RTD_1.0
- * @param domain domain-name of issuing organization
- * @param type domain-specific type of data
- * @param data payload as bytes
- * @throws IllegalArugmentException if either domain or type are empty or invalid
- */
- public static NdefRecord createExternal(String domain, String type, byte[] data) {
- if (domain == null) throw new NullPointerException("domain is null");
- if (type == null) throw new NullPointerException("type is null");
-
- domain = domain.trim().toLowerCase(Locale.ROOT);
- type = type.trim().toLowerCase(Locale.ROOT);
-
- if (domain.length() == 0) throw new IllegalArgumentException("domain is empty");
- if (type.length() == 0) throw new IllegalArgumentException("type is empty");
-
- byte[] byteDomain = domain.getBytes(StandardCharsets.UTF_8);
- byte[] byteType = type.getBytes(StandardCharsets.UTF_8);
- byte[] b = new byte[byteDomain.length + 1 + byteType.length];
- System.arraycopy(byteDomain, 0, b, 0, byteDomain.length);
- b[byteDomain.length] = ':';
- System.arraycopy(byteType, 0, b, byteDomain.length + 1, byteType.length);
-
- return new NdefRecord(TNF_EXTERNAL_TYPE, b, null, data);
- }
-
- /**
- * Create a new NDEF record containing UTF-8 text data.<p>
- *
- * The caller can either specify the language code for the provided text,
- * or otherwise the language code corresponding to the current default
- * locale will be used.
- *
- * Reference specification: NFCForum-TS-RTD_Text_1.0
- * @param languageCode The languageCode for the record. If locale is empty or null,
- * the language code of the current default locale will be used.
- * @param text The text to be encoded in the record. Will be represented in UTF-8 format.
- * @throws IllegalArgumentException if text is null
- */
- public static NdefRecord createTextRecord(String languageCode, String text) {
- if (text == null) throw new NullPointerException("text is null");
-
- byte[] textBytes = text.getBytes(StandardCharsets.UTF_8);
-
- byte[] languageCodeBytes = null;
- if (languageCode != null && !languageCode.isEmpty()) {
- languageCodeBytes = languageCode.getBytes(StandardCharsets.US_ASCII);
- } else {
- languageCodeBytes = Locale.getDefault().getLanguage().
- getBytes(StandardCharsets.US_ASCII);
- }
- // We only have 6 bits to indicate ISO/IANA language code.
- if (languageCodeBytes.length >= 64) {
- throw new IllegalArgumentException("language code is too long, must be <64 bytes.");
- }
- ByteBuffer buffer = ByteBuffer.allocate(1 + languageCodeBytes.length + textBytes.length);
-
- byte status = (byte) (languageCodeBytes.length & 0xFF);
- buffer.put(status);
- buffer.put(languageCodeBytes);
- buffer.put(textBytes);
-
- return new NdefRecord(TNF_WELL_KNOWN, RTD_TEXT, null, buffer.array());
- }
-
- /**
- * Construct an NDEF Record from its component fields.<p>
- * Recommend to use helpers such as {#createUri} or
- * {{@link #createExternal} where possible, since they perform
- * stricter validation that the record is correctly formatted
- * as per NDEF specifications. However if you know what you are
- * doing then this constructor offers the most flexibility.<p>
- * An {@link NdefRecord} represents a logical (complete)
- * record, and cannot represent NDEF Record chunks.<p>
- * Basic validation of the tnf, type, id and payload is performed
- * as per the following rules:
- * <ul>
- * <li>The tnf paramter must be a 3-bit value.</li>
- * <li>Records with a tnf of {@link #TNF_EMPTY} cannot have a type,
- * id or payload.</li>
- * <li>Records with a tnf of {@link #TNF_UNKNOWN} or {@literal 0x07}
- * cannot have a type.</li>
- * <li>Records with a tnf of {@link #TNF_UNCHANGED} are not allowed
- * since this class only represents complete (unchunked) records.</li>
- * </ul>
- * This minimal validation is specified by
- * NFCForum-TS-NDEF_1.0 section 3.2.6 (Type Name Format).<p>
- * If any of the above validation
- * steps fail then {@link IllegalArgumentException} is thrown.<p>
- * Deep inspection of the type, id and payload fields is not
- * performed, so it is possible to create NDEF Records
- * that conform to section 3.2.6
- * but fail other more strict NDEF specification requirements. For
- * example, the payload may be invalid given the tnf and type.
- * <p>
- * To omit a type, id or payload field, set the parameter to an
- * empty byte array or null.
- *
- * @param tnf a 3-bit TNF constant
- * @param type byte array, containing zero to 255 bytes, or null
- * @param id byte array, containing zero to 255 bytes, or null
- * @param payload byte array, containing zero to (2 ** 32 - 1) bytes,
- * or null
- * @throws IllegalArugmentException if a valid record cannot be created
- */
- public NdefRecord(short tnf, byte[] type, byte[] id, byte[] payload) {
- /* convert nulls */
- if (type == null) type = EMPTY_BYTE_ARRAY;
- if (id == null) id = EMPTY_BYTE_ARRAY;
- if (payload == null) payload = EMPTY_BYTE_ARRAY;
-
- String message = validateTnf(tnf, type, id, payload);
- if (message != null) {
- throw new IllegalArgumentException(message);
- }
-
- mTnf = tnf;
- mType = type;
- mId = id;
- mPayload = payload;
- }
-
- /**
- * Construct an NDEF Record from raw bytes.<p>
- * This method is deprecated, use {@link NdefMessage#NdefMessage(byte[])}
- * instead. This is because it does not make sense to parse a record:
- * the NDEF binary format is only defined for a message, and the
- * record flags MB and ME do not make sense outside of the context of
- * an entire message.<p>
- * This implementation will attempt to parse a single record by ignoring
- * the MB and ME flags, and otherwise following the rules of
- * {@link NdefMessage#NdefMessage(byte[])}.<p>
- *
- * @param data raw bytes to parse
- * @throws FormatException if the data cannot be parsed into a valid record
- * @deprecated use {@link NdefMessage#NdefMessage(byte[])} instead.
- */
- @Deprecated
- public NdefRecord(byte[] data) throws FormatException {
- ByteBuffer buffer = ByteBuffer.wrap(data);
- NdefRecord[] rs = parse(buffer, true);
-
- if (buffer.remaining() > 0) {
- throw new FormatException("data too long");
- }
-
- mTnf = rs[0].mTnf;
- mType = rs[0].mType;
- mId = rs[0].mId;
- mPayload = rs[0].mPayload;
- }
-
- /**
- * Returns the 3-bit TNF.
- * <p>
- * TNF is the top-level type.
- */
- public short getTnf() {
- return mTnf;
- }
-
- /**
- * Returns the variable length Type field.
- * <p>
- * This should be used in conjunction with the TNF field to determine the
- * payload format.
- * <p>
- * Returns an empty byte array if this record
- * does not have a type field.
- */
- public byte[] getType() {
- return mType.clone();
- }
-
- /**
- * Returns the variable length ID.
- * <p>
- * Returns an empty byte array if this record
- * does not have an id field.
- */
- public byte[] getId() {
- return mId.clone();
- }
-
- /**
- * Returns the variable length payload.
- * <p>
- * Returns an empty byte array if this record
- * does not have a payload field.
- */
- public byte[] getPayload() {
- return mPayload.clone();
- }
-
- /**
- * Return this NDEF Record as a byte array.<p>
- * This method is deprecated, use {@link NdefMessage#toByteArray}
- * instead. This is because the NDEF binary format is not defined for
- * a record outside of the context of a message: the MB and ME flags
- * cannot be set without knowing the location inside a message.<p>
- * This implementation will attempt to serialize a single record by
- * always setting the MB and ME flags (in other words, assume this
- * is a single-record NDEF Message).<p>
- *
- * @deprecated use {@link NdefMessage#toByteArray()} instead
- */
- @Deprecated
- public byte[] toByteArray() {
- ByteBuffer buffer = ByteBuffer.allocate(getByteLength());
- writeToByteBuffer(buffer, true, true);
- return buffer.array();
- }
-
- /**
- * Map this record to a MIME type, or return null if it cannot be mapped.<p>
- * Currently this method considers all {@link #TNF_MIME_MEDIA} records to
- * be MIME records, as well as some {@link #TNF_WELL_KNOWN} records such as
- * {@link #RTD_TEXT}. If this is a MIME record then the MIME type as string
- * is returned, otherwise null is returned.<p>
- * This method does not perform validation that the MIME type is
- * actually valid. It always attempts to
- * return a string containing the type if this is a MIME record.<p>
- * The returned MIME type will by normalized to lower-case using
- * {@link Intent#normalizeMimeType}.<p>
- * The MIME payload can be obtained using {@link #getPayload}.
- *
- * @return MIME type as a string, or null if this is not a MIME record
- */
- public String toMimeType() {
- switch (mTnf) {
- case NdefRecord.TNF_WELL_KNOWN:
- if (Arrays.equals(mType, NdefRecord.RTD_TEXT)) {
- return "text/plain";
- }
- break;
- case NdefRecord.TNF_MIME_MEDIA:
- String mimeType = new String(mType, StandardCharsets.US_ASCII);
- return Intent.normalizeMimeType(mimeType);
- }
- return null;
- }
-
- /**
- * Map this record to a URI, or return null if it cannot be mapped.<p>
- * Currently this method considers the following to be URI records:
- * <ul>
- * <li>{@link #TNF_ABSOLUTE_URI} records.</li>
- * <li>{@link #TNF_WELL_KNOWN} with a type of {@link #RTD_URI}.</li>
- * <li>{@link #TNF_WELL_KNOWN} with a type of {@link #RTD_SMART_POSTER}
- * and containing a URI record in the NDEF message nested in the payload.
- * </li>
- * <li>{@link #TNF_EXTERNAL_TYPE} records.</li>
- * </ul>
- * If this is not a URI record by the above rules, then null is returned.<p>
- * This method does not perform validation that the URI is
- * actually valid: it always attempts to create and return a URI if
- * this record appears to be a URI record by the above rules.<p>
- * The returned URI will be normalized to have a lower case scheme
- * using {@link Uri#normalizeScheme}.<p>
- *
- * @return URI, or null if this is not a URI record
- */
- public Uri toUri() {
- return toUri(false);
- }
-
- private Uri toUri(boolean inSmartPoster) {
- switch (mTnf) {
- case TNF_WELL_KNOWN:
- if (Arrays.equals(mType, RTD_SMART_POSTER) && !inSmartPoster) {
- try {
- // check payload for a nested NDEF Message containing a URI
- NdefMessage nestedMessage = new NdefMessage(mPayload);
- for (NdefRecord nestedRecord : nestedMessage.getRecords()) {
- Uri uri = nestedRecord.toUri(true);
- if (uri != null) {
- return uri;
- }
- }
- } catch (FormatException e) { }
- } else if (Arrays.equals(mType, RTD_URI)) {
- Uri wktUri = parseWktUri();
- return (wktUri != null ? wktUri.normalizeScheme() : null);
- }
- break;
-
- case TNF_ABSOLUTE_URI:
- Uri uri = Uri.parse(new String(mType, StandardCharsets.UTF_8));
- return uri.normalizeScheme();
-
- case TNF_EXTERNAL_TYPE:
- if (inSmartPoster) {
- break;
- }
- return Uri.parse("vnd.android.nfc://ext/" + new String(mType, StandardCharsets.US_ASCII));
- }
- return null;
- }
-
- /**
- * Return complete URI of {@link #TNF_WELL_KNOWN}, {@link #RTD_URI} records.
- * @return complete URI, or null if invalid
- */
- private Uri parseWktUri() {
- if (mPayload.length < 2) {
- return null;
- }
-
- // payload[0] contains the URI Identifier Code, as per
- // NFC Forum "URI Record Type Definition" section 3.2.2.
- int prefixIndex = (mPayload[0] & (byte)0xFF);
- if (prefixIndex < 0 || prefixIndex >= URI_PREFIX_MAP.length) {
- return null;
- }
- String prefix = URI_PREFIX_MAP[prefixIndex];
- String suffix = new String(Arrays.copyOfRange(mPayload, 1, mPayload.length),
- StandardCharsets.UTF_8);
- return Uri.parse(prefix + suffix);
- }
-
- /**
- * Main record parsing method.<p>
- * Expects NdefMessage to begin immediately, allows trailing data.<p>
- * Currently has strict validation of all fields as per NDEF 1.0
- * specification section 2.5. We will attempt to keep this as strict as
- * possible to encourage well-formatted NDEF.<p>
- * Always returns 1 or more NdefRecord's, or throws FormatException.
- *
- * @param buffer ByteBuffer to read from
- * @param ignoreMbMe ignore MB and ME flags, and read only 1 complete record
- * @return one or more records
- * @throws FormatException on any parsing error
- */
- static NdefRecord[] parse(ByteBuffer buffer, boolean ignoreMbMe) throws FormatException {
- List<NdefRecord> records = new ArrayList<NdefRecord>();
-
- try {
- byte[] type = null;
- byte[] id = null;
- byte[] payload = null;
- ArrayList<byte[]> chunks = new ArrayList<byte[]>();
- boolean inChunk = false;
- short chunkTnf = -1;
- boolean me = false;
-
- while (!me) {
- byte flag = buffer.get();
-
- boolean mb = (flag & NdefRecord.FLAG_MB) != 0;
- me = (flag & NdefRecord.FLAG_ME) != 0;
- boolean cf = (flag & NdefRecord.FLAG_CF) != 0;
- boolean sr = (flag & NdefRecord.FLAG_SR) != 0;
- boolean il = (flag & NdefRecord.FLAG_IL) != 0;
- short tnf = (short)(flag & 0x07);
-
- if (!mb && records.size() == 0 && !inChunk && !ignoreMbMe) {
- throw new FormatException("expected MB flag");
- } else if (mb && (records.size() != 0 || inChunk) && !ignoreMbMe) {
- throw new FormatException("unexpected MB flag");
- } else if (inChunk && il) {
- throw new FormatException("unexpected IL flag in non-leading chunk");
- } else if (cf && me) {
- throw new FormatException("unexpected ME flag in non-trailing chunk");
- } else if (inChunk && tnf != NdefRecord.TNF_UNCHANGED) {
- throw new FormatException("expected TNF_UNCHANGED in non-leading chunk");
- } else if (!inChunk && tnf == NdefRecord.TNF_UNCHANGED) {
- throw new FormatException("" +
- "unexpected TNF_UNCHANGED in first chunk or unchunked record");
- }
-
- int typeLength = buffer.get() & 0xFF;
- long payloadLength = sr ? (buffer.get() & 0xFF) : (buffer.getInt() & 0xFFFFFFFFL);
- int idLength = il ? (buffer.get() & 0xFF) : 0;
-
- if (inChunk && typeLength != 0) {
- throw new FormatException("expected zero-length type in non-leading chunk");
- }
-
- if (!inChunk) {
- type = (typeLength > 0 ? new byte[typeLength] : EMPTY_BYTE_ARRAY);
- id = (idLength > 0 ? new byte[idLength] : EMPTY_BYTE_ARRAY);
- buffer.get(type);
- buffer.get(id);
- }
-
- ensureSanePayloadSize(payloadLength);
- payload = (payloadLength > 0 ? new byte[(int)payloadLength] : EMPTY_BYTE_ARRAY);
- buffer.get(payload);
-
- if (cf && !inChunk) {
- // first chunk
- if (typeLength == 0 && tnf != NdefRecord.TNF_UNKNOWN) {
- throw new FormatException("expected non-zero type length in first chunk");
- }
- chunks.clear();
- chunkTnf = tnf;
- }
- if (cf || inChunk) {
- // any chunk
- chunks.add(payload);
- }
- if (!cf && inChunk) {
- // last chunk, flatten the payload
- payloadLength = 0;
- for (byte[] p : chunks) {
- payloadLength += p.length;
- }
- ensureSanePayloadSize(payloadLength);
- payload = new byte[(int)payloadLength];
- int i = 0;
- for (byte[] p : chunks) {
- System.arraycopy(p, 0, payload, i, p.length);
- i += p.length;
- }
- tnf = chunkTnf;
- }
- if (cf) {
- // more chunks to come
- inChunk = true;
- continue;
- } else {
- inChunk = false;
- }
-
- String error = validateTnf(tnf, type, id, payload);
- if (error != null) {
- throw new FormatException(error);
- }
- records.add(new NdefRecord(tnf, type, id, payload));
- if (ignoreMbMe) { // for parsing a single NdefRecord
- break;
- }
- }
- } catch (BufferUnderflowException e) {
- throw new FormatException("expected more data", e);
- }
- return records.toArray(new NdefRecord[records.size()]);
- }
-
- private static void ensureSanePayloadSize(long size) throws FormatException {
- if (size > MAX_PAYLOAD_SIZE) {
- throw new FormatException(
- "payload above max limit: " + size + " > " + MAX_PAYLOAD_SIZE);
- }
- }
-
- /**
- * Perform simple validation that the tnf is valid.<p>
- * Validates the requirements of NFCForum-TS-NDEF_1.0 section
- * 3.2.6 (Type Name Format). This just validates that the tnf
- * is valid, and that the relevant type, id and payload
- * fields are present (or empty) for this tnf. It does not
- * perform any deep inspection of the type, id and payload fields.<p>
- * Also does not allow TNF_UNCHANGED since this class is only used
- * to present logical (unchunked) records.
- *
- * @return null if valid, or a string error if invalid.
- */
- static String validateTnf(short tnf, byte[] type, byte[] id, byte[] payload) {
- switch (tnf) {
- case TNF_EMPTY:
- if (type.length != 0 || id.length != 0 || payload.length != 0) {
- return "unexpected data in TNF_EMPTY record";
- }
- return null;
- case TNF_WELL_KNOWN:
- case TNF_MIME_MEDIA:
- case TNF_ABSOLUTE_URI:
- case TNF_EXTERNAL_TYPE:
- return null;
- case TNF_UNKNOWN:
- case TNF_RESERVED:
- if (type.length != 0) {
- return "unexpected type field in TNF_UNKNOWN or TNF_RESERVEd record";
- }
- return null;
- case TNF_UNCHANGED:
- return "unexpected TNF_UNCHANGED in first chunk or logical record";
- default:
- return String.format("unexpected tnf value: 0x%02x", tnf);
- }
- }
-
- /**
- * Serialize record for network transmission.<p>
- * Uses specified MB and ME flags.<p>
- * Does not chunk records.
- */
- void writeToByteBuffer(ByteBuffer buffer, boolean mb, boolean me) {
- boolean sr = mPayload.length < 256;
- boolean il = mTnf == TNF_EMPTY ? true : mId.length > 0;
-
- byte flags = (byte)((mb ? FLAG_MB : 0) | (me ? FLAG_ME : 0) |
- (sr ? FLAG_SR : 0) | (il ? FLAG_IL : 0) | mTnf);
- buffer.put(flags);
-
- buffer.put((byte)mType.length);
- if (sr) {
- buffer.put((byte)mPayload.length);
- } else {
- buffer.putInt(mPayload.length);
- }
- if (il) {
- buffer.put((byte)mId.length);
- }
-
- buffer.put(mType);
- buffer.put(mId);
- buffer.put(mPayload);
- }
-
- /**
- * Get byte length of serialized record.
- */
- int getByteLength() {
- int length = 3 + mType.length + mId.length + mPayload.length;
-
- boolean sr = mPayload.length < 256;
- boolean il = mTnf == TNF_EMPTY ? true : mId.length > 0;
-
- if (!sr) length += 3;
- if (il) length += 1;
-
- return length;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mTnf);
- dest.writeInt(mType.length);
- dest.writeByteArray(mType);
- dest.writeInt(mId.length);
- dest.writeByteArray(mId);
- dest.writeInt(mPayload.length);
- dest.writeByteArray(mPayload);
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<NdefRecord> CREATOR =
- new Parcelable.Creator<NdefRecord>() {
- @Override
- public NdefRecord createFromParcel(Parcel in) {
- short tnf = (short)in.readInt();
- int typeLength = in.readInt();
- byte[] type = new byte[typeLength];
- in.readByteArray(type);
- int idLength = in.readInt();
- byte[] id = new byte[idLength];
- in.readByteArray(id);
- int payloadLength = in.readInt();
- byte[] payload = new byte[payloadLength];
- in.readByteArray(payload);
-
- return new NdefRecord(tnf, type, id, payload);
- }
- @Override
- public NdefRecord[] newArray(int size) {
- return new NdefRecord[size];
- }
- };
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + Arrays.hashCode(mId);
- result = prime * result + Arrays.hashCode(mPayload);
- result = prime * result + mTnf;
- result = prime * result + Arrays.hashCode(mType);
- return result;
- }
-
- /**
- * Returns true if the specified NDEF Record contains
- * identical tnf, type, id and payload fields.
- */
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) return true;
- if (obj == null) return false;
- if (getClass() != obj.getClass()) return false;
- NdefRecord other = (NdefRecord) obj;
- if (!Arrays.equals(mId, other.mId)) return false;
- if (!Arrays.equals(mPayload, other.mPayload)) return false;
- if (mTnf != other.mTnf) return false;
- return Arrays.equals(mType, other.mType);
- }
-
- @Override
- public String toString() {
- StringBuilder b = new StringBuilder(String.format("NdefRecord tnf=%X", mTnf));
- if (mType.length > 0) b.append(" type=").append(bytesToString(mType));
- if (mId.length > 0) b.append(" id=").append(bytesToString(mId));
- if (mPayload.length > 0) b.append(" payload=").append(bytesToString(mPayload));
- return b.toString();
- }
-
- /**
- * Dump debugging information as a NdefRecordProto
- * @hide
- *
- * Note:
- * See proto definition in frameworks/base/core/proto/android/nfc/ndef.proto
- * When writing a nested message, must call {@link ProtoOutputStream#start(long)} before and
- * {@link ProtoOutputStream#end(long)} after.
- * Never reuse a proto field number. When removing a field, mark it as reserved.
- */
- public void dumpDebug(ProtoOutputStream proto) {
- proto.write(NdefRecordProto.TYPE, mType);
- proto.write(NdefRecordProto.ID, mId);
- proto.write(NdefRecordProto.PAYLOAD_BYTES, mPayload.length);
- }
-
- private static StringBuilder bytesToString(byte[] bs) {
- StringBuilder s = new StringBuilder();
- for (byte b : bs) {
- s.append(String.format("%02X", b));
- }
- return s;
- }
-}
diff --git a/nfc/java/android/nfc/NfcActivityManager.java b/nfc/java/android/nfc/NfcActivityManager.java
deleted file mode 100644
index 909eca7b0c9d..000000000000
--- a/nfc/java/android/nfc/NfcActivityManager.java
+++ /dev/null
@@ -1,403 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-import android.app.Activity;
-import android.app.Application;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.nfc.NfcAdapter.ReaderCallback;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Manages NFC API's that are coupled to the life-cycle of an Activity.
- *
- * <p>Uses {@link Application#registerActivityLifecycleCallbacks} to hook
- * into activity life-cycle events such as onPause() and onResume().
- *
- * @hide
- */
-public final class NfcActivityManager extends IAppCallback.Stub
- implements Application.ActivityLifecycleCallbacks {
- static final String TAG = NfcAdapter.TAG;
- static final Boolean DBG = false;
-
- @UnsupportedAppUsage
- final NfcAdapter mAdapter;
-
- // All objects in the lists are protected by this
- final List<NfcApplicationState> mApps; // Application(s) that have NFC state. Usually one
- final List<NfcActivityState> mActivities; // Activities that have NFC state
-
- /**
- * NFC State associated with an {@link Application}.
- */
- class NfcApplicationState {
- int refCount = 0;
- final Application app;
- public NfcApplicationState(Application app) {
- this.app = app;
- }
- public void register() {
- refCount++;
- if (refCount == 1) {
- this.app.registerActivityLifecycleCallbacks(NfcActivityManager.this);
- }
- }
- public void unregister() {
- refCount--;
- if (refCount == 0) {
- this.app.unregisterActivityLifecycleCallbacks(NfcActivityManager.this);
- } else if (refCount < 0) {
- Log.e(TAG, "-ve refcount for " + app);
- }
- }
- }
-
- NfcApplicationState findAppState(Application app) {
- for (NfcApplicationState appState : mApps) {
- if (appState.app == app) {
- return appState;
- }
- }
- return null;
- }
-
- void registerApplication(Application app) {
- NfcApplicationState appState = findAppState(app);
- if (appState == null) {
- appState = new NfcApplicationState(app);
- mApps.add(appState);
- }
- appState.register();
- }
-
- void unregisterApplication(Application app) {
- NfcApplicationState appState = findAppState(app);
- if (appState == null) {
- Log.e(TAG, "app was not registered " + app);
- return;
- }
- appState.unregister();
- }
-
- /**
- * NFC state associated with an {@link Activity}
- */
- class NfcActivityState {
- boolean resumed = false;
- Activity activity;
- NfcAdapter.ReaderCallback readerCallback = null;
- int readerModeFlags = 0;
- Bundle readerModeExtras = null;
- Binder token;
-
- int mPollTech = NfcAdapter.FLAG_USE_ALL_TECH;
- int mListenTech = NfcAdapter.FLAG_USE_ALL_TECH;
-
- public NfcActivityState(Activity activity) {
- if (activity.isDestroyed()) {
- throw new IllegalStateException("activity is already destroyed");
- }
- // Check if activity is resumed right now, as we will not
- // immediately get a callback for that.
- resumed = activity.isResumed();
-
- this.activity = activity;
- this.token = new Binder();
- registerApplication(activity.getApplication());
- }
- public void destroy() {
- unregisterApplication(activity.getApplication());
- resumed = false;
- activity = null;
- readerCallback = null;
- readerModeFlags = 0;
- readerModeExtras = null;
- token = null;
-
- mPollTech = NfcAdapter.FLAG_USE_ALL_TECH;
- mListenTech = NfcAdapter.FLAG_USE_ALL_TECH;
- }
- @Override
- public String toString() {
- StringBuilder s = new StringBuilder("[");
- s.append(readerCallback);
- s.append("]");
- return s.toString();
- }
- }
-
- /** find activity state from mActivities */
- synchronized NfcActivityState findActivityState(Activity activity) {
- for (NfcActivityState state : mActivities) {
- if (state.activity == activity) {
- return state;
- }
- }
- return null;
- }
-
- /** find or create activity state from mActivities */
- synchronized NfcActivityState getActivityState(Activity activity) {
- NfcActivityState state = findActivityState(activity);
- if (state == null) {
- state = new NfcActivityState(activity);
- mActivities.add(state);
- }
- return state;
- }
-
- synchronized NfcActivityState findResumedActivityState() {
- for (NfcActivityState state : mActivities) {
- if (state.resumed) {
- return state;
- }
- }
- return null;
- }
-
- synchronized void destroyActivityState(Activity activity) {
- NfcActivityState activityState = findActivityState(activity);
- if (activityState != null) {
- activityState.destroy();
- mActivities.remove(activityState);
- }
- }
-
- public NfcActivityManager(NfcAdapter adapter) {
- mAdapter = adapter;
- mActivities = new LinkedList<NfcActivityState>();
- mApps = new ArrayList<NfcApplicationState>(1); // Android VM usually has 1 app
- }
-
- public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
- Bundle extras) {
- boolean isResumed;
- Binder token;
- int pollTech, listenTech;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.readerCallback = callback;
- state.readerModeFlags = flags;
- state.readerModeExtras = extras;
- pollTech = state.mPollTech;
- listenTech = state.mListenTech;
- token = state.token;
- isResumed = state.resumed;
- }
- if (isResumed) {
- if (listenTech != NfcAdapter.FLAG_USE_ALL_TECH
- || pollTech != NfcAdapter.FLAG_USE_ALL_TECH) {
- throw new IllegalStateException(
- "Cannot be used when alternative DiscoveryTechnology is set");
- } else {
- setReaderMode(token, flags, extras);
- }
- }
- }
-
- public void disableReaderMode(Activity activity) {
- boolean isResumed;
- Binder token;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.readerCallback = null;
- state.readerModeFlags = 0;
- state.readerModeExtras = null;
- token = state.token;
- isResumed = state.resumed;
- }
- if (isResumed) {
- setReaderMode(token, 0, null);
- }
-
- }
-
- public void setReaderMode(Binder token, int flags, Bundle extras) {
- if (DBG) Log.d(TAG, "Setting reader mode");
- NfcAdapter.callService(() -> NfcAdapter.sService.setReaderMode(
- token, this, flags, extras, mAdapter.getContext().getPackageName()));
- }
-
- /**
- * Request or unrequest NFC service callbacks.
- * Makes IPC call - do not hold lock.
- */
- void requestNfcServiceCallback() {
- NfcAdapter.callService(() -> NfcAdapter.sService.setAppCallback(this));
- }
-
- void verifyNfcPermission() {
- NfcAdapter.callService(() -> NfcAdapter.sService.verifyNfcPermission());
- }
-
- @Override
- public void onTagDiscovered(Tag tag) throws RemoteException {
- NfcAdapter.ReaderCallback callback;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = findResumedActivityState();
- if (state == null) return;
-
- callback = state.readerCallback;
- }
-
- // Make callback without lock
- if (callback != null) {
- callback.onTagDiscovered(tag);
- }
-
- }
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivityCreated(Activity activity, Bundle savedInstanceState) { /* NO-OP */ }
-
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivityStarted(Activity activity) { /* NO-OP */ }
-
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivityResumed(Activity activity) {
- int readerModeFlags = 0;
- Bundle readerModeExtras = null;
- Binder token;
- int pollTech;
- int listenTech;
-
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = findActivityState(activity);
- if (DBG) Log.d(TAG, "onResume() for " + activity + " " + state);
- if (state == null) return;
- state.resumed = true;
- token = state.token;
- readerModeFlags = state.readerModeFlags;
- readerModeExtras = state.readerModeExtras;
-
- pollTech = state.mPollTech;
- listenTech = state.mListenTech;
- }
- if (readerModeFlags != 0) {
- setReaderMode(token, readerModeFlags, readerModeExtras);
- } else if (listenTech != NfcAdapter.FLAG_USE_ALL_TECH
- || pollTech != NfcAdapter.FLAG_USE_ALL_TECH) {
- changeDiscoveryTech(token, pollTech, listenTech);
- }
- requestNfcServiceCallback();
- }
-
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivityPaused(Activity activity) {
- boolean readerModeFlagsSet;
- Binder token;
- int pollTech;
- int listenTech;
-
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = findActivityState(activity);
- if (DBG) Log.d(TAG, "onPause() for " + activity + " " + state);
- if (state == null) return;
- state.resumed = false;
- token = state.token;
- readerModeFlagsSet = state.readerModeFlags != 0;
-
- pollTech = state.mPollTech;
- listenTech = state.mListenTech;
- }
- if (readerModeFlagsSet) {
- // Restore default p2p modes
- setReaderMode(token, 0, null);
- } else if (listenTech != NfcAdapter.FLAG_USE_ALL_TECH
- || pollTech != NfcAdapter.FLAG_USE_ALL_TECH) {
- changeDiscoveryTech(token,
- NfcAdapter.FLAG_USE_ALL_TECH, NfcAdapter.FLAG_USE_ALL_TECH);
- }
- }
-
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivityStopped(Activity activity) { /* NO-OP */ }
-
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle outState) { /* NO-OP */ }
-
- /** Callback from Activity life-cycle, on main thread */
- @Override
- public void onActivityDestroyed(Activity activity) {
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = findActivityState(activity);
- if (DBG) Log.d(TAG, "onDestroy() for " + activity + " " + state);
- if (state != null) {
- // release all associated references
- destroyActivityState(activity);
- }
- }
- }
-
- /** setDiscoveryTechnology() implementation */
- public void setDiscoveryTech(Activity activity, int pollTech, int listenTech) {
- boolean isResumed;
- Binder token;
- boolean readerModeFlagsSet;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- readerModeFlagsSet = state.readerModeFlags != 0;
- state.mListenTech = listenTech;
- state.mPollTech = pollTech;
- token = state.token;
- isResumed = state.resumed;
- }
- if (!readerModeFlagsSet && isResumed) {
- changeDiscoveryTech(token, pollTech, listenTech);
- } else if (readerModeFlagsSet) {
- throw new IllegalStateException("Cannot be used when the Reader Mode is enabled");
- }
- }
-
- /** resetDiscoveryTechnology() implementation */
- public void resetDiscoveryTech(Activity activity) {
- boolean isResumed;
- Binder token;
- boolean readerModeFlagsSet;
- synchronized (NfcActivityManager.this) {
- NfcActivityState state = getActivityState(activity);
- state.mListenTech = NfcAdapter.FLAG_USE_ALL_TECH;
- state.mPollTech = NfcAdapter.FLAG_USE_ALL_TECH;
- token = state.token;
- isResumed = state.resumed;
- }
- if (isResumed) {
- changeDiscoveryTech(token, NfcAdapter.FLAG_USE_ALL_TECH, NfcAdapter.FLAG_USE_ALL_TECH);
- }
-
- }
-
- private void changeDiscoveryTech(Binder token, int pollTech, int listenTech) {
- NfcAdapter.callService(
- () -> NfcAdapter.sService.updateDiscoveryTechnology(
- token, pollTech, listenTech, mAdapter.getContext().getPackageName()));
- }
-
-}
diff --git a/nfc/java/android/nfc/NfcAdapter.java b/nfc/java/android/nfc/NfcAdapter.java
deleted file mode 100644
index 63397c21b036..000000000000
--- a/nfc/java/android/nfc/NfcAdapter.java
+++ /dev/null
@@ -1,2949 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.annotation.SystemApi;
-import android.annotation.TestApi;
-import android.annotation.UserIdInt;
-import android.app.Activity;
-import android.app.PendingIntent;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.net.Uri;
-import android.nfc.cardemulation.PollingFrame;
-import android.nfc.tech.MifareClassic;
-import android.nfc.tech.Ndef;
-import android.nfc.tech.NfcA;
-import android.nfc.tech.NfcF;
-import android.os.Binder;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.Log;
-
-import java.io.IOException;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-
-/**
- * Represents the local NFC adapter.
- * <p>
- * Use the helper {@link #getDefaultAdapter(Context)} to get the default NFC
- * adapter for this Android device.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using NFC, read the
- * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
- * <p>To perform basic file sharing between devices, read
- * <a href="{@docRoot}training/beam-files/index.html">Sharing Files with NFC</a>.
- * </div>
- */
-public final class NfcAdapter {
- static final String TAG = "NFC";
-
- private final NfcControllerAlwaysOnListener mControllerAlwaysOnListener;
- private final NfcWlcStateListener mNfcWlcStateListener;
- private final NfcVendorNciCallbackListener mNfcVendorNciCallbackListener;
-
- /**
- * Intent to start an activity when a tag with NDEF payload is discovered.
- *
- * <p>The system inspects the first {@link NdefRecord} in the first {@link NdefMessage} and
- * looks for a URI, SmartPoster, or MIME record. If a URI or SmartPoster record is found the
- * intent will contain the URI in its data field. If a MIME record is found the intent will
- * contain the MIME type in its type field. This allows activities to register
- * {@link IntentFilter}s targeting specific content on tags. Activities should register the
- * most specific intent filters possible to avoid the activity chooser dialog, which can
- * disrupt the interaction with the tag as the user interacts with the screen.
- *
- * <p>If the tag has an NDEF payload this intent is started before
- * {@link #ACTION_TECH_DISCOVERED}. If any activities respond to this intent neither
- * {@link #ACTION_TECH_DISCOVERED} or {@link #ACTION_TAG_DISCOVERED} will be started.
- *
- * <p>The MIME type or data URI of this intent are normalized before dispatch -
- * so that MIME, URI scheme and URI host are always lower-case.
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_NDEF_DISCOVERED = "android.nfc.action.NDEF_DISCOVERED";
-
- /**
- * Intent to start an activity when a tag is discovered and activities are registered for the
- * specific technologies on the tag.
- *
- * <p>To receive this intent an activity must include an intent filter
- * for this action and specify the desired tech types in a
- * manifest <code>meta-data</code> entry. Here is an example manfiest entry:
- * <pre>
- * &lt;activity android:name=".nfc.TechFilter" android:label="NFC/TechFilter"&gt;
- * &lt;!-- Add a technology filter --&gt;
- * &lt;intent-filter&gt;
- * &lt;action android:name="android.nfc.action.TECH_DISCOVERED" /&gt;
- * &lt;/intent-filter&gt;
- *
- * &lt;meta-data android:name="android.nfc.action.TECH_DISCOVERED"
- * android:resource="@xml/filter_nfc"
- * /&gt;
- * &lt;/activity&gt;</pre>
- *
- * <p>The meta-data XML file should contain one or more <code>tech-list</code> entries
- * each consisting or one or more <code>tech</code> entries. The <code>tech</code> entries refer
- * to the qualified class name implementing the technology, for example "android.nfc.tech.NfcA".
- *
- * <p>A tag matches if any of the
- * <code>tech-list</code> sets is a subset of {@link Tag#getTechList() Tag.getTechList()}. Each
- * of the <code>tech-list</code>s is considered independently and the
- * activity is considered a match is any single <code>tech-list</code> matches the tag that was
- * discovered. This provides AND and OR semantics for filtering desired techs. Here is an
- * example that will match any tag using {@link NfcF} or any tag using {@link NfcA},
- * {@link MifareClassic}, and {@link Ndef}:
- *
- * <pre>
- * &lt;resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"&gt;
- * &lt;!-- capture anything using NfcF --&gt;
- * &lt;tech-list&gt;
- * &lt;tech&gt;android.nfc.tech.NfcF&lt;/tech&gt;
- * &lt;/tech-list&gt;
- *
- * &lt;!-- OR --&gt;
- *
- * &lt;!-- capture all MIFARE Classics with NDEF payloads --&gt;
- * &lt;tech-list&gt;
- * &lt;tech&gt;android.nfc.tech.NfcA&lt;/tech&gt;
- * &lt;tech&gt;android.nfc.tech.MifareClassic&lt;/tech&gt;
- * &lt;tech&gt;android.nfc.tech.Ndef&lt;/tech&gt;
- * &lt;/tech-list&gt;
- * &lt;/resources&gt;</pre>
- *
- * <p>This intent is started after {@link #ACTION_NDEF_DISCOVERED} and before
- * {@link #ACTION_TAG_DISCOVERED}. If any activities respond to {@link #ACTION_NDEF_DISCOVERED}
- * this intent will not be started. If any activities respond to this intent
- * {@link #ACTION_TAG_DISCOVERED} will not be started.
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_TECH_DISCOVERED = "android.nfc.action.TECH_DISCOVERED";
-
- /**
- * Intent to start an activity when a tag is discovered.
- *
- * <p>This intent will not be started when a tag is discovered if any activities respond to
- * {@link #ACTION_NDEF_DISCOVERED} or {@link #ACTION_TECH_DISCOVERED} for the current tag.
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_TAG_DISCOVERED = "android.nfc.action.TAG_DISCOVERED";
-
- /**
- * Broadcast Action: Intent to notify an application that a transaction event has occurred
- * on the Secure Element.
- *
- * <p>This intent will only be sent if the application has requested permission for
- * {@link android.Manifest.permission#NFC_TRANSACTION_EVENT} and if the application has the
- * necessary access to Secure Element which witnessed the particular event.
- */
- @RequiresPermission(android.Manifest.permission.NFC_TRANSACTION_EVENT)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_TRANSACTION_DETECTED =
- "android.nfc.action.TRANSACTION_DETECTED";
-
- /**
- * Broadcast Action: Intent to notify if the preferred payment service changed.
- *
- * <p>This intent will only be sent to the application has requested permission for
- * {@link android.Manifest.permission#NFC_PREFERRED_PAYMENT_INFO} and if the application
- * has the necessary access to Secure Element which witnessed the particular event.
- */
- @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_PREFERRED_PAYMENT_CHANGED =
- "android.nfc.action.PREFERRED_PAYMENT_CHANGED";
-
- /**
- * Broadcast to only the activity that handles ACTION_TAG_DISCOVERED
- * @hide
- */
- public static final String ACTION_TAG_LEFT_FIELD = "android.nfc.action.TAG_LOST";
-
- /**
- * Mandatory extra containing the {@link Tag} that was discovered for the
- * {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
- * {@link #ACTION_TAG_DISCOVERED} intents.
- */
- public static final String EXTRA_TAG = "android.nfc.extra.TAG";
-
- /**
- * Extra containing an array of {@link NdefMessage} present on the discovered tag.<p>
- * This extra is mandatory for {@link #ACTION_NDEF_DISCOVERED} intents,
- * and optional for {@link #ACTION_TECH_DISCOVERED}, and
- * {@link #ACTION_TAG_DISCOVERED} intents.<p>
- * When this extra is present there will always be at least one
- * {@link NdefMessage} element. Most NDEF tags have only one NDEF message,
- * but we use an array for future compatibility.
- */
- public static final String EXTRA_NDEF_MESSAGES = "android.nfc.extra.NDEF_MESSAGES";
-
- /**
- * Optional extra containing a byte array containing the ID of the discovered tag for
- * the {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED}, and
- * {@link #ACTION_TAG_DISCOVERED} intents.
- */
- public static final String EXTRA_ID = "android.nfc.extra.ID";
-
- /**
- * Broadcast Action: The state of the local NFC adapter has been
- * changed.
- * <p>For example, NFC has been turned on or off.
- * <p>Always contains the extra field {@link #EXTRA_ADAPTER_STATE}
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_ADAPTER_STATE_CHANGED =
- "android.nfc.action.ADAPTER_STATE_CHANGED";
-
- /**
- * Used as an int extra field in {@link #ACTION_ADAPTER_STATE_CHANGED}
- * intents to request the current power state. Possible values are:
- * {@link #STATE_OFF},
- * {@link #STATE_TURNING_ON},
- * {@link #STATE_ON},
- * {@link #STATE_TURNING_OFF},
- */
- public static final String EXTRA_ADAPTER_STATE = "android.nfc.extra.ADAPTER_STATE";
-
- /**
- * Mandatory byte[] extra field in {@link #ACTION_TRANSACTION_DETECTED}
- */
- public static final String EXTRA_AID = "android.nfc.extra.AID";
-
- /**
- * Optional byte[] extra field in {@link #ACTION_TRANSACTION_DETECTED}
- */
- public static final String EXTRA_DATA = "android.nfc.extra.DATA";
-
- /**
- * Mandatory String extra field in {@link #ACTION_TRANSACTION_DETECTED}
- * Indicates the Secure Element on which the transaction occurred.
- * eSE1...eSEn for Embedded Secure Elements, SIM1...SIMn for UICC/EUICC, etc.
- */
- public static final String EXTRA_SECURE_ELEMENT_NAME = "android.nfc.extra.SECURE_ELEMENT_NAME";
-
- /**
- * Mandatory String extra field in {@link #ACTION_PREFERRED_PAYMENT_CHANGED}
- * Indicates the condition when trigger this event. Possible values are:
- * {@link #PREFERRED_PAYMENT_LOADED},
- * {@link #PREFERRED_PAYMENT_CHANGED},
- * {@link #PREFERRED_PAYMENT_UPDATED},
- */
- public static final String EXTRA_PREFERRED_PAYMENT_CHANGED_REASON =
- "android.nfc.extra.PREFERRED_PAYMENT_CHANGED_REASON";
- /**
- * Nfc is enabled and the preferred payment aids are registered.
- */
- public static final int PREFERRED_PAYMENT_LOADED = 1;
- /**
- * User selected another payment application as the preferred payment.
- */
- public static final int PREFERRED_PAYMENT_CHANGED = 2;
- /**
- * Current preferred payment has issued an update (registered/unregistered new aids or has been
- * updated itself).
- */
- public static final int PREFERRED_PAYMENT_UPDATED = 3;
-
- public static final int STATE_OFF = 1;
- public static final int STATE_TURNING_ON = 2;
- public static final int STATE_ON = 3;
- public static final int STATE_TURNING_OFF = 4;
-
- /**
- * Possible states from {@link #getAdapterState}.
- *
- * @hide
- */
- @IntDef(prefix = { "STATE_" }, value = {
- STATE_OFF,
- STATE_TURNING_ON,
- STATE_ON,
- STATE_TURNING_OFF
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AdapterState{}
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag enables polling for Nfc-A technology.
- */
- public static final int FLAG_READER_NFC_A = 0x1;
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag enables polling for Nfc-B technology.
- */
- public static final int FLAG_READER_NFC_B = 0x2;
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag enables polling for Nfc-F technology.
- */
- public static final int FLAG_READER_NFC_F = 0x4;
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag enables polling for Nfc-V (ISO15693) technology.
- */
- public static final int FLAG_READER_NFC_V = 0x8;
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag enables polling for NfcBarcode technology.
- */
- public static final int FLAG_READER_NFC_BARCODE = 0x10;
-
- /** @hide */
- @IntDef(flag = true, value = {
- FLAG_SET_DEFAULT_TECH,
- FLAG_READER_KEEP,
- FLAG_READER_DISABLE,
- FLAG_READER_NFC_A,
- FLAG_READER_NFC_B,
- FLAG_READER_NFC_F,
- FLAG_READER_NFC_V,
- FLAG_READER_NFC_BARCODE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface PollTechnology {}
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag allows the caller to prevent the
- * platform from performing an NDEF check on the tags it
- * finds.
- */
- public static final int FLAG_READER_SKIP_NDEF_CHECK = 0x80;
-
- /**
- * Flag for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this flag allows the caller to prevent the
- * platform from playing sounds when it discovers a tag.
- */
- public static final int FLAG_READER_NO_PLATFORM_SOUNDS = 0x100;
-
- /**
- * Int Extra for use with {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}.
- * <p>
- * Setting this integer extra allows the calling application to specify
- * the delay that the platform will use for performing presence checks
- * on any discovered tag.
- */
- public static final String EXTRA_READER_PRESENCE_CHECK_DELAY = "presence";
-
- /**
- * Flag for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag enables listening for Nfc-A technology.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_LISTEN_NFC_PASSIVE_A = 0x1;
-
- /**
- * Flag for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag enables listening for Nfc-B technology.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_LISTEN_NFC_PASSIVE_B = 1 << 1;
-
- /**
- * Flag for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag enables listening for Nfc-F technology.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_LISTEN_NFC_PASSIVE_F = 1 << 2;
-
- /**
- * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag disables listening.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_LISTEN_DISABLE = 0x0;
-
- /**
- * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag disables polling.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_READER_DISABLE = 0x0;
-
- /**
- * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag makes listening to keep the current technology configuration.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_LISTEN_KEEP = 0x80000000;
-
- /**
- * Flags for use with {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag makes polling to keep the current technology configuration.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public static final int FLAG_READER_KEEP = 0x80000000;
-
- /** @hide */
- public static final int FLAG_USE_ALL_TECH = 0xff;
-
- /** @hide */
- @IntDef(flag = true, value = {
- FLAG_SET_DEFAULT_TECH,
- FLAG_LISTEN_KEEP,
- FLAG_LISTEN_DISABLE,
- FLAG_LISTEN_NFC_PASSIVE_A,
- FLAG_LISTEN_NFC_PASSIVE_B,
- FLAG_LISTEN_NFC_PASSIVE_F
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ListenTechnology {}
-
- /**
- * Flag used in {@link #setDiscoveryTechnology(Activity, int, int)}.
- * <p>
- * Setting this flag changes the default listen or poll tech.
- * Only available to privileged apps.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH)
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public static final int FLAG_SET_DEFAULT_TECH = 0x40000000;
-
- /**
- * @hide
- * @removed
- */
- @SystemApi
- @UnsupportedAppUsage
- public static final int FLAG_NDEF_PUSH_NO_CONFIRM = 0x1;
-
- /** @hide */
- public static final String ACTION_HANDOVER_TRANSFER_STARTED =
- "android.nfc.action.HANDOVER_TRANSFER_STARTED";
-
- /** @hide */
- public static final String ACTION_HANDOVER_TRANSFER_DONE =
- "android.nfc.action.HANDOVER_TRANSFER_DONE";
-
- /** @hide */
- public static final String EXTRA_HANDOVER_TRANSFER_STATUS =
- "android.nfc.extra.HANDOVER_TRANSFER_STATUS";
-
- /** @hide */
- public static final int HANDOVER_TRANSFER_STATUS_SUCCESS = 0;
- /** @hide */
- public static final int HANDOVER_TRANSFER_STATUS_FAILURE = 1;
-
- /** @hide */
- public static final String EXTRA_HANDOVER_TRANSFER_URI =
- "android.nfc.extra.HANDOVER_TRANSFER_URI";
-
- /**
- * Broadcast Action: Notify possible NFC transaction blocked because device is locked.
- * <p>An external NFC field detected when device locked and SecureNfc enabled.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public static final String ACTION_REQUIRE_UNLOCK_FOR_NFC =
- "android.nfc.action.REQUIRE_UNLOCK_FOR_NFC";
-
- /**
- * Intent action to start a NFC resolver activity in a customized share session with list of
- * {@link ResolveInfo}.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- @RequiresPermission(Manifest.permission.SHOW_CUSTOMIZED_RESOLVER)
- public static final String ACTION_SHOW_NFC_RESOLVER = "android.nfc.action.SHOW_NFC_RESOLVER";
-
- /**
- * "Extras" key for an ArrayList of {@link ResolveInfo} records which are to be shown as the
- * targets in the customized share session.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public static final String EXTRA_RESOLVE_INFOS = "android.nfc.extra.RESOLVE_INFOS";
-
- /**
- * The requested app is correctly added to the Tag intent app preference.
- *
- * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
- * @hide
- */
- @SystemApi
- public static final int TAG_INTENT_APP_PREF_RESULT_SUCCESS = 0;
-
- /**
- * The requested app is not installed on the device.
- *
- * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
- * @hide
- */
- @SystemApi
- public static final int TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND = -1;
-
- /**
- * The NfcService is not available.
- *
- * @see #setTagIntentAppPreferenceForUser(int userId, String pkg, boolean allow)
- * @hide
- */
- @SystemApi
- public static final int TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE = -2;
-
- /**
- * Possible response codes from {@link #setTagIntentAppPreferenceForUser}.
- *
- * @hide
- */
- @IntDef(prefix = { "TAG_INTENT_APP_PREF_RESULT" }, value = {
- TAG_INTENT_APP_PREF_RESULT_SUCCESS,
- TAG_INTENT_APP_PREF_RESULT_PACKAGE_NOT_FOUND,
- TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE})
- @Retention(RetentionPolicy.SOURCE)
- public @interface TagIntentAppPreferenceResult {}
-
- /**
- * Mode Type for {@link NfcOemExtension#setControllerAlwaysOnMode(int)}.
- * @hide
- */
- public static final int CONTROLLER_ALWAYS_ON_MODE_DEFAULT = 1;
-
- /**
- * Mode Type for {@link NfcOemExtension#setControllerAlwaysOnMode(int)}.
- * @hide
- */
- public static final int CONTROLLER_ALWAYS_ON_DISABLE = 0;
-
- // Guarded by sLock
- static boolean sIsInitialized = false;
- static boolean sHasNfcFeature;
- static boolean sHasCeFeature;
- static boolean sHasNfcWlcFeature;
-
- static Object sLock = new Object();
-
- // Final after first constructor, except for
- // attemptDeadServiceRecovery() when NFC crashes - we accept a best effort
- // recovery
- @UnsupportedAppUsage
- static INfcAdapter sService;
- static NfcServiceManager.ServiceRegisterer sServiceRegisterer;
- static INfcTag sTagService;
- static INfcCardEmulation sCardEmulationService;
- static INfcFCardEmulation sNfcFCardEmulationService;
- static IT4tNdefNfcee sNdefNfceeService;
-
- /**
- * The NfcAdapter object for each application context.
- * There is a 1-1 relationship between application context and
- * NfcAdapter object.
- */
- static HashMap<Context, NfcAdapter> sNfcAdapters = new HashMap(); //guard by NfcAdapter.class
-
- /**
- * NfcAdapter used with a null context. This ctor was deprecated but we have
- * to support it for backwards compatibility. New methods that require context
- * might throw when called on the null-context NfcAdapter.
- */
- static NfcAdapter sNullContextNfcAdapter; // protected by NfcAdapter.class
-
- final NfcActivityManager mNfcActivityManager;
- final Context mContext;
- final HashMap<NfcUnlockHandler, INfcUnlockHandler> mNfcUnlockHandlers;
- final Object mLock;
- final NfcOemExtension mNfcOemExtension;
-
- ITagRemovedCallback mTagRemovedListener; // protected by mLock
-
- /**
- * A callback to be invoked when the system finds a tag while the foreground activity is
- * operating in reader mode.
- * <p>Register your {@code ReaderCallback} implementation with {@link
- * NfcAdapter#enableReaderMode} and disable it with {@link
- * NfcAdapter#disableReaderMode}.
- * @see NfcAdapter#enableReaderMode
- */
- public interface ReaderCallback {
- public void onTagDiscovered(Tag tag);
- }
-
- /**
- * A listener to be invoked when NFC controller always on state changes.
- * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link
- * NfcAdapter#registerControllerAlwaysOnListener} and disable it with {@link
- * NfcAdapter#unregisterControllerAlwaysOnListener}.
- * @see #registerControllerAlwaysOnListener
- * @hide
- */
- @SystemApi
- public interface ControllerAlwaysOnListener {
- /**
- * Called on NFC controller always on state changes
- */
- void onControllerAlwaysOnChanged(boolean isEnabled);
- }
-
- /**
- * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
- * to another device.
- * @deprecated this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- public interface OnNdefPushCompleteCallback {
- /**
- * Called on successful NDEF push.
- *
- * <p>This callback is usually made on a binder thread (not the UI thread).
- *
- * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
- */
- public void onNdefPushComplete(NfcEvent event);
- }
-
- /**
- * A callback to be invoked when another NFC device capable of NDEF push (Android Beam)
- * is within range.
- * <p>Implement this interface and pass it to {@code
- * NfcAdapter#setNdefPushMessageCallback setNdefPushMessageCallback()} in order to create an
- * {@link NdefMessage} at the moment that another device is within range for NFC. Using this
- * callback allows you to create a message with data that might vary based on the
- * content currently visible to the user. Alternatively, you can call {@code
- * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
- * same data.
- * @deprecated this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- public interface CreateNdefMessageCallback {
- /**
- * Called to provide a {@link NdefMessage} to push.
- *
- * <p>This callback is usually made on a binder thread (not the UI thread).
- *
- * <p>Called when this device is in range of another device
- * that might support NDEF push. It allows the application to
- * create the NDEF message only when it is required.
- *
- * <p>NDEF push cannot occur until this method returns, so do not
- * block for too long.
- *
- * <p>The Android operating system will usually show a system UI
- * on top of your activity during this time, so do not try to request
- * input from the user to complete the callback, or provide custom NDEF
- * push UI. The user probably will not see it.
- *
- * @param event {@link NfcEvent} with the {@link NfcEvent#nfcAdapter} field set
- * @return NDEF message to push, or null to not provide a message
- */
- public NdefMessage createNdefMessage(NfcEvent event);
- }
-
-
- /**
- * @deprecated this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- public interface CreateBeamUrisCallback {
- public Uri[] createBeamUris(NfcEvent event);
- }
-
- /**
- * A callback that is invoked when a tag is removed from the field.
- * @see NfcAdapter#ignore
- */
- public interface OnTagRemovedListener {
- void onTagRemoved();
- }
-
- /**
- * A callback to be invoked when an application has registered as a
- * handler to unlock the device given an NFC tag at the lockscreen.
- * @hide
- */
- @SystemApi
- public interface NfcUnlockHandler {
- /**
- * Called at the lock screen to attempt to unlock the device with the given tag.
- * @param tag the detected tag, to be used to unlock the device
- * @return true if the device was successfully unlocked
- */
- public boolean onUnlockAttempted(Tag tag);
- }
-
- /**
- * Return list of Secure Elements which support off host card emulation.
- *
- * @return List<String> containing secure elements on the device which supports
- * off host card emulation. eSE for Embedded secure element,
- * SIM for UICC/EUICC and so on.
- * @hide
- */
- public @NonNull List<String> getSupportedOffHostSecureElements() {
- if (mContext == null) {
- throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
- + " getSupportedOffHostSecureElements APIs");
- }
- List<String> offHostSE = new ArrayList<String>();
- PackageManager pm = mContext.getPackageManager();
- if (pm == null) {
- Log.e(TAG, "Cannot get package manager, assuming no off-host CE feature");
- return offHostSE;
- }
- if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)) {
- offHostSE.add("SIM");
- }
- if (pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE)) {
- offHostSE.add("eSE");
- }
- return offHostSE;
- }
-
- private static void retrieveServiceRegisterer() {
- if (sServiceRegisterer == null) {
- NfcServiceManager manager = NfcFrameworkInitializer.getNfcServiceManager();
- if (manager == null) {
- Log.e(TAG, "NfcServiceManager is null");
- throw new UnsupportedOperationException();
- }
- sServiceRegisterer = manager.getNfcManagerServiceRegisterer();
- }
- }
-
- /**
- * Returns the NfcAdapter for application context,
- * or throws if NFC is not available.
- * @hide
- */
- @UnsupportedAppUsage
- public static synchronized NfcAdapter getNfcAdapter(Context context) {
- if (context == null) {
- if (sNullContextNfcAdapter == null) {
- sNullContextNfcAdapter = new NfcAdapter(null);
- }
- return sNullContextNfcAdapter;
- }
- if (!sIsInitialized) {
- PackageManager pm;
- pm = context.getPackageManager();
- sHasNfcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC);
- sHasCeFeature =
- pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
- || pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)
- || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)
- || pm.hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE);
- sHasNfcWlcFeature = pm.hasSystemFeature(PackageManager.FEATURE_NFC_CHARGING);
- /* is this device meant to have NFC */
- if (!sHasNfcFeature && !sHasCeFeature && !sHasNfcWlcFeature) {
- Log.v(TAG, "this device does not have NFC support");
- throw new UnsupportedOperationException();
- }
- retrieveServiceRegisterer();
- sService = getServiceInterface();
- if (sService == null) {
- Log.e(TAG, "could not retrieve NFC service");
- throw new UnsupportedOperationException();
- }
- if (sHasNfcFeature) {
- try {
- sTagService = sService.getNfcTagInterface();
- } catch (RemoteException e) {
- sTagService = null;
- Log.e(TAG, "could not retrieve NFC Tag service");
- throw new UnsupportedOperationException();
- }
- }
- if (sHasCeFeature) {
- try {
- sNfcFCardEmulationService = sService.getNfcFCardEmulationInterface();
- } catch (RemoteException e) {
- sNfcFCardEmulationService = null;
- Log.e(TAG, "could not retrieve NFC-F card emulation service");
- throw new UnsupportedOperationException();
- }
- try {
- sCardEmulationService = sService.getNfcCardEmulationInterface();
- } catch (RemoteException e) {
- sCardEmulationService = null;
- Log.e(TAG, "could not retrieve card emulation service");
- throw new UnsupportedOperationException();
- }
- }
- try {
- sNdefNfceeService = sService.getT4tNdefNfceeInterface();
- } catch (RemoteException e) {
- sNdefNfceeService = null;
- Log.e(TAG, "could not retrieve NDEF NFCEE service");
- throw new UnsupportedOperationException();
- }
- sIsInitialized = true;
- }
- NfcAdapter adapter = sNfcAdapters.get(context);
- if (adapter == null) {
- adapter = new NfcAdapter(context);
- sNfcAdapters.put(context, adapter);
- }
- return adapter;
- }
-
- /** get handle to NFC service interface */
- private static INfcAdapter getServiceInterface() {
- /* get a handle to NFC service */
- IBinder b = sServiceRegisterer.get();
- if (b == null) {
- return null;
- }
- return INfcAdapter.Stub.asInterface(b);
- }
-
- /**
- * Helper to get the default NFC Adapter.
- * <p>
- * Most Android devices will only have one NFC Adapter (NFC Controller).
- * <p>
- * This helper is the equivalent of:
- * <pre>
- * NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
- * NfcAdapter adapter = manager.getDefaultAdapter();</pre>
- * @param context the calling application's context
- *
- * @return the default NFC adapter, or null if no NFC adapter exists
- */
- public static NfcAdapter getDefaultAdapter(Context context) {
- if (context == null) {
- throw new IllegalArgumentException("context cannot be null");
- }
- context = context.getApplicationContext();
- if (context == null) {
- throw new IllegalArgumentException(
- "context not associated with any application (using a mock context?)");
- }
- retrieveServiceRegisterer();
- if (sServiceRegisterer.tryGet() == null) {
- if (sIsInitialized) {
- synchronized (NfcAdapter.class) {
- /* Stale sService pointer */
- if (sIsInitialized) sIsInitialized = false;
- }
- }
- return null;
- }
- /* Try to initialize the service */
- NfcManager manager = (NfcManager) context.getSystemService(Context.NFC_SERVICE);
- if (manager == null) {
- // NFC not available
- return null;
- }
- return manager.getDefaultAdapter();
- }
-
- /**
- * Legacy NfcAdapter getter, always use {@link #getDefaultAdapter(Context)} instead.<p>
- * This method was deprecated at API level 10 (Gingerbread MR1) because a context is required
- * for many NFC API methods. Those methods will fail when called on an NfcAdapter
- * object created from this method.<p>
- * @deprecated use {@link #getDefaultAdapter(Context)}
- * @hide
- */
- @Deprecated
- @UnsupportedAppUsage
- public static NfcAdapter getDefaultAdapter() {
- // introduced in API version 9 (GB 2.3)
- // deprecated in API version 10 (GB 2.3.3)
- // removed from public API in version 16 (ICS MR2)
- // should maintain as a hidden API for binary compatibility for a little longer
- Log.w(TAG, "WARNING: NfcAdapter.getDefaultAdapter() is deprecated, use " +
- "NfcAdapter.getDefaultAdapter(Context) instead", new Exception());
-
- return NfcAdapter.getNfcAdapter(null);
- }
-
- NfcAdapter(Context context) {
- mContext = context;
- mNfcActivityManager = new NfcActivityManager(this);
- mNfcUnlockHandlers = new HashMap<NfcUnlockHandler, INfcUnlockHandler>();
- mTagRemovedListener = null;
- mLock = new Object();
- mControllerAlwaysOnListener = new NfcControllerAlwaysOnListener(getService());
- mNfcWlcStateListener = new NfcWlcStateListener(getService());
- mNfcVendorNciCallbackListener = new NfcVendorNciCallbackListener(getService());
- mNfcOemExtension = new NfcOemExtension(mContext, this);
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage
- public Context getContext() {
- return mContext;
- }
-
- /**
- * Returns the binder interface to the service.
- * @hide
- */
- @UnsupportedAppUsage
- public static INfcAdapter getService() {
- isEnabledStatic(); // NOP call to recover sService if it is stale
- return sService;
- }
-
- /**
- * Returns the binder interface to the tag service.
- * @hide
- */
- public static INfcTag getTagService() {
- isEnabledStatic(); // NOP call to recover sTagService if it is stale
- return sTagService;
- }
-
- /**
- * Returns the binder interface to the card emulation service.
- * @hide
- */
- public static INfcCardEmulation getCardEmulationService() {
- isEnabledStatic();
- return sCardEmulationService;
- }
-
- /**
- * Returns the binder interface to the NFC-F card emulation service.
- * @hide
- */
- public static INfcFCardEmulation getNfcFCardEmulationService() {
- isEnabledStatic();
- return sNfcFCardEmulationService;
- }
-
- /**
- * Returns the binder interface to the NFC-DTA test interface.
- * @hide
- */
- public INfcDta getNfcDtaInterface() {
- if (mContext == null) {
- throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
- + " NFC extras APIs");
- }
- return callServiceReturn(() -> sService.getNfcDtaInterface(mContext.getPackageName()),
- null);
-
- }
-
- /**
- * NFC service dead - attempt best effort recovery
- * @hide
- */
- @UnsupportedAppUsage
- public static void attemptDeadServiceRecovery(RemoteException e) {
- Log.e(TAG, "NFC service dead - attempting to recover", e);
- INfcAdapter service = getServiceInterface();
- if (service == null) {
- Log.e(TAG, "could not retrieve NFC service during service recovery");
- // nothing more can be done now, sService is still stale, we'll hit
- // this recovery path again later
- e.rethrowAsRuntimeException();
- }
- // assigning to sService is not thread-safe, but this is best-effort code
- // and on a well-behaved system should never happen
- sService = service;
- if (sHasNfcFeature) {
- try {
- sTagService = service.getNfcTagInterface();
- } catch (RemoteException ee) {
- sTagService = null;
- Log.e(TAG, "could not retrieve NFC tag service during service recovery");
- // nothing more can be done now, sService is still stale, we'll hit
- // this recovery path again later
- ee.rethrowAsRuntimeException();
- }
- }
-
- if (sHasCeFeature) {
- try {
- sCardEmulationService = service.getNfcCardEmulationInterface();
- } catch (RemoteException ee) {
- sCardEmulationService = null;
- Log.e(TAG,
- "could not retrieve NFC card emulation service during service recovery");
- }
-
- try {
- sNfcFCardEmulationService = service.getNfcFCardEmulationInterface();
- } catch (RemoteException ee) {
- sNfcFCardEmulationService = null;
- Log.e(TAG,
- "could not retrieve NFC-F card emulation service during service recovery");
- }
- }
- }
-
- private static boolean isCardEmulationEnabled() {
- if (sHasCeFeature) {
- return (sCardEmulationService != null || sNfcFCardEmulationService != null);
- }
- return false;
- }
-
- private static boolean isTagReadingEnabled() {
- if (sHasNfcFeature) {
- return sTagService != null;
- }
- return false;
- }
-
- private static boolean isEnabledStatic() {
- boolean serviceState = callServiceReturn(() -> sService.getState() == STATE_ON, false);
- return serviceState
- && (isTagReadingEnabled() || isCardEmulationEnabled() || sHasNfcWlcFeature);
- }
-
- /**
- * Return true if this NFC Adapter has any features enabled.
- *
- * <p>If this method returns false, the NFC hardware is guaranteed not to
- * generate or respond to any NFC communication over its NFC radio.
- * <p>Applications can use this to check if NFC is enabled. Applications
- * can request Settings UI allowing the user to toggle NFC using:
- * <p><pre>startActivity(new Intent(Settings.ACTION_NFC_SETTINGS))</pre>
- *
- * @see android.provider.Settings#ACTION_NFC_SETTINGS
- * @return true if this NFC Adapter has any features enabled
- */
- public boolean isEnabled() {
- return isEnabledStatic();
- }
-
- /**
- * Return the state of this NFC Adapter.
- *
- * <p>Returns one of {@link #STATE_ON}, {@link #STATE_TURNING_ON},
- * {@link #STATE_OFF}, {@link #STATE_TURNING_OFF}.
- *
- * <p>{@link #isEnabled()} is equivalent to
- * <code>{@link #getAdapterState()} == {@link #STATE_ON}</code>
- *
- * @return the current state of this NFC adapter
- *
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- public @AdapterState int getAdapterState() {
- return callServiceReturn(() -> sService.getState(), NfcAdapter.STATE_OFF);
-
- }
-
- /**
- * Enable NFC hardware.
- *
- * <p>This call is asynchronous. Listen for
- * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
- * operation is complete.
- *
- * <p>This API is only allowed to be called by system apps
- * or apps which are Device Owner or Profile Owner.
- *
- * <p>If this returns true, then either NFC is already on, or
- * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
- * to indicate a state transition. If this returns false, then
- * there is some problem that prevents an attempt to turn
- * NFC on (for example we are in airplane mode and NFC is not
- * toggleable in airplane mode on this platform).
- *
- */
- @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean enable() {
- return callServiceReturn(() -> sService.enable(mContext.getPackageName()), false);
-
- }
-
- /**
- * Disable NFC hardware.
- *
- * <p>No NFC features will work after this call, and the hardware
- * will not perform or respond to any NFC communication.
- *
- * <p>This call is asynchronous. Listen for
- * {@link #ACTION_ADAPTER_STATE_CHANGED} broadcasts to find out when the
- * operation is complete.
- *
- * <p>This API is only allowed to be called by system apps
- * or apps which are Device Owner or Profile Owner.
- *
- * <p>If this returns true, then either NFC is already off, or
- * a {@link #ACTION_ADAPTER_STATE_CHANGED} broadcast will be sent
- * to indicate a state transition. If this returns false, then
- * there is some problem that prevents an attempt to turn
- * NFC off.
- *
- */
- @FlaggedApi(Flags.FLAG_NFC_STATE_CHANGE)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean disable() {
- return callServiceReturn(() -> sService.disable(true, mContext.getPackageName()),
- false);
-
- }
-
- /**
- * Disable NFC hardware.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean disable(boolean persist) {
- return callServiceReturn(() -> sService.disable(persist, mContext.getPackageName()),
- false);
-
- }
-
- /**
- * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
- * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely
- * use {@link #resumePolling() to resume the polling.
- * @hide
- */
- public void pausePolling(int timeoutInMs) {
- callService(() -> sService.pausePolling(timeoutInMs));
- }
-
-
- /**
- * Returns whether the device supports observe mode or not. When observe mode is enabled, the
- * NFC hardware will listen to NFC readers, but not respond to them. While enabled, observed
- * polling frames will be sent to the APDU service (see {@link #setObserveModeEnabled(boolean)}.
- * When observe mode is disabled (or if it's not supported), the NFC hardware will automatically
- * respond to the reader and proceed with the transaction.
- * @return true if the mode is supported, false otherwise.
- */
- @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
- public boolean isObserveModeSupported() {
- return callServiceReturn(() -> sService.isObserveModeSupported(), false);
- }
-
- /**
- * Returns whether Observe Mode is currently enabled or not.
- *
- * @return true if observe mode is enabled, false otherwise.
- */
-
- @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
- public boolean isObserveModeEnabled() {
- return callServiceReturn(() -> sService.isObserveModeEnabled(), false);
- }
-
- /**
- * Controls whether the NFC adapter will allow transactions to proceed or be in observe mode
- * and simply observe and notify the APDU service of polling loop frames. See
- * {@link #isObserveModeSupported()} for a description of observe mode. Only the package of the
- * currently preferred service (the service set as preferred by the current foreground
- * application via {@link android.nfc.cardemulation.CardEmulation#setPreferredService(Activity,
- * android.content.ComponentName)} or the current Default Wallet Role Holder
- * {@link android.app.role.RoleManager#ROLE_WALLET}), otherwise a call to this method will fail
- * and return false.
- *
- * @param enabled false disables observe mode to allow the transaction to proceed while true
- * enables observe mode and does not allow transactions to proceed.
- *
- * @return boolean indicating success or failure.
- */
-
- @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
- public boolean setObserveModeEnabled(boolean enabled) {
- if (mContext == null) {
- throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
- + " observe mode APIs");
- }
- return callServiceReturn(() -> sService.setObserveMode(enabled, mContext.getPackageName()),
- false);
- }
-
- /**
- * Resumes default NFC tag reader mode polling for the current device state if polling is
- * paused. Calling this while already in polling is a no-op.
- * @hide
- */
- public void resumePolling() {
- callService(() -> sService.resumePolling());
- }
-
- /**
- * Set one or more {@link Uri}s to send using Android Beam (TM). Every
- * Uri you provide must have either scheme 'file' or scheme 'content'.
- *
- * <p>For the data provided through this method, Android Beam tries to
- * switch to alternate transports such as Bluetooth to achieve a fast
- * transfer speed. Hence this method is very suitable
- * for transferring large files such as pictures or songs.
- *
- * <p>The receiving side will store the content of each Uri in
- * a file and present a notification to the user to open the file
- * with a {@link android.content.Intent} with action
- * {@link android.content.Intent#ACTION_VIEW}.
- * If multiple URIs are sent, the {@link android.content.Intent} will refer
- * to the first of the stored files.
- *
- * <p>This method may be called at any time before {@link Activity#onDestroy},
- * but the URI(s) are only made available for Android Beam when the
- * specified activity(s) are in resumed (foreground) state. The recommended
- * approach is to call this method during your Activity's
- * {@link Activity#onCreate} - see sample
- * code below. This method does not immediately perform any I/O or blocking work,
- * so is safe to call on your main thread.
- *
- * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
- * have priority over both {@link #setNdefPushMessage} and
- * {@link #setNdefPushMessageCallback}.
- *
- * <p>If {@link #setBeamPushUris} is called with a null Uri array,
- * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
- * then the Uri push will be completely disabled for the specified activity(s).
- *
- * <p>Code example:
- * <pre>
- * protected void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState);
- * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
- * if (nfcAdapter == null) return; // NFC not available on this device
- * nfcAdapter.setBeamPushUris(new Uri[] {uri1, uri2}, this);
- * }</pre>
- * And that is it. Only one call per activity is necessary. The Android
- * OS will automatically release its references to the Uri(s) and the
- * Activity object when it is destroyed if you follow this pattern.
- *
- * <p>If your Activity wants to dynamically supply Uri(s),
- * then set a callback using {@link #setBeamPushUrisCallback} instead
- * of using this method.
- *
- * <p class="note">Do not pass in an Activity that has already been through
- * {@link Activity#onDestroy}. This is guaranteed if you call this API
- * during {@link Activity#onCreate}.
- *
- * <p class="note">If this device does not support alternate transports
- * such as Bluetooth or WiFI, calling this method does nothing.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param uris an array of Uri(s) to push over Android Beam
- * @param activity activity for which the Uri(s) will be pushed
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public void setBeamPushUris(Uri[] uris, Activity activity) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Set a callback that will dynamically generate one or more {@link Uri}s
- * to send using Android Beam (TM). Every Uri the callback provides
- * must have either scheme 'file' or scheme 'content'.
- *
- * <p>For the data provided through this callback, Android Beam tries to
- * switch to alternate transports such as Bluetooth to achieve a fast
- * transfer speed. Hence this method is very suitable
- * for transferring large files such as pictures or songs.
- *
- * <p>The receiving side will store the content of each Uri in
- * a file and present a notification to the user to open the file
- * with a {@link android.content.Intent} with action
- * {@link android.content.Intent#ACTION_VIEW}.
- * If multiple URIs are sent, the {@link android.content.Intent} will refer
- * to the first of the stored files.
- *
- * <p>This method may be called at any time before {@link Activity#onDestroy},
- * but the URI(s) are only made available for Android Beam when the
- * specified activity(s) are in resumed (foreground) state. The recommended
- * approach is to call this method during your Activity's
- * {@link Activity#onCreate} - see sample
- * code below. This method does not immediately perform any I/O or blocking work,
- * so is safe to call on your main thread.
- *
- * <p>{@link #setBeamPushUris} and {@link #setBeamPushUrisCallback}
- * have priority over both {@link #setNdefPushMessage} and
- * {@link #setNdefPushMessageCallback}.
- *
- * <p>If {@link #setBeamPushUris} is called with a null Uri array,
- * and/or {@link #setBeamPushUrisCallback} is called with a null callback,
- * then the Uri push will be completely disabled for the specified activity(s).
- *
- * <p>Code example:
- * <pre>
- * protected void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState);
- * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
- * if (nfcAdapter == null) return; // NFC not available on this device
- * nfcAdapter.setBeamPushUrisCallback(callback, this);
- * }</pre>
- * And that is it. Only one call per activity is necessary. The Android
- * OS will automatically release its references to the Uri(s) and the
- * Activity object when it is destroyed if you follow this pattern.
- *
- * <p class="note">Do not pass in an Activity that has already been through
- * {@link Activity#onDestroy}. This is guaranteed if you call this API
- * during {@link Activity#onCreate}.
- *
- * <p class="note">If this device does not support alternate transports
- * such as Bluetooth or WiFI, calling this method does nothing.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param callback callback, or null to disable
- * @param activity activity for which the Uri(s) will be pushed
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Set a static {@link NdefMessage} to send using Android Beam (TM).
- *
- * <p>This method may be called at any time before {@link Activity#onDestroy},
- * but the NDEF message is only made available for NDEF push when the
- * specified activity(s) are in resumed (foreground) state. The recommended
- * approach is to call this method during your Activity's
- * {@link Activity#onCreate} - see sample
- * code below. This method does not immediately perform any I/O or blocking work,
- * so is safe to call on your main thread.
- *
- * <p>Only one NDEF message can be pushed by the currently resumed activity.
- * If both {@link #setNdefPushMessage} and
- * {@link #setNdefPushMessageCallback} are set, then
- * the callback will take priority.
- *
- * <p>If neither {@link #setNdefPushMessage} or
- * {@link #setNdefPushMessageCallback} have been called for your activity, then
- * the Android OS may choose to send a default NDEF message on your behalf,
- * such as a URI for your application.
- *
- * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
- * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
- * then NDEF push will be completely disabled for the specified activity(s).
- * This also disables any default NDEF message the Android OS would have
- * otherwise sent on your behalf for those activity(s).
- *
- * <p>If you want to prevent the Android OS from sending default NDEF
- * messages completely (for all activities), you can include a
- * {@code <meta-data>} element inside the {@code <application>}
- * element of your AndroidManifest.xml file, like this:
- * <pre>
- * &lt;application ...>
- * &lt;meta-data android:name="android.nfc.disable_beam_default"
- * android:value="true" />
- * &lt;/application></pre>
- *
- * <p>The API allows for multiple activities to be specified at a time,
- * but it is strongly recommended to just register one at a time,
- * and to do so during the activity's {@link Activity#onCreate}. For example:
- * <pre>
- * protected void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState);
- * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
- * if (nfcAdapter == null) return; // NFC not available on this device
- * nfcAdapter.setNdefPushMessage(ndefMessage, this);
- * }</pre>
- * And that is it. Only one call per activity is necessary. The Android
- * OS will automatically release its references to the NDEF message and the
- * Activity object when it is destroyed if you follow this pattern.
- *
- * <p>If your Activity wants to dynamically generate an NDEF message,
- * then set a callback using {@link #setNdefPushMessageCallback} instead
- * of a static message.
- *
- * <p class="note">Do not pass in an Activity that has already been through
- * {@link Activity#onDestroy}. This is guaranteed if you call this API
- * during {@link Activity#onCreate}.
- *
- * <p class="note">For sending large content such as pictures and songs,
- * consider using {@link #setBeamPushUris}, which switches to alternate transports
- * such as Bluetooth to achieve a fast transfer rate.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param message NDEF message to push over NFC, or null to disable
- * @param activity activity for which the NDEF message will be pushed
- * @param activities optional additional activities, however we strongly recommend
- * to only register one at a time, and to do so in that activity's
- * {@link Activity#onCreate}
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public void setNdefPushMessage(NdefMessage message, Activity activity,
- Activity ... activities) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * @hide
- * @removed
- */
- @SystemApi
- @UnsupportedAppUsage
- public void setNdefPushMessage(NdefMessage message, Activity activity, int flags) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Set a callback that dynamically generates NDEF messages to send using Android Beam (TM).
- *
- * <p>This method may be called at any time before {@link Activity#onDestroy},
- * but the NDEF message callback can only occur when the
- * specified activity(s) are in resumed (foreground) state. The recommended
- * approach is to call this method during your Activity's
- * {@link Activity#onCreate} - see sample
- * code below. This method does not immediately perform any I/O or blocking work,
- * so is safe to call on your main thread.
- *
- * <p>Only one NDEF message can be pushed by the currently resumed activity.
- * If both {@link #setNdefPushMessage} and
- * {@link #setNdefPushMessageCallback} are set, then
- * the callback will take priority.
- *
- * <p>If neither {@link #setNdefPushMessage} or
- * {@link #setNdefPushMessageCallback} have been called for your activity, then
- * the Android OS may choose to send a default NDEF message on your behalf,
- * such as a URI for your application.
- *
- * <p>If {@link #setNdefPushMessage} is called with a null NDEF message,
- * and/or {@link #setNdefPushMessageCallback} is called with a null callback,
- * then NDEF push will be completely disabled for the specified activity(s).
- * This also disables any default NDEF message the Android OS would have
- * otherwise sent on your behalf for those activity(s).
- *
- * <p>If you want to prevent the Android OS from sending default NDEF
- * messages completely (for all activities), you can include a
- * {@code <meta-data>} element inside the {@code <application>}
- * element of your AndroidManifest.xml file, like this:
- * <pre>
- * &lt;application ...>
- * &lt;meta-data android:name="android.nfc.disable_beam_default"
- * android:value="true" />
- * &lt;/application></pre>
- *
- * <p>The API allows for multiple activities to be specified at a time,
- * but it is strongly recommended to just register one at a time,
- * and to do so during the activity's {@link Activity#onCreate}. For example:
- * <pre>
- * protected void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState);
- * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
- * if (nfcAdapter == null) return; // NFC not available on this device
- * nfcAdapter.setNdefPushMessageCallback(callback, this);
- * }</pre>
- * And that is it. Only one call per activity is necessary. The Android
- * OS will automatically release its references to the callback and the
- * Activity object when it is destroyed if you follow this pattern.
- *
- * <p class="note">Do not pass in an Activity that has already been through
- * {@link Activity#onDestroy}. This is guaranteed if you call this API
- * during {@link Activity#onCreate}.
- * <p class="note">For sending large content such as pictures and songs,
- * consider using {@link #setBeamPushUris}, which switches to alternate transports
- * such as Bluetooth to achieve a fast transfer rate.
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param callback callback, or null to disable
- * @param activity activity for which the NDEF message will be pushed
- * @param activities optional additional activities, however we strongly recommend
- * to only register one at a time, and to do so in that activity's
- * {@link Activity#onCreate}
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
- Activity ... activities) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Set a callback on successful Android Beam (TM).
- *
- * <p>This method may be called at any time before {@link Activity#onDestroy},
- * but the callback can only occur when the
- * specified activity(s) are in resumed (foreground) state. The recommended
- * approach is to call this method during your Activity's
- * {@link Activity#onCreate} - see sample
- * code below. This method does not immediately perform any I/O or blocking work,
- * so is safe to call on your main thread.
- *
- * <p>The API allows for multiple activities to be specified at a time,
- * but it is strongly recommended to just register one at a time,
- * and to do so during the activity's {@link Activity#onCreate}. For example:
- * <pre>
- * protected void onCreate(Bundle savedInstanceState) {
- * super.onCreate(savedInstanceState);
- * NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
- * if (nfcAdapter == null) return; // NFC not available on this device
- * nfcAdapter.setOnNdefPushCompleteCallback(callback, this);
- * }</pre>
- * And that is it. Only one call per activity is necessary. The Android
- * OS will automatically release its references to the callback and the
- * Activity object when it is destroyed if you follow this pattern.
- *
- * <p class="note">Do not pass in an Activity that has already been through
- * {@link Activity#onDestroy}. This is guaranteed if you call this API
- * during {@link Activity#onCreate}.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param callback callback, or null to disable
- * @param activity activity for which the NDEF message will be pushed
- * @param activities optional additional activities, however we strongly recommend
- * to only register one at a time, and to do so in that activity's
- * {@link Activity#onCreate}
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
- Activity activity, Activity ... activities) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Enable foreground dispatch to the given Activity.
- *
- * <p>This will give priority to the foreground activity when
- * dispatching a discovered {@link Tag} to an application.
- *
- * <p>If any IntentFilters are provided to this method they are used to match dispatch Intents
- * for both the {@link NfcAdapter#ACTION_NDEF_DISCOVERED} and
- * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. Since {@link NfcAdapter#ACTION_TECH_DISCOVERED}
- * relies on meta data outside of the IntentFilter matching for that dispatch Intent is handled
- * by passing in the tech lists separately. Each first level entry in the tech list represents
- * an array of technologies that must all be present to match. If any of the first level sets
- * match then the dispatch is routed through the given PendingIntent. In other words, the second
- * level is ANDed together and the first level entries are ORed together.
- *
- * <p>If you pass {@code null} for both the {@code filters} and {@code techLists} parameters
- * that acts a wild card and will cause the foreground activity to receive all tags via the
- * {@link NfcAdapter#ACTION_TAG_DISCOVERED} intent.
- *
- * <p>This method must be called from the main thread, and only when the activity is in the
- * foreground (resumed). Also, activities must call {@link #disableForegroundDispatch} before
- * the completion of their {@link Activity#onPause} callback to disable foreground dispatch
- * after it has been enabled.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param activity the Activity to dispatch to
- * @param intent the PendingIntent to start for the dispatch
- * @param filters the IntentFilters to override dispatching for, or null to always dispatch
- * @param techLists the tech lists used to perform matching for dispatching of the
- * {@link NfcAdapter#ACTION_TECH_DISCOVERED} intent
- * @throws IllegalStateException if the Activity is not currently in the foreground
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- */
- public void enableForegroundDispatch(Activity activity, PendingIntent intent,
- IntentFilter[] filters, String[][] techLists) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- if (activity == null || intent == null) {
- throw new NullPointerException();
- }
- final TechListParcel parcel = (techLists != null && techLists.length > 0)
- ? new TechListParcel(techLists)
- : null;
- callService(() -> sService.setForegroundDispatch(intent, filters, parcel));
- }
-
- /**
- * Disable foreground dispatch to the given activity.
- *
- * <p>After calling {@link #enableForegroundDispatch}, an activity
- * must call this method before its {@link Activity#onPause} callback
- * completes.
- *
- * <p>This method must be called from the main thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param activity the Activity to disable dispatch to
- * @throws IllegalStateException if the Activity has already been paused
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- */
- public void disableForegroundDispatch(Activity activity) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- callService(() -> sService.setForegroundDispatch(null, null, null));
- }
-
- /**
- * Limit the NFC controller to reader mode while this Activity is in the foreground.
- *
- * <p>In this mode the NFC controller will only act as an NFC tag reader/writer,
- * thus disabling any peer-to-peer (Android Beam) and card-emulation modes of
- * the NFC adapter on this device.
- *
- * <p>Use {@link #FLAG_READER_SKIP_NDEF_CHECK} to prevent the platform from
- * performing any NDEF checks in reader mode. Note that this will prevent the
- * {@link Ndef} tag technology from being enumerated on the tag, and that
- * NDEF-based tag dispatch will not be functional.
- *
- * <p>For interacting with tags that are emulated on another Android device
- * using Android's host-based card-emulation, the recommended flags are
- * {@link #FLAG_READER_NFC_A} and {@link #FLAG_READER_SKIP_NDEF_CHECK}.
- *
- * @param activity the Activity that requests the adapter to be in reader mode
- * @param callback the callback to be called when a tag is discovered
- * @param flags Flags indicating poll technologies and other optional parameters
- * @param extras Additional extras for configuring reader mode.
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- */
- public void enableReaderMode(Activity activity, ReaderCallback callback, int flags,
- Bundle extras) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- mNfcActivityManager.enableReaderMode(activity, callback, flags, extras);
- }
-
- /**
- * Restore the NFC adapter to normal mode of operation: supporting
- * peer-to-peer (Android Beam), card emulation, and polling for
- * all supported tag technologies.
- *
- * @param activity the Activity that currently has reader mode enabled
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- */
- public void disableReaderMode(Activity activity) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- mNfcActivityManager.disableReaderMode(activity);
- }
-
- // Flags arguments to NFC adapter to enable/disable NFC
- private static final int DISABLE_POLLING_FLAGS = 0x1000;
- private static final int ENABLE_POLLING_FLAGS = 0x0000;
-
- /**
- * Privileged API to enable or disable reader polling.
- * Unlike {@link #enableReaderMode(Activity, ReaderCallback, int, Bundle)}, this API does not
- * need a foreground activity to control reader mode parameters
- * Note: Use with caution! The app is responsible for ensuring that the polling state is
- * returned to normal.
- *
- * @see #enableReaderMode(Activity, ReaderCallback, int, Bundle) for more detailed
- * documentation.
- *
- * @param enablePolling whether to enable or disable polling.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- @SuppressLint("VisiblySynchronized")
- public void setReaderModePollingEnabled(boolean enable) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- Binder token = new Binder();
- int flags = enable ? ENABLE_POLLING_FLAGS : DISABLE_POLLING_FLAGS;
- callService(() -> sService.setReaderMode(
- token, null, flags, null, mContext.getPackageName()));
- }
-
- /**
- * Set the NFC controller to enable specific poll/listen technologies,
- * as specified in parameters, while this Activity is in the foreground.
- *
- * Use {@link #FLAG_READER_KEEP} to keep current polling technology.
- * Use {@link #FLAG_LISTEN_KEEP} to keep current listenig technology.
- * (if the _KEEP flag is specified the other technology flags shouldn't be set
- * and are quietly ignored otherwise).
- * Use {@link #FLAG_READER_DISABLE} to disable polling.
- * Use {@link #FLAG_LISTEN_DISABLE} to disable listening.
- * Also refer to {@link #resetDiscoveryTechnology(Activity)} to restore these changes.
- * </p>
- * The pollTechnology, listenTechnology parameters can be one or several of below list.
- * <pre>
- * Poll Listen
- * Passive A 0x01 (NFC_A) 0x01 (NFC_PASSIVE_A)
- * Passive B 0x02 (NFC_B) 0x02 (NFC_PASSIVE_B)
- * Passive F 0x04 (NFC_F) 0x04 (NFC_PASSIVE_F)
- * ISO 15693 0x08 (NFC_V) -
- * Kovio 0x10 (NFC_BARCODE) -
- * </pre>
- * <p>Example usage in an Activity that requires to disable poll,
- * keep current listen technologies:
- * <pre>
- * protected void onResume() {
- * mNfcAdapter = NfcAdapter.getDefaultAdapter(getApplicationContext());
- * mNfcAdapter.setDiscoveryTechnology(this,
- * NfcAdapter.FLAG_READER_DISABLE, NfcAdapter.FLAG_LISTEN_KEEP);
- * }</pre></p>
- * @param activity The Activity that requests NFC controller to enable specific technologies.
- * @param pollTechnology Flags indicating poll technologies.
- * @param listenTechnology Flags indicating listen technologies.
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF are unavailable.
- *
- * NOTE: This API overrides all technology flags regardless of the current device state,
- * it is incompatible with enableReaderMode() API and the others that either update
- * or assume any techlology flag set by the OS.
- * Please use with care.
- */
-
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public void setDiscoveryTechnology(@NonNull Activity activity,
- @PollTechnology int pollTechnology, @ListenTechnology int listenTechnology) {
-
- if (listenTechnology == FLAG_LISTEN_DISABLE) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- } else if (pollTechnology == FLAG_READER_DISABLE) {
- synchronized (sLock) {
- if (!sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- }
- } else {
- synchronized (sLock) {
- if (!sHasNfcFeature || !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
- /*
- * Privileged FLAG to set technology mask for all data processed by NFC controller
- * Note: Use with caution! The app is responsible for ensuring that the discovery
- * technology mask is returned to default.
- * Note: FLAG_USE_ALL_TECH used with _KEEP flags will reset the technolody to android default
- */
- if (Flags.nfcSetDefaultDiscTech()
- && ((pollTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH
- || (listenTechnology & FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {
- Binder token = new Binder();
- callService( () ->
- sService.updateDiscoveryTechnology(
- token, pollTechnology, listenTechnology, mContext.getPackageName()));
- } else {
- mNfcActivityManager.setDiscoveryTech(activity, pollTechnology, listenTechnology);
- }
- }
-
- /**
- * Restore the poll/listen technologies of NFC controller to its default state,
- * which were changed by {@link #setDiscoveryTechnology(Activity , int , int)}
- *
- * @param activity The Activity that requested to change technologies.
- */
-
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_SET_DISCOVERY_TECH)
- public void resetDiscoveryTechnology(@NonNull Activity activity) {
- mNfcActivityManager.resetDiscoveryTech(activity);
- }
-
- /**
- * Manually invoke Android Beam to share data.
- *
- * <p>The Android Beam animation is normally only shown when two NFC-capable
- * devices come into range.
- * By calling this method, an Activity can invoke the Beam animation directly
- * even if no other NFC device is in range yet. The Beam animation will then
- * prompt the user to tap another NFC-capable device to complete the data
- * transfer.
- *
- * <p>The main advantage of using this method is that it avoids the need for the
- * user to tap the screen to complete the transfer, as this method already
- * establishes the direction of the transfer and the consent of the user to
- * share data. Callers are responsible for making sure that the user has
- * consented to sharing data on NFC tap.
- *
- * <p>Note that to use this method, the passed in Activity must have already
- * set data to share over Beam by using method calls such as
- * {@link #setNdefPushMessageCallback} or
- * {@link #setBeamPushUrisCallback}.
- *
- * @param activity the current foreground Activity that has registered data to share
- * @return whether the Beam animation was successfully invoked
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public boolean invokeBeam(Activity activity) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- return false;
- }
-
- /**
- * Enable NDEF message push over NFC while this Activity is in the foreground.
- *
- * <p>You must explicitly call this method every time the activity is
- * resumed, and you must call {@link #disableForegroundNdefPush} before
- * your activity completes {@link Activity#onPause}.
- *
- * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
- * instead: it automatically hooks into your activity life-cycle,
- * so you do not need to call enable/disable in your onResume/onPause.
- *
- * <p>For NDEF push to function properly the other NFC device must
- * support either NFC Forum's SNEP (Simple Ndef Exchange Protocol), or
- * Android's "com.android.npp" (Ndef Push Protocol). This was optional
- * on Gingerbread level Android NFC devices, but SNEP is mandatory on
- * Ice-Cream-Sandwich and beyond.
- *
- * <p>This method must be called from the main thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param activity foreground activity
- * @param message a NDEF Message to push over NFC
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @Deprecated
- @UnsupportedAppUsage
- public void enableForegroundNdefPush(Activity activity, NdefMessage message) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Disable NDEF message push over P2P.
- *
- * <p>After calling {@link #enableForegroundNdefPush}, an activity
- * must call this method before its {@link Activity#onPause} callback
- * completes.
- *
- * <p>Strongly recommend to use the new {@link #setNdefPushMessage}
- * instead: it automatically hooks into your activity life-cycle,
- * so you do not need to call enable/disable in your onResume/onPause.
- *
- * <p>This method must be called from the main thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param activity the Foreground activity
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @Deprecated
- @UnsupportedAppUsage
- public void disableForegroundNdefPush(Activity activity) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- }
-
- /**
- * Sets Secure NFC feature.
- * <p>This API is for the Settings application.
- * @return True if successful
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean enableSecureNfc(boolean enable) {
- if (!sHasNfcFeature && !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.setNfcSecure(enable), false);
-
- }
-
- /**
- * Checks if the device supports Secure NFC functionality.
- *
- * @return True if device supports Secure NFC, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable
- */
- public boolean isSecureNfcSupported() {
- if (!sHasNfcFeature && !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.deviceSupportsNfcSecure(), false);
-
- }
-
- /**
- * Returns information regarding Nfc antennas on the device
- * such as their relative positioning on the device.
- *
- * @return Information on the nfc antenna(s) on the device.
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable
- */
- @Nullable
- public NfcAntennaInfo getNfcAntennaInfo() {
- if (!sHasNfcFeature && !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.getNfcAntennaInfo(), null);
-
- }
-
- /**
- * Checks Secure NFC feature is enabled.
- *
- * @return True if Secure NFC is enabled, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable
- * @throws UnsupportedOperationException if device doesn't support
- * Secure NFC functionality. {@link #isSecureNfcSupported}
- */
- public boolean isSecureNfcEnabled() {
- if (!sHasNfcFeature && !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.isNfcSecureEnabled(), false);
-
- }
-
- /**
- * Sets NFC Reader option feature.
- * <p>This API is for the Settings application.
- * @return True if successful
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean enableReaderOption(boolean enable) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() ->
- sService.enableReaderOption(enable, mContext.getPackageName()), false);
-
- }
-
- /**
- * Checks if the device supports NFC Reader option functionality.
- *
- * @return True if device supports NFC Reader option, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
- public boolean isReaderOptionSupported() {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.isReaderOptionSupported(), false);
-
- }
-
- /**
- * Checks NFC Reader option feature is enabled.
- *
- * @return True if NFC Reader option is enabled, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @throws UnsupportedOperationException if device doesn't support
- * NFC Reader option functionality. {@link #isReaderOptionSupported}
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_READER_OPTION)
- public boolean isReaderOptionEnabled() {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.isReaderOptionEnabled(), false);
-
- }
-
- /**
- * Enable NDEF Push feature.
- * <p>This API is for the Settings application.
- * @hide
- * @removed
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @UnsupportedAppUsage
- public boolean enableNdefPush() {
- return false;
- }
-
- /**
- * Disable NDEF Push feature.
- * <p>This API is for the Settings application.
- * @hide
- * @removed
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @UnsupportedAppUsage
- public boolean disableNdefPush() {
- return false;
- }
-
- /**
- * Return true if the NDEF Push (Android Beam) feature is enabled.
- * <p>This function will return true only if both NFC is enabled, and the
- * NDEF Push feature is enabled.
- * <p>Note that if NFC is enabled but NDEF Push is disabled then this
- * device can still <i>receive</i> NDEF messages, it just cannot send them.
- * <p>Applications cannot directly toggle the NDEF Push feature, but they
- * can request Settings UI allowing the user to toggle NDEF Push using
- * <code>startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS))</code>
- * <p>Example usage in an Activity that requires NDEF Push:
- * <p><pre>
- * protected void onResume() {
- * super.onResume();
- * if (!nfcAdapter.isEnabled()) {
- * startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
- * } else if (!nfcAdapter.isNdefPushEnabled()) {
- * startActivity(new Intent(Settings.ACTION_NFCSHARING_SETTINGS));
- * }
- * }</pre>
- *
- * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
- * @return true if NDEF Push feature is enabled
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- * @removed this feature is removed. File sharing can work using other technology like
- * Bluetooth.
- */
- @java.lang.Deprecated
- @UnsupportedAppUsage
- public boolean isNdefPushEnabled() {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- return false;
- }
-
- /**
- * Signals that you are no longer interested in communicating with an NFC tag
- * for as long as it remains in range.
- *
- * All future attempted communication to this tag will fail with {@link IOException}.
- * The NFC controller will be put in a low-power polling mode, allowing the device
- * to save power in cases where it's "attached" to a tag all the time (e.g. a tag in
- * car dock).
- *
- * Additionally the debounceMs parameter allows you to specify for how long the tag needs
- * to have gone out of range, before it will be dispatched again.
- *
- * Note: the NFC controller typically polls at a pretty slow interval (100 - 500 ms).
- * This means that if the tag repeatedly goes in and out of range (for example, in
- * case of a flaky connection), and the controller happens to poll every time the
- * tag is out of range, it *will* re-dispatch the tag after debounceMs, despite the tag
- * having been "in range" during the interval.
- *
- * Note 2: if a tag with another UID is detected after this API is called, its effect
- * will be cancelled; if this tag shows up before the amount of time specified in
- * debounceMs, it will be dispatched again.
- *
- * Note 3: some tags have a random UID, in which case this API won't work reliably.
- *
- * @param tag the {@link android.nfc.Tag Tag} to ignore.
- * @param debounceMs minimum amount of time the tag needs to be out of range before being
- * dispatched again.
- * @param tagRemovedListener listener to be called when the tag is removed from the field.
- * Note that this will only be called if the tag has been out of range
- * for at least debounceMs, or if another tag came into range before
- * debounceMs. May be null in case you don't want a callback.
- * @param handler the {@link android.os.Handler Handler} that will be used for delivering
- * the callback. if the handler is null, then the thread used for delivering
- * the callback is unspecified.
- * @return false if the tag couldn't be found (or has already gone out of range), true otherwise
- */
- public boolean ignore(final Tag tag, int debounceMs,
- final OnTagRemovedListener tagRemovedListener, final Handler handler) {
- ITagRemovedCallback.Stub iListener = null;
- if (tagRemovedListener != null) {
- iListener = new ITagRemovedCallback.Stub() {
- @Override
- public void onTagRemoved() throws RemoteException {
- if (handler != null) {
- handler.post(new Runnable() {
- @Override
- public void run() {
- tagRemovedListener.onTagRemoved();
- }
- });
- } else {
- tagRemovedListener.onTagRemoved();
- }
- synchronized (mLock) {
- mTagRemovedListener = null;
- }
- }
- };
- }
- synchronized (mLock) {
- mTagRemovedListener = iListener;
- }
- final ITagRemovedCallback.Stub passedListener = iListener;
- return callServiceReturn(() ->
- sService.ignore(tag.getServiceHandle(), debounceMs, passedListener), false);
- }
-
- /**
- * Inject a mock NFC tag.<p>
- * Used for testing purposes.
- * <p class="note">Requires the
- * {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
- * @hide
- */
- public void dispatch(Tag tag) {
- if (tag == null) {
- throw new NullPointerException("tag cannot be null");
- }
- callService(() -> sService.dispatch(tag));
- }
-
- /**
- * Registers a new NFC unlock handler with the NFC service.
- *
- * <p />NFC unlock handlers are intended to unlock the keyguard in the presence of a trusted
- * NFC device. The handler should return true if it successfully authenticates the user and
- * unlocks the keyguard.
- *
- * <p /> The parameter {@code tagTechnologies} determines which Tag technologies will be polled for
- * at the lockscreen. Polling for less tag technologies reduces latency, and so it is
- * strongly recommended to only provide the Tag technologies that the handler is expected to
- * receive. There must be at least one tag technology provided, otherwise the unlock handler
- * is ignored.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean addNfcUnlockHandler(final NfcUnlockHandler unlockHandler,
- String[] tagTechnologies) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- // If there are no tag technologies, don't bother adding unlock handler
- if (tagTechnologies.length == 0) {
- return false;
- }
-
- try {
- synchronized (mLock) {
- if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
- // update the tag technologies
- callService(() -> {
- sService.removeNfcUnlockHandler(mNfcUnlockHandlers.get(unlockHandler));
- mNfcUnlockHandlers.remove(unlockHandler);
- });
- }
-
- INfcUnlockHandler.Stub iHandler = new INfcUnlockHandler.Stub() {
- @Override
- public boolean onUnlockAttempted(Tag tag) throws RemoteException {
- return unlockHandler.onUnlockAttempted(tag);
- }
- };
- return callServiceReturn(() -> {
- sService.addNfcUnlockHandler(
- iHandler, Tag.getTechCodesFromStrings(tagTechnologies));
- mNfcUnlockHandlers.put(unlockHandler, iHandler);
- return true;
- }, false);
- }
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Unable to register LockscreenDispatch", e);
- return false;
- }
-
- }
-
- /**
- * Removes a previously registered unlock handler. Also removes the tag technologies
- * associated with the removed unlock handler.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean removeNfcUnlockHandler(NfcUnlockHandler unlockHandler) {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- synchronized (mLock) {
- if (mNfcUnlockHandlers.containsKey(unlockHandler)) {
- return callServiceReturn(() -> {
- sService.removeNfcUnlockHandler(mNfcUnlockHandlers.remove(unlockHandler));
- return true;
- }, false);
- }
- return true;
- }
- }
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- public INfcAdapterExtras getNfcAdapterExtrasInterface() {
- if (mContext == null) {
- throw new UnsupportedOperationException("You need a context on NfcAdapter to use the "
- + " NFC extras APIs");
- }
- return callServiceReturn(() ->
- sService.getNfcAdapterExtrasInterface(mContext.getPackageName()), null);
-
- }
-
- void enforceResumed(Activity activity) {
- if (!activity.isResumed()) {
- throw new IllegalStateException("API cannot be called while activity is paused");
- }
- }
-
- int getSdkVersion() {
- if (mContext == null) {
- return android.os.Build.VERSION_CODES.GINGERBREAD; // best guess
- } else {
- return mContext.getApplicationInfo().targetSdkVersion;
- }
- }
-
- /**
- * Sets NFC controller always on feature.
- * <p>This API is for the NFCC internal state management. It allows to discriminate
- * the controller function from the NFC function by keeping the NFC controller on without
- * any NFC RF enabled if necessary.
- * <p>This call is asynchronous. Register a listener {@link ControllerAlwaysOnListener}
- * by {@link #registerControllerAlwaysOnListener} to find out when the operation is
- * complete.
- * <p>If this returns true, then either NFCC always on state has been set based on the value,
- * or a {@link ControllerAlwaysOnListener#onControllerAlwaysOnChanged(boolean)} will be invoked
- * to indicate the state change.
- * If this returns false, then there is some problem that prevents an attempt to turn NFCC
- * always on.
- * @param value if true the NFCC will be kept on (with no RF enabled if NFC adapter is
- * disabled), if false the NFCC will follow completely the Nfc adapter state.
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable
- * @return true if feature is supported by the device and operation has been initiated,
- * false if the feature is not supported by the device.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public boolean setControllerAlwaysOn(boolean value) {
- if (!sHasNfcFeature && !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- int mode = value ? CONTROLLER_ALWAYS_ON_MODE_DEFAULT : CONTROLLER_ALWAYS_ON_DISABLE;
- try {
- callService(() -> sService.setControllerAlwaysOn(mode));
- } catch (UnsupportedOperationException e) {
- return false;
- }
- return true;
- }
-
- /**
- * Checks NFC controller always on feature is enabled.
- *
- * @return True if NFC controller always on is enabled, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public boolean isControllerAlwaysOn() {
- return callServiceReturn(() -> sService.isControllerAlwaysOn(), false);
-
- }
-
- /**
- * Checks if the device supports NFC controller always on functionality.
- *
- * @return True if device supports NFC controller always on, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC,
- * FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public boolean isControllerAlwaysOnSupported() {
- if (!sHasNfcFeature && !sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.isControllerAlwaysOnSupported(), false);
-
- }
-
- /**
- * Register a {@link ControllerAlwaysOnListener} to listen for NFC controller always on
- * state changes
- * <p>The provided listener will be invoked by the given {@link Executor}.
- *
- * @param executor an {@link Executor} to execute given listener
- * @param listener user implementation of the {@link ControllerAlwaysOnListener}
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public void registerControllerAlwaysOnListener(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull ControllerAlwaysOnListener listener) {
- mControllerAlwaysOnListener.register(executor, listener);
- }
-
- /**
- * Unregister the specified {@link ControllerAlwaysOnListener}
- * <p>The same {@link ControllerAlwaysOnListener} object used when calling
- * {@link #registerControllerAlwaysOnListener(Executor, ControllerAlwaysOnListener)}
- * must be used.
- *
- * <p>Listeners are automatically unregistered when application process goes away
- *
- * @param listener user implementation of the {@link ControllerAlwaysOnListener}
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public void unregisterControllerAlwaysOnListener(
- @NonNull ControllerAlwaysOnListener listener) {
- mControllerAlwaysOnListener.unregister(listener);
- }
-
-
- /**
- * Sets whether we dispatch NFC Tag intents to the package.
- *
- * <p>{@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
- * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
- * disallowed.
- * <p>An app is added to the preference list with the allowed flag set to {@code true}
- * when a Tag intent is dispatched to the package for the first time. This API is called
- * by settings to note that the user wants to change this default preference.
- *
- * @param userId the user to whom this package name will belong to
- * @param pkg the full name (i.e. com.google.android.tag) of the package that will be added to
- * the preference list
- * @param allow {@code true} to allow dispatching Tag intents to the package's activity,
- * {@code false} otherwise
- * @return the {@link #TagIntentAppPreferenceResult} value
- * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
- * {@code false}
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @TagIntentAppPreferenceResult
- public int setTagIntentAppPreferenceForUser(@UserIdInt int userId,
- @NonNull String pkg, boolean allow) {
- Objects.requireNonNull(pkg, "pkg cannot be null");
- if (!isTagIntentAppPreferenceSupported()) {
- Log.e(TAG, "TagIntentAppPreference is not supported");
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() ->
- sService.setTagIntentAppPreferenceForUser(userId, pkg, allow),
- TAG_INTENT_APP_PREF_RESULT_UNAVAILABLE);
- }
-
-
- /**
- * Get the Tag dispatch preference list of the UserId.
- *
- * <p>This returns a mapping of package names for this user id to whether we dispatch Tag
- * intents to the package. {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
- * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if its package is
- * mapped to {@code false}.
- * <p>There are three different possible cases:
- * <p>A package not being in the preference list.
- * It does not contain any Tag intent filters or the user never triggers a Tag detection that
- * matches the intent filter of the package.
- * <p>A package being mapped to {@code true}.
- * When a package has been launched by a tag detection for the first time, the package name is
- * put to the map and by default mapped to {@code true}. The package will receive Tag intents as
- * usual.
- * <p>A package being mapped to {@code false}.
- * The user chooses to disable this package and it will not receive any Tag intents anymore.
- *
- * @param userId the user to whom this preference list will belong to
- * @return a map of the UserId which indicates the mapping from package name to
- * boolean(allow status), otherwise return an empty map
- * @throws UnsupportedOperationException if {@link isTagIntentAppPreferenceSupported} returns
- * {@code false}
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @NonNull
- public Map<String, Boolean> getTagIntentAppPreferenceForUser(@UserIdInt int userId) {
- if (!isTagIntentAppPreferenceSupported()) {
- Log.e(TAG, "TagIntentAppPreference is not supported");
- throw new UnsupportedOperationException();
- }
- return callServiceReturn( () ->
- sService.getTagIntentAppPreferenceForUser(userId), Collections.emptyMap());
- }
-
- /**
- * Checks if the device supports Tag Intent App Preference functionality.
- *
- * When supported, {@link #ACTION_NDEF_DISCOVERED}, {@link #ACTION_TECH_DISCOVERED} or
- * {@link #ACTION_TAG_DISCOVERED} will not be dispatched to an Activity if
- * {@link isTagIntentAllowed} returns {@code false}.
- *
- * @return {@code true} if the device supports Tag application preference, {@code false}
- * otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable
- */
- @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
- public boolean isTagIntentAppPreferenceSupported() {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.isTagIntentAppPreferenceSupported(), false);
- }
-
- /**
- * Notifies the system of a new polling loop.
- *
- * @param frame is the new frame.
- *
- * @hide
- */
- @TestApi
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public void notifyPollingLoop(@NonNull PollingFrame pollingFrame) {
- callService(() -> sService.notifyPollingLoop(pollingFrame));
- }
-
-
- /**
- * Notifies the system of new HCE data for tests.
- *
- * @hide
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public void notifyTestHceData(int technology, byte[] data) {
- callService(() -> sService.notifyTestHceData(technology, data));
- }
-
- /** @hide */
- interface ServiceCall {
- void call() throws RemoteException;
- }
- /** @hide */
- static void callService(ServiceCall call) {
- try {
- if (sService == null) {
- attemptDeadServiceRecovery(new RemoteException("NFC Service is null"));
- }
- call.call();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- try {
- call.call();
- } catch (RemoteException ee) {
- ee.rethrowAsRuntimeException();
- }
- }
- }
- /** @hide */
- interface ServiceCallReturn<T> {
- T call() throws RemoteException;
- }
- /** @hide */
- static <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) {
- try {
- if (sService == null) {
- attemptDeadServiceRecovery(new RemoteException("NFC Service is null"));
- }
- return call.call();
- } catch (RemoteException e) {
- attemptDeadServiceRecovery(e);
- // Try one more time
- try {
- return call.call();
- } catch (RemoteException ee) {
- ee.rethrowAsRuntimeException();
- }
- }
- return defaultReturn;
- }
-
- /**
- * Notifies the system of a an HCE session being deactivated.
- * *
- * @hide
- */
- @TestApi
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public void notifyHceDeactivated() {
- callService(() -> sService.notifyHceDeactivated());
- }
-
- /**
- * Sets NFC charging feature.
- * <p>This API is for the Settings application.
- * @return True if successful
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean setWlcEnabled(boolean enable) {
- if (!sHasNfcWlcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.setWlcEnabled(enable), false);
- }
-
- /**
- * Checks NFC charging feature is enabled.
- *
- * @return True if NFC charging is enabled, false otherwise
- * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
- * is unavailable
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
- public boolean isWlcEnabled() {
- if (!sHasNfcWlcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.isWlcEnabled(), false);
-
- }
-
- /**
- * A listener to be invoked when NFC controller always on state changes.
- * <p>Register your {@code ControllerAlwaysOnListener} implementation with {@link
- * NfcAdapter#registerWlcStateListener} and disable it with {@link
- * NfcAdapter#unregisterWlcStateListenerListener}.
- * @see #registerWlcStateListener
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
- public interface WlcStateListener {
- /**
- * Called on NFC WLC state changes
- */
- void onWlcStateChanged(@NonNull WlcListenerDeviceInfo wlcListenerDeviceInfo);
- }
-
- /**
- * Register a {@link WlcStateListener} to listen for NFC WLC state changes
- * <p>The provided listener will be invoked by the given {@link Executor}.
- *
- * @param executor an {@link Executor} to execute given listener
- * @param listener user implementation of the {@link WlcStateListener}
- * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
- * is unavailable
- *
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
- public void registerWlcStateListener(
- @NonNull @CallbackExecutor Executor executor,
- @NonNull WlcStateListener listener) {
- if (!sHasNfcWlcFeature) {
- throw new UnsupportedOperationException();
- }
- mNfcWlcStateListener.register(executor, listener);
- }
-
- /**
- * Unregister the specified {@link WlcStateListener}
- * <p>The same {@link WlcStateListener} object used when calling
- * {@link #registerWlcStateListener(Executor, WlcStateListener)}
- * must be used.
- *
- * <p>Listeners are automatically unregistered when application process goes away
- *
- * @param listener user implementation of the {@link WlcStateListener}a
- * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
- * is unavailable
- *
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
- public void unregisterWlcStateListener(
- @NonNull WlcStateListener listener) {
- if (!sHasNfcWlcFeature) {
- throw new UnsupportedOperationException();
- }
- mNfcWlcStateListener.unregister(listener);
- }
-
- /**
- * Returns information on the NFC charging listener device
- *
- * @return Information on the NFC charging listener device
- * @throws UnsupportedOperationException if FEATURE_NFC_CHARGING
- * is unavailable
- */
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
- @Nullable
- public WlcListenerDeviceInfo getWlcListenerDeviceInfo() {
- if (!sHasNfcWlcFeature) {
- throw new UnsupportedOperationException();
- }
- return callServiceReturn(() -> sService.getWlcListenerDeviceInfo(), null);
-
- }
-
- /**
- * Vendor NCI command success.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- public static final int SEND_VENDOR_NCI_STATUS_SUCCESS = 0;
- /**
- * Vendor NCI command rejected.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- public static final int SEND_VENDOR_NCI_STATUS_REJECTED = 1;
- /**
- * Vendor NCI command corrupted.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- public static final int SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED = 2;
- /**
- * Vendor NCI command failed with unknown reason.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- public static final int SEND_VENDOR_NCI_STATUS_FAILED = 3;
-
- /**
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- SEND_VENDOR_NCI_STATUS_SUCCESS,
- SEND_VENDOR_NCI_STATUS_REJECTED,
- SEND_VENDOR_NCI_STATUS_MESSAGE_CORRUPTED,
- SEND_VENDOR_NCI_STATUS_FAILED,
- })
- @interface SendVendorNciStatus {}
-
- /**
- * Message Type for NCI Command.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- public static final int MESSAGE_TYPE_COMMAND = 1;
-
- /**
- * @hide
- */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- MESSAGE_TYPE_COMMAND,
- })
- @interface MessageType {}
-
- /**
- * Send Vendor specific Nci Messages with custom message type.
- *
- * The format of the NCI messages are defined in the NCI specification. The platform is
- * responsible for fragmenting the payload if necessary.
- *
- * Note that mt (message type) is added at the beginning of method parameters as it is more
- * distinctive than other parameters and was requested from vendor.
- *
- * @param mt message Type of the command
- * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
- * the NCI specification
- * @param oid opcode ID of the command. This is left to the OEM / vendor to decide
- * @param payload containing vendor Nci message payload
- * @return message send status
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public @SendVendorNciStatus int sendVendorNciMessage(@MessageType int mt,
- @IntRange(from = 0, to = 15) int gid, @IntRange(from = 0) int oid,
- @NonNull byte[] payload) {
- Objects.requireNonNull(payload, "Payload must not be null");
- return callServiceReturn(() -> sService.sendVendorNciMessage(mt, gid, oid, payload),
- SEND_VENDOR_NCI_STATUS_FAILED);
- }
-
- /**
- * Register an {@link NfcVendorNciCallback} to listen for Nfc vendor responses and notifications
- * <p>The provided callback will be invoked by the given {@link Executor}.
- *
- * <p>When first registering a callback, the callbacks's
- * {@link NfcVendorNciCallback#onVendorNciCallBack(byte[])} is immediately invoked to
- * notify the vendor notification.
- *
- * @param executor an {@link Executor} to execute given callback
- * @param callback user implementation of the {@link NfcVendorNciCallback}
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void registerNfcVendorNciCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull NfcVendorNciCallback callback) {
- mNfcVendorNciCallbackListener.register(executor, callback);
- }
-
- /**
- * Unregister the specified {@link NfcVendorNciCallback}
- *
- * <p>The same {@link NfcVendorNciCallback} object used when calling
- * {@link #registerNfcVendorNciCallback(Executor, NfcVendorNciCallback)} must be used.
- *
- * <p>Callbacks are automatically unregistered when application process goes away
- *
- * @param callback user implementation of the {@link NfcVendorNciCallback}
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void unregisterNfcVendorNciCallback(@NonNull NfcVendorNciCallback callback) {
- mNfcVendorNciCallbackListener.unregister(callback);
- }
-
- /**
- * Interface for receiving vendor NCI responses and notifications.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- public interface NfcVendorNciCallback {
- /**
- * Invoked when a vendor specific NCI response is received.
- *
- * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
- * the NCI specification.
- * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
- * @param payload containing vendor Nci message payload.
- */
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- void onVendorNciResponse(
- @IntRange(from = 0, to = 15) int gid, int oid, @NonNull byte[] payload);
-
- /**
- * Invoked when a vendor specific NCI notification is received.
- *
- * @param gid group ID of the command. This needs to be one of the vendor reserved GIDs from
- * the NCI specification.
- * @param oid opcode ID of the command. This is left to the OEM / vendor to decide.
- * @param payload containing vendor Nci message payload.
- */
- @FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD)
- void onVendorNciNotification(
- @IntRange(from = 9, to = 15) int gid, int oid, @NonNull byte[] payload);
- }
-
- /**
- * Used by data migration to indicate data migration is in progrerss or not.
- *
- * Note: This is @hide intentionally since the client is inside the NFC apex.
- * @param inProgress true if migration is in progress, false once done.
- * @hide
- */
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void indicateDataMigration(boolean inProgress) {
- callService(() -> sService.indicateDataMigration(inProgress, mContext.getPackageName()));
- }
-
- /**
- * Returns an instance of {@link NfcOemExtension} associated with {@link NfcAdapter} instance.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @NonNull public NfcOemExtension getNfcOemExtension() {
- synchronized (sLock) {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- }
- return mNfcOemExtension;
- }
-
- /**
- * Activity action: Bring up the settings page that allows the user to enable or disable tag
- * intent reception for apps.
- *
- * <p>This will direct user to the settings page shows a list that asks users whether
- * they want to allow or disallow the package to start an activity when a tag is discovered.
- *
- */
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
- public static final String ACTION_CHANGE_TAG_INTENT_PREFERENCE =
- "android.nfc.action.CHANGE_TAG_INTENT_PREFERENCE";
-
- /**
- * Checks whether the user has disabled the calling app from receiving NFC tag intents.
- *
- * <p>This method checks whether the caller package name is either not present in the user
- * disabled list or is explicitly allowed by the user.
- *
- * @return {@code true} if an app is either not present in the list or is added to the list
- * with the flag set to {@code true}. Otherwise, it returns {@code false}.
- * It also returns {@code true} if {@link isTagIntentAppPreferenceSupported} returns
- * {@code false}.
- *
- * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
- */
- @FlaggedApi(Flags.FLAG_NFC_CHECK_TAG_INTENT_PREFERENCE)
- public boolean isTagIntentAllowed() {
- if (!sHasNfcFeature) {
- throw new UnsupportedOperationException();
- }
- if (!isTagIntentAppPreferenceSupported()) {
- return true;
- }
- return callServiceReturn(() -> sService.isTagIntentAllowed(mContext.getPackageName(),
- UserHandle.myUserId()), false);
- }
-}
diff --git a/nfc/java/android/nfc/NfcAntennaInfo.aidl b/nfc/java/android/nfc/NfcAntennaInfo.aidl
deleted file mode 100644
index d5e79fc37282..000000000000
--- a/nfc/java/android/nfc/NfcAntennaInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2013 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.nfc;
-
-parcelable NfcAntennaInfo;
diff --git a/nfc/java/android/nfc/NfcAntennaInfo.java b/nfc/java/android/nfc/NfcAntennaInfo.java
deleted file mode 100644
index c57b2e029cc5..000000000000
--- a/nfc/java/android/nfc/NfcAntennaInfo.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc;
-
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-
-/**
- * Contains information on all available Nfc
- * antennas on an Android device as well as information
- * on the device itself in relation positioning of the
- * antennas.
- */
-public final class NfcAntennaInfo implements Parcelable {
- // Width of the device in millimeters.
- private final int mDeviceWidth;
- // Height of the device in millimeters.
- private final int mDeviceHeight;
- // Whether the device is foldable.
- private final boolean mDeviceFoldable;
- // All available Nfc Antennas on the device.
- private final List<AvailableNfcAntenna> mAvailableNfcAntennas;
-
- public NfcAntennaInfo(int deviceWidth, int deviceHeight, boolean deviceFoldable,
- @NonNull List<AvailableNfcAntenna> availableNfcAntennas) {
- this.mDeviceWidth = deviceWidth;
- this.mDeviceHeight = deviceHeight;
- this.mDeviceFoldable = deviceFoldable;
- this.mAvailableNfcAntennas = availableNfcAntennas;
- }
-
- /**
- * Width of the device in millimeters.
- */
- public int getDeviceWidth() {
- return mDeviceWidth;
- }
-
- /**
- * Height of the device in millimeters.
- */
- public int getDeviceHeight() {
- return mDeviceHeight;
- }
-
- /**
- * Whether the device is foldable. When the device is foldable,
- * the 0, 0 is considered to be top-left when the device is unfolded and
- * the screens are facing the user. For non-foldable devices 0, 0
- * is top-left when the user is facing the screen.
- */
- public boolean isDeviceFoldable() {
- return mDeviceFoldable;
- }
-
- /**
- * Get all NFC antennas that exist on the device.
- */
- @NonNull
- public List<AvailableNfcAntenna> getAvailableNfcAntennas() {
- return mAvailableNfcAntennas;
- }
-
- private NfcAntennaInfo(Parcel in) {
- this.mDeviceWidth = in.readInt();
- this.mDeviceHeight = in.readInt();
- this.mDeviceFoldable = in.readByte() != 0;
- this.mAvailableNfcAntennas = new ArrayList<>();
- in.readTypedList(this.mAvailableNfcAntennas,
- AvailableNfcAntenna.CREATOR);
- }
-
- public static final @NonNull Parcelable.Creator<NfcAntennaInfo> CREATOR =
- new Parcelable.Creator<NfcAntennaInfo>() {
- @Override
- public NfcAntennaInfo createFromParcel(Parcel in) {
- return new NfcAntennaInfo(in);
- }
-
- @Override
- public NfcAntennaInfo[] newArray(int size) {
- return new NfcAntennaInfo[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mDeviceWidth);
- dest.writeInt(mDeviceHeight);
- dest.writeByte((byte) (mDeviceFoldable ? 1 : 0));
- dest.writeTypedList(mAvailableNfcAntennas, 0);
- }
-}
diff --git a/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java b/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java
deleted file mode 100644
index 6ae58fd38cbe..000000000000
--- a/nfc/java/android/nfc/NfcControllerAlwaysOnListener.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc;
-
-import android.annotation.NonNull;
-import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public class NfcControllerAlwaysOnListener extends INfcControllerAlwaysOnListener.Stub {
- private static final String TAG = NfcControllerAlwaysOnListener.class.getSimpleName();
-
- private final INfcAdapter mAdapter;
-
- private final Map<ControllerAlwaysOnListener, Executor> mListenerMap = new HashMap<>();
-
- private boolean mCurrentState = false;
- private boolean mIsRegistered = false;
-
- public NfcControllerAlwaysOnListener(@NonNull INfcAdapter adapter) {
- mAdapter = adapter;
- }
-
- /**
- * Register a {@link ControllerAlwaysOnListener} with this
- * {@link NfcControllerAlwaysOnListener}
- *
- * @param executor an {@link Executor} to execute given listener
- * @param listener user implementation of the {@link ControllerAlwaysOnListener}
- */
- public void register(@NonNull Executor executor,
- @NonNull ControllerAlwaysOnListener listener) {
- try {
- if (!mAdapter.isControllerAlwaysOnSupported()) {
- return;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to register");
- return;
- }
- synchronized (this) {
- if (mListenerMap.containsKey(listener)) {
- return;
- }
-
- mListenerMap.put(listener, executor);
- if (!mIsRegistered) {
- try {
- mAdapter.registerControllerAlwaysOnListener(this);
- mIsRegistered = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to register");
- }
- }
- }
- }
-
- /**
- * Unregister the specified {@link ControllerAlwaysOnListener}
- *
- * @param listener user implementation of the {@link ControllerAlwaysOnListener}
- */
- public void unregister(@NonNull ControllerAlwaysOnListener listener) {
- try {
- if (!mAdapter.isControllerAlwaysOnSupported()) {
- return;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to unregister");
- return;
- }
- synchronized (this) {
- if (!mListenerMap.containsKey(listener)) {
- return;
- }
-
- mListenerMap.remove(listener);
-
- if (mListenerMap.isEmpty() && mIsRegistered) {
- try {
- mAdapter.unregisterControllerAlwaysOnListener(this);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to unregister");
- }
- mIsRegistered = false;
- }
- }
- }
-
- private void sendCurrentState(@NonNull ControllerAlwaysOnListener listener) {
- synchronized (this) {
- Executor executor = mListenerMap.get(listener);
-
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> listener.onControllerAlwaysOnChanged(
- mCurrentState));
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- @Override
- public void onControllerAlwaysOnChanged(boolean isEnabled) {
- synchronized (this) {
- mCurrentState = isEnabled;
- for (ControllerAlwaysOnListener cb : mListenerMap.keySet()) {
- sendCurrentState(cb);
- }
- }
- }
-}
-
diff --git a/nfc/java/android/nfc/NfcEvent.java b/nfc/java/android/nfc/NfcEvent.java
deleted file mode 100644
index aff4f52f2bab..000000000000
--- a/nfc/java/android/nfc/NfcEvent.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-/**
- * Wraps information associated with any NFC event.
- *
- * <p>Immutable object, with direct access to the (final) fields.
- *
- * <p>An {@link NfcEvent} object is usually included in callbacks from
- * {@link NfcAdapter}. Check the documentation of the callback to see
- * which fields may be set.
- *
- * <p>This wrapper object is used (instead of parameters
- * in the callback) because it allows new fields to be added without breaking
- * API compatibility.
- *
- * @see NfcAdapter.OnNdefPushCompleteCallback#onNdefPushComplete
- * @see NfcAdapter.CreateNdefMessageCallback#createNdefMessage
- */
-public final class NfcEvent {
- /**
- * The {@link NfcAdapter} associated with the NFC event.
- */
- public final NfcAdapter nfcAdapter;
-
- /**
- * The major LLCP version number of the peer associated with the NFC event.
- */
- public final int peerLlcpMajorVersion;
-
- /**
- * The minor LLCP version number of the peer associated with the NFC event.
- */
- public final int peerLlcpMinorVersion;
-
- NfcEvent(NfcAdapter nfcAdapter, byte peerLlcpVersion) {
- this.nfcAdapter = nfcAdapter;
- this.peerLlcpMajorVersion = (peerLlcpVersion & 0xF0) >> 4;
- this.peerLlcpMinorVersion = peerLlcpVersion & 0x0F;
- }
-}
diff --git a/nfc/java/android/nfc/NfcFrameworkInitializer.java b/nfc/java/android/nfc/NfcFrameworkInitializer.java
deleted file mode 100644
index 1ab8a1ebd72c..000000000000
--- a/nfc/java/android/nfc/NfcFrameworkInitializer.java
+++ /dev/null
@@ -1,71 +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.nfc;
-
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.app.SystemServiceRegistry;
-import android.content.Context;
-
-/**
- * Class for performing registration for Nfc service.
- *
- * @hide
- */
-@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
-public class NfcFrameworkInitializer {
- private NfcFrameworkInitializer() {}
-
- private static volatile NfcServiceManager sNfcServiceManager;
-
- /**
- * Sets an instance of {@link NfcServiceManager} that allows
- * the nfc mainline module to register/obtain nfc binder services. This is called
- * by the platform during the system initialization.
- *
- * @param nfcServiceManager instance of {@link NfcServiceManager} that allows
- * the nfc mainline module to register/obtain nfcd binder services.
- */
- public static void setNfcServiceManager(
- @NonNull NfcServiceManager nfcServiceManager) {
- if (sNfcServiceManager != null) {
- throw new IllegalStateException("setNfcServiceManager called twice!");
- }
-
- if (nfcServiceManager == null) {
- throw new IllegalArgumentException("nfcServiceManager must not be null");
- }
-
- sNfcServiceManager = nfcServiceManager;
- }
-
- /** @hide */
- public static NfcServiceManager getNfcServiceManager() {
- return sNfcServiceManager;
- }
-
- /**
- * Called by {@link SystemServiceRegistry}'s static initializer and registers NFC service
- * to {@link Context}, so that {@link Context#getSystemService} can return them.
- *
- * @throws IllegalStateException if this is called from anywhere besides
- * {@link SystemServiceRegistry}
- */
- public static void registerServiceWrappers() {
- SystemServiceRegistry.registerContextAwareService(Context.NFC_SERVICE,
- NfcManager.class, context -> new NfcManager(context));
- }
-}
diff --git a/nfc/java/android/nfc/NfcManager.java b/nfc/java/android/nfc/NfcManager.java
deleted file mode 100644
index 644e3122774b..000000000000
--- a/nfc/java/android/nfc/NfcManager.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.annotation.SystemService;
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.os.Build;
-
-/**
- * High level manager used to obtain an instance of an {@link NfcAdapter}.
- * <p>
- * Use {@link android.content.Context#getSystemService(java.lang.String)}
- * with {@link Context#NFC_SERVICE} to create an {@link NfcManager},
- * then call {@link #getDefaultAdapter} to obtain the {@link NfcAdapter}.
- * <p>
- * Alternately, you can just call the static helper
- * {@link NfcAdapter#getDefaultAdapter(android.content.Context)}.
- *
- * <div class="special reference">
- * <h3>Developer Guides</h3>
- * <p>For more information about using NFC, read the
- * <a href="{@docRoot}guide/topics/nfc/index.html">Near Field Communication</a> developer guide.</p>
- * </div>
- *
- * @see NfcAdapter#getDefaultAdapter(android.content.Context)
- */
-@SystemService(Context.NFC_SERVICE)
-public final class NfcManager {
- private final NfcAdapter mAdapter;
-
- /**
- * @hide
- */
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
- public NfcManager(Context context) {
- NfcAdapter adapter;
- context = context.getApplicationContext();
- if (context == null) {
- throw new IllegalArgumentException(
- "context not associated with any application (using a mock context?)");
- }
- try {
- adapter = NfcAdapter.getNfcAdapter(context);
- } catch (UnsupportedOperationException e) {
- adapter = null;
- }
- mAdapter = adapter;
- }
-
- /**
- * Get the default NFC Adapter for this device.
- *
- * @return the default NFC Adapter
- */
- public NfcAdapter getDefaultAdapter() {
- return mAdapter;
- }
-}
diff --git a/nfc/java/android/nfc/NfcOemExtension.java b/nfc/java/android/nfc/NfcOemExtension.java
deleted file mode 100644
index 1fc0786d3582..000000000000
--- a/nfc/java/android/nfc/NfcOemExtension.java
+++ /dev/null
@@ -1,1248 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_DH;
-import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE;
-import static android.nfc.cardemulation.CardEmulation.PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC;
-import static android.nfc.cardemulation.CardEmulation.routeIntToString;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.DurationMillisLong;
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.nfc.cardemulation.ApduServiceInfo;
-import android.nfc.cardemulation.CardEmulation;
-import android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.se.omapi.Reader;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.function.BiConsumer;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.function.Supplier;
-
-/**
- * Used for OEM extension APIs.
- * This class holds all the APIs and callbacks defined for OEMs/vendors to extend the NFC stack
- * for their proprietary features.
- *
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public final class NfcOemExtension {
- private static final String TAG = "NfcOemExtension";
- private static final int OEM_EXTENSION_RESPONSE_THRESHOLD_MS = 2000;
- private static final int TYPE_TECHNOLOGY = 0;
- private static final int TYPE_PROTOCOL = 1;
- private static final int TYPE_AID = 2;
- private static final int TYPE_SYSTEMCODE = 3;
-
- private final NfcAdapter mAdapter;
- private final NfcOemExtensionCallback mOemNfcExtensionCallback;
- private boolean mIsRegistered = false;
- private final Map<Callback, Executor> mCallbackMap = new HashMap<>();
- private final Context mContext;
- private final Object mLock = new Object();
- private boolean mCardEmulationActivated = false;
- private boolean mRfFieldActivated = false;
- private boolean mRfDiscoveryStarted = false;
- private boolean mEeListenActivated = false;
-
- /**
- * Broadcast Action: Sent on NFC stack initialization when NFC OEM extensions are enabled.
- * <p> OEM extension modules should use this intent to start their extension service </p>
- * @hide
- */
- public static final String ACTION_OEM_EXTENSION_INIT = "android.nfc.action.OEM_EXTENSION_INIT";
-
- /**
- * Mode Type for {@link #setControllerAlwaysOnMode(int)}.
- * Enables the controller in default mode when NFC is disabled (existing API behavior).
- * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int ENABLE_DEFAULT = NfcAdapter.CONTROLLER_ALWAYS_ON_MODE_DEFAULT;
-
- /**
- * Mode Type for {@link #setControllerAlwaysOnMode(int)}.
- * Enables the controller in transparent mode when NFC is disabled.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int ENABLE_TRANSPARENT = 2;
-
- /**
- * Mode Type for {@link #setControllerAlwaysOnMode(int)}.
- * Enables the controller and initializes and enables the EE subsystem when NFC is disabled.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int ENABLE_EE = 3;
-
- /**
- * Mode Type for {@link #setControllerAlwaysOnMode(int)}.
- * Disable the Controller Always On Mode.
- * works same as {@link NfcAdapter#setControllerAlwaysOn(boolean)}.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int DISABLE = NfcAdapter.CONTROLLER_ALWAYS_ON_DISABLE;
-
- /**
- * Possible controller modes for {@link #setControllerAlwaysOnMode(int)}.
- *
- * @hide
- */
- @IntDef(prefix = { "" }, value = {
- ENABLE_DEFAULT,
- ENABLE_TRANSPARENT,
- ENABLE_EE,
- DISABLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ControllerMode{}
-
- /**
- * Technology Type for {@link #getActiveNfceeList()}.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int NFCEE_TECH_NONE = 0;
-
- /**
- * Technology Type for {@link #getActiveNfceeList()}.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int NFCEE_TECH_A = 1;
-
- /**
- * Technology Type for {@link #getActiveNfceeList()}.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int NFCEE_TECH_B = 1 << 1;
-
- /**
- * Technology Type for {@link #getActiveNfceeList()}.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int NFCEE_TECH_F = 1 << 2;
-
- /**
- * Nfc technology flags for {@link #getActiveNfceeList()}.
- *
- * @hide
- */
- @IntDef(flag = true, value = {
- NFCEE_TECH_NONE,
- NFCEE_TECH_A,
- NFCEE_TECH_B,
- NFCEE_TECH_F,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface NfceeTechnology {}
-
- /**
- * Event that Host Card Emulation is activated.
- */
- public static final int HCE_ACTIVATE = 1;
- /**
- * Event that some data is transferred in Host Card Emulation.
- */
- public static final int HCE_DATA_TRANSFERRED = 2;
- /**
- * Event that Host Card Emulation is deactivated.
- */
- public static final int HCE_DEACTIVATE = 3;
- /**
- * Possible events from {@link Callback#onHceEventReceived}.
- *
- * @hide
- */
- @IntDef(value = {
- HCE_ACTIVATE,
- HCE_DATA_TRANSFERRED,
- HCE_DEACTIVATE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface HostCardEmulationAction {}
-
- /**
- * Status code returned when the polling state change request succeeded.
- * @see #pausePolling()
- * @see #resumePolling()
- */
- public static final int POLLING_STATE_CHANGE_SUCCEEDED = 1;
- /**
- * Status code returned when the polling state change request is already in
- * required state.
- * @see #pausePolling()
- * @see #resumePolling()
- */
- public static final int POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE = 2;
- /**
- * Possible status codes for {@link #pausePolling()} and
- * {@link #resumePolling()}.
- * @hide
- */
- @IntDef(value = {
- POLLING_STATE_CHANGE_SUCCEEDED,
- POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface PollingStateChangeStatusCode {}
-
- /**
- * Status OK
- */
- public static final int STATUS_OK = 0;
- /**
- * Status unknown error
- */
- public static final int STATUS_UNKNOWN_ERROR = 1;
-
- /**
- * Status codes passed to OEM extension callbacks.
- *
- * @hide
- */
- @IntDef(value = {
- STATUS_OK,
- STATUS_UNKNOWN_ERROR
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface StatusCode {}
-
- /**
- * Routing commit succeeded.
- */
- public static final int COMMIT_ROUTING_STATUS_OK = 0;
- /**
- * Routing commit failed.
- */
- public static final int COMMIT_ROUTING_STATUS_FAILED = 3;
- /**
- * Routing commit failed due to the update is in progress.
- */
- public static final int COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS = 6;
-
- /**
- * Status codes returned when calling {@link #forceRoutingTableCommit()}
- * @hide
- */
- @IntDef(prefix = "COMMIT_ROUTING_STATUS_", value = {
- COMMIT_ROUTING_STATUS_OK,
- COMMIT_ROUTING_STATUS_FAILED,
- COMMIT_ROUTING_STATUS_FAILED_UPDATE_IN_PROGRESS,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface CommitRoutingStatusCode {}
- /**
- * Interface for Oem extensions for NFC.
- */
- public interface Callback {
- /**
- * Notify Oem to tag is connected or not
- * ex - if tag is connected notify cover and Nfctest app if app is in testing mode
- *
- * @param connected status of the tag true if tag is connected otherwise false
- */
- void onTagConnected(boolean connected);
-
- /**
- * Update the Nfc Adapter State
- * @param state new state that need to be updated
- */
- void onStateUpdated(@NfcAdapter.AdapterState int state);
- /**
- * Check if NfcService apply routing method need to be skipped for
- * some feature.
- * @param isSkipped The {@link Consumer} to be completed. If apply routing can be skipped,
- * the {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
- */
- void onApplyRouting(@NonNull Consumer<Boolean> isSkipped);
- /**
- * Check if NfcService ndefRead method need to be skipped To skip
- * and start checking for presence of tag
- * @param isSkipped The {@link Consumer} to be completed. If Ndef read can be skipped,
- * the {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
- */
- void onNdefRead(@NonNull Consumer<Boolean> isSkipped);
- /**
- * Method to check if Nfc is allowed to be enabled by OEMs.
- * @param isAllowed The {@link Consumer} to be completed. If enabling NFC is allowed,
- * the {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
- * false if NFC cannot be enabled at this time.
- */
- void onEnableRequested(@NonNull Consumer<Boolean> isAllowed);
- /**
- * Method to check if Nfc is allowed to be disabled by OEMs.
- * @param isAllowed The {@link Consumer} to be completed. If disabling NFC is allowed,
- * the {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
- * false if NFC cannot be disabled at this time.
- */
- void onDisableRequested(@NonNull Consumer<Boolean> isAllowed);
-
- /**
- * Callback to indicate that Nfc starts to boot.
- */
- void onBootStarted();
-
- /**
- * Callback to indicate that Nfc starts to enable.
- */
- void onEnableStarted();
-
- /**
- * Callback to indicate that Nfc starts to disable.
- */
- void onDisableStarted();
-
- /**
- * Callback to indicate if NFC boots successfully or not.
- * @param status the status code indicating if boot finished successfully
- */
- void onBootFinished(@StatusCode int status);
-
- /**
- * Callback to indicate if NFC is successfully enabled.
- * @param status the status code indicating if enable finished successfully
- */
- void onEnableFinished(@StatusCode int status);
-
- /**
- * Callback to indicate if NFC is successfully disabled.
- * @param status the status code indicating if disable finished successfully
- */
- void onDisableFinished(@StatusCode int status);
-
- /**
- * Check if NfcService tag dispatch need to be skipped.
- * @param isSkipped The {@link Consumer} to be completed. If tag dispatch can be skipped,
- * the {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
- */
- void onTagDispatch(@NonNull Consumer<Boolean> isSkipped);
-
- /**
- * Notifies routing configuration is changed.
- * @param isCommitRoutingSkipped The {@link Consumer} to be
- * completed. If routing commit should be skipped,
- * the {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with {@link Boolean#FALSE}.
- */
- void onRoutingChanged(@NonNull Consumer<Boolean> isCommitRoutingSkipped);
-
- /**
- * API to activate start stop cpu boost on hce event.
- *
- * <p>When HCE is activated, transferring data, and deactivated,
- * must call this method to activate, start and stop cpu boost respectively.
- * @param action Flag indicating actions to activate, start and stop cpu boost.
- */
- void onHceEventReceived(@HostCardEmulationAction int action);
-
- /**
- * API to notify when reader option has been changed using
- * {@link NfcAdapter#enableReaderOption(boolean)} by some app.
- * @param enabled Flag indicating ReaderMode enabled/disabled
- */
- void onReaderOptionChanged(boolean enabled);
-
- /**
- * Notifies NFC is activated in listen mode.
- * NFC Forum NCI-2.3 ch.5.2.6 specification
- *
- * <p>NFCC is ready to communicate with a Card reader
- *
- * @param isActivated true, if card emulation activated, else de-activated.
- */
- void onCardEmulationActivated(boolean isActivated);
-
- /**
- * Notifies the Remote NFC Endpoint RF Field is detected.
- * NFC Forum NCI-2.3 ch.5.3 specification
- *
- * @param isActive true, if RF Field is ON, else RF Field is OFF.
- */
- void onRfFieldDetected(boolean isActive);
-
- /**
- * Notifies the NFC RF discovery is started or in the IDLE state.
- * NFC Forum NCI-2.3 ch.5.2 specification
- *
- * @param isDiscoveryStarted true, if RF discovery started, else RF state is Idle.
- */
- void onRfDiscoveryStarted(boolean isDiscoveryStarted);
-
- /**
- * Notifies the NFCEE (NFC Execution Environment) Listen has been activated.
- *
- * @param isActivated true, if EE Listen is ON, else EE Listen is OFF.
- */
- void onEeListenActivated(boolean isActivated);
-
- /**
- * Notifies that some NFCEE (NFC Execution Environment) has been updated.
- *
- * <p> This indicates that some applet has been installed/updated/removed in
- * one of the NFCEE's.
- * </p>
- */
- void onEeUpdated();
-
- /**
- * Gets the intent to find the OEM package in the OEM App market. If the consumer returns
- * {@code null} or a timeout occurs, the intent from the first available package will be
- * used instead.
- *
- * @param packages the OEM packages name stored in the tag
- * @param intentConsumer The {@link Consumer} to be completed.
- * The {@link Consumer#accept(Object)} should be called with
- * the Intent required.
- *
- */
- void onGetOemAppSearchIntent(@NonNull List<String> packages,
- @NonNull Consumer<Intent> intentConsumer);
-
- /**
- * Checks if the NDEF message contains any specific OEM package executable content
- *
- * @param tag the {@link android.nfc.Tag Tag}
- * @param message NDEF Message to read from tag
- * @param hasOemExecutableContent The {@link Consumer} to be completed. If there is
- * OEM package executable content, the
- * {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}, otherwise call with
- * {@link Boolean#FALSE}.
- */
- void onNdefMessage(@NonNull Tag tag, @NonNull NdefMessage message,
- @NonNull Consumer<Boolean> hasOemExecutableContent);
-
- /**
- * Callback to indicate the app chooser activity should be launched for handling CE
- * transaction. This is invoked for example when there are more than 1 app installed that
- * can handle the HCE transaction. OEMs can launch the Activity based
- * on their requirement.
- *
- * @param selectedAid the selected AID from APDU
- * @param services {@link ApduServiceInfo} of the service triggering the activity
- * @param failedComponent the component failed to be resolved
- * @param category the category of the service
- */
- void onLaunchHceAppChooserActivity(@NonNull String selectedAid,
- @NonNull List<ApduServiceInfo> services,
- @NonNull ComponentName failedComponent,
- @NonNull String category);
-
- /**
- * Callback to indicate tap again dialog should be launched for handling HCE transaction.
- * This is invoked for example when a CE service needs the device to unlocked before
- * handling the transaction. OEMs can launch the Activity based on their requirement.
- *
- * @param service {@link ApduServiceInfo} of the service triggering the dialog
- * @param category the category of the service
- */
- void onLaunchHceTapAgainDialog(@NonNull ApduServiceInfo service, @NonNull String category);
-
- /**
- * Callback to indicate that routing table is full and the OEM can optionally launch a
- * dialog to request the user to remove some Card Emulation apps from the device to free
- * routing table space.
- */
- void onRoutingTableFull();
-
- /**
- * Callback when OEM specified log event are notified.
- * @param item the log items that contains log information of NFC event.
- */
- void onLogEventNotified(@NonNull OemLogItems item);
-
- /**
- * Callback to to extract OEM defined packages from given NDEF message when
- * a NFC tag is detected. These are used to handle NFC tags encoded with a
- * proprietary format for storing app name (Android native app format).
- *
- * @param message NDEF message containing OEM package names
- * @param packageConsumer The {@link Consumer} to be completed.
- * The {@link Consumer#accept(Object)} should be called with
- * the list of package names.
- */
- void onExtractOemPackages(@NonNull NdefMessage message,
- @NonNull Consumer<List<String>> packageConsumer);
- }
-
-
- /**
- * Constructor to be used only by {@link NfcAdapter}.
- */
- NfcOemExtension(@NonNull Context context, @NonNull NfcAdapter adapter) {
- mContext = context;
- mAdapter = adapter;
- mOemNfcExtensionCallback = new NfcOemExtensionCallback();
- }
-
- /**
- * Get an instance of {@link T4tNdefNfcee} object for performing T4T (Type-4 Tag)
- * NDEF (NFC Data Exchange Format) NFCEE (NFC Execution Environment) operations.
- * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
- * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
- * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
- *
- * This is a singleton object which shall be used by OEM extension module to do NDEF-NFCEE
- * read/write operations.
- *
- * <p>Returns {@link T4tNdefNfcee}
- * <p>Does not cause any RF activity and does not block.
- * @return NFC Data Exchange Format (NDEF) NFC Execution Environment (NFCEE) object
- * @hide
- */
- @SystemApi
- @NonNull
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public T4tNdefNfcee getT4tNdefNfcee() {
- return T4tNdefNfcee.getInstance();
- }
-
- /**
- * Register an {@link Callback} to listen for NFC oem extension callbacks
- * Multiple clients can register and callbacks will be invoked asynchronously.
- *
- * <p>The provided callback will be invoked by the given {@link Executor}.
- * As part of {@link #registerCallback(Executor, Callback)} the
- * {@link Callback} will be invoked with current NFC state
- * before the {@link #registerCallback(Executor, Callback)} function completes.
- *
- * @param executor an {@link Executor} to execute given callback
- * @param callback oem implementation of {@link Callback}
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void registerCallback(@NonNull @CallbackExecutor Executor executor,
- @NonNull Callback callback) {
- synchronized (mLock) {
- if (executor == null || callback == null) {
- Log.e(TAG, "Executor and Callback must not be null!");
- throw new IllegalArgumentException();
- }
-
- if (mCallbackMap.containsKey(callback)) {
- Log.e(TAG, "Callback already registered. Unregister existing callback before"
- + "registering");
- throw new IllegalArgumentException();
- }
- mCallbackMap.put(callback, executor);
- if (!mIsRegistered) {
- NfcAdapter.callService(() -> {
- NfcAdapter.sService.registerOemExtensionCallback(mOemNfcExtensionCallback);
- mIsRegistered = true;
- });
- } else {
- updateNfCState(callback, executor);
- }
- }
- }
-
- private void updateNfCState(Callback callback, Executor executor) {
- if (callback != null) {
- Log.i(TAG, "updateNfCState");
- executor.execute(() -> {
- callback.onCardEmulationActivated(mCardEmulationActivated);
- callback.onRfFieldDetected(mRfFieldActivated);
- callback.onRfDiscoveryStarted(mRfDiscoveryStarted);
- callback.onEeListenActivated(mEeListenActivated);
- });
- }
- }
-
- /**
- * Unregister the specified {@link Callback}
- *
- * <p>The same {@link Callback} object used when calling
- * {@link #registerCallback(Executor, Callback)} must be used.
- *
- * <p>Callbacks are automatically unregistered when an application process goes away
- *
- * @param callback oem implementation of {@link Callback}
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void unregisterCallback(@NonNull Callback callback) {
- synchronized (mLock) {
- if (!mCallbackMap.containsKey(callback) || !mIsRegistered) {
- Log.e(TAG, "Callback not registered");
- throw new IllegalArgumentException();
- }
- if (mCallbackMap.size() == 1) {
- NfcAdapter.callService(() -> {
- NfcAdapter.sService.unregisterOemExtensionCallback(mOemNfcExtensionCallback);
- mIsRegistered = false;
- mCallbackMap.remove(callback);
- });
- } else {
- mCallbackMap.remove(callback);
- }
- }
- }
-
- /**
- * Clear NfcService preference, interface method to clear NFC preference values on OEM specific
- * events. For ex: on soft reset, Nfc default values needs to be overridden by OEM defaults.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void clearPreference() {
- NfcAdapter.callService(() -> NfcAdapter.sService.clearPreference());
- }
-
- /**
- * Get the screen state from system and set it to current screen state.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void synchronizeScreenState() {
- NfcAdapter.callService(() -> NfcAdapter.sService.setScreenState());
- }
-
- /**
- * Check if the firmware needs updating.
- *
- * <p>If an update is needed, a firmware will be triggered when NFC is disabled.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void maybeTriggerFirmwareUpdate() {
- NfcAdapter.callService(() -> NfcAdapter.sService.checkFirmware());
- }
-
- /**
- * Get the Active NFCEE (NFC Execution Environment) List
- *
- * @return Map< String, @NfceeTechnology Integer >
- * A HashMap where keys are activated secure elements and
- * the values are bitmap of technologies supported by each secure element:
- * NFCEE_TECH_A == 0x1
- * NFCEE_TECH_B == 0x2
- * NFCEE_TECH_F == 0x4
- * and keys can contain "eSE" and "SIM" with a number,
- * in case of failure an empty map is returned.
- * @see Reader#getName() for the list of possible NFCEE names.
- */
- @NonNull
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public Map<String, Integer> getActiveNfceeList() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sService.fetchActiveNfceeList(), new HashMap<String, Integer>());
- }
-
- /**
- * Sets NFC controller always on feature.
- * <p>This API is for the NFCC internal state management. It allows to discriminate
- * the controller function from the NFC function by keeping the NFC controller on without
- * any NFC RF enabled if necessary.
- * <p>This call is asynchronous, register listener {@link NfcAdapter.ControllerAlwaysOnListener}
- * by {@link NfcAdapter#registerControllerAlwaysOnListener} to find out when the operation is
- * complete.
- * <p> Note: This adds more always on modes on top of existing
- * {@link NfcAdapter#setControllerAlwaysOn(boolean)} API which can be used to set the NFCC in
- * only {@link #ENABLE_DEFAULT} and {@link #DISABLE} modes.
- * @param mode one of {@link ControllerMode} modes
- * @throws UnsupportedOperationException if
- * <li> if FEATURE_NFC, FEATURE_NFC_HOST_CARD_EMULATION, FEATURE_NFC_HOST_CARD_EMULATION_NFCF,
- * FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC and FEATURE_NFC_OFF_HOST_CARD_EMULATION_ESE
- * are unavailable </li>
- * <li> if the feature is unavailable @see NfcAdapter#isNfcControllerAlwaysOnSupported() </li>
- * @hide
- * @see NfcAdapter#setControllerAlwaysOn(boolean)
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON)
- public void setControllerAlwaysOnMode(@ControllerMode int mode) {
- if (!NfcAdapter.sHasNfcFeature && !NfcAdapter.sHasCeFeature) {
- throw new UnsupportedOperationException();
- }
- NfcAdapter.callService(() -> NfcAdapter.sService.setControllerAlwaysOn(mode));
- }
-
- /**
- * Triggers NFC initialization. If OEM extension is registered
- * (indicated via `enable_oem_extension` NFC overlay), the NFC stack initialization at bootup
- * is delayed until the OEM extension app triggers the initialization via this call.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public void triggerInitialization() {
- NfcAdapter.callService(() -> NfcAdapter.sService.triggerInitialization());
- }
-
- /**
- * Gets the last user toggle status.
- * @return true if NFC is set to ON, false otherwise
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean hasUserEnabledNfc() {
- return NfcAdapter.callServiceReturn(() -> NfcAdapter.sService.getSettingStatus(), false);
- }
-
- /**
- * Checks if the tag is present or not.
- * @return true if the tag is present, false otherwise
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean isTagPresent() {
- return NfcAdapter.callServiceReturn(() -> NfcAdapter.sService.isTagPresent(), false);
- }
-
- /**
- * Pauses NFC tag reader mode polling for a {@code timeoutInMs} millisecond.
- * In case of {@code timeoutInMs} is zero or invalid polling will be stopped indefinitely.
- * Use {@link #resumePolling()} to resume the polling.
- * Use {@link #getMaxPausePollingTimeoutMs()} to check the max timeout value.
- * @param timeoutInMs the pause polling duration in millisecond.
- * @return status of the operation
- * @throws IllegalArgumentException if timeoutInMs value is invalid
- * (0 < timeoutInMs < max).
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public @PollingStateChangeStatusCode int pausePolling(@DurationMillisLong long timeoutInMs) {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sService.pausePolling(timeoutInMs),
- POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
- }
-
- /**
- * Resumes default NFC tag reader mode polling for the current device state if polling is
- * paused. Calling this while already in polling is a no-op.
- * @return status of the operation
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public @PollingStateChangeStatusCode int resumePolling() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sService.resumePolling(),
- POLLING_STATE_CHANGE_ALREADY_IN_REQUESTED_STATE);
- }
-
- /**
- * Gets the max pause polling timeout value in millisecond.
- * @return long integer representing the max timeout
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @DurationMillisLong
- public long getMaxPausePollingTimeoutMills() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sService.getMaxPausePollingTimeoutMs(), 0L);
- }
-
- /**
- * Set whether to enable auto routing change or not (enabled by default).
- * If disabled, routing targets are limited to a single off-host destination.
- *
- * @param state status of auto routing change, true if enable, otherwise false
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public void setAutoChangeEnabled(boolean state) {
- NfcAdapter.callService(() ->
- NfcAdapter.sCardEmulationService.setAutoChangeStatus(state));
- }
-
- /**
- * Check if auto routing change is enabled or not.
- *
- * @return true if enabled, otherwise false
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean isAutoChangeEnabled() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sCardEmulationService.isAutoChangeEnabled(), false);
- }
-
- /**
- * Get current routing status
- *
- * @return {@link RoutingStatus} indicating the default route, default ISO-DEP
- * route and default off-host route.
- */
- @NonNull
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- public RoutingStatus getRoutingStatus() {
- List<String> status = NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sCardEmulationService.getRoutingStatus(), new ArrayList<>());
- return new RoutingStatus(routeStringToInt(status.get(0)),
- routeStringToInt(status.get(1)),
- routeStringToInt(status.get(2)));
- }
-
- /**
- * Overwrites NFC controller routing table, which includes Protocol Route, Technology Route,
- * and Empty AID Route.
- *
- * The parameter set to
- * {@link ProtocolAndTechnologyRoute#PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET}
- * can be used to keep current values for that entry. At least one route should be overridden
- * when calling this API, otherwise throw {@link IllegalArgumentException}.
- *
- * @param protocol ISO-DEP route destination, where the possible inputs are defined in
- * {@link ProtocolAndTechnologyRoute}.
- * @param technology Tech-A, Tech-B and Tech-F route destination, where the possible inputs
- * are defined in
- * {@link ProtocolAndTechnologyRoute}
- * @param emptyAid Zero-length AID route destination, where the possible inputs are defined in
- * {@link ProtocolAndTechnologyRoute}
- * @param systemCode System Code route destination, where the possible inputs are defined in
- * {@link ProtocolAndTechnologyRoute}
- */
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public void overwriteRoutingTable(
- @CardEmulation.ProtocolAndTechnologyRoute int protocol,
- @CardEmulation.ProtocolAndTechnologyRoute int technology,
- @CardEmulation.ProtocolAndTechnologyRoute int emptyAid,
- @CardEmulation.ProtocolAndTechnologyRoute int systemCode) {
-
- String protocolRoute = routeIntToString(protocol);
- String technologyRoute = routeIntToString(technology);
- String emptyAidRoute = routeIntToString(emptyAid);
- String systemCodeRoute = routeIntToString(systemCode);
-
- NfcAdapter.callService(() ->
- NfcAdapter.sCardEmulationService.overwriteRoutingTable(
- mContext.getUser().getIdentifier(),
- emptyAidRoute,
- protocolRoute,
- technologyRoute,
- systemCodeRoute
- ));
- }
-
- /**
- * Gets current routing table entries.
- * @return List of {@link NfcRoutingTableEntry} representing current routing table
- */
- @NonNull
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public List<NfcRoutingTableEntry> getRoutingTable() {
- List<Entry> entryList = NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sService.getRoutingTableEntryList(), null);
- List<NfcRoutingTableEntry> result = new ArrayList<>();
- for (Entry entry : entryList) {
- switch (entry.getType()) {
- case TYPE_TECHNOLOGY -> result.add(
- new RoutingTableTechnologyEntry(entry.getNfceeId(),
- RoutingTableTechnologyEntry.techStringToInt(entry.getEntry()),
- routeStringToInt(entry.getRoutingType()))
- );
- case TYPE_PROTOCOL -> result.add(
- new RoutingTableProtocolEntry(entry.getNfceeId(),
- RoutingTableProtocolEntry.protocolStringToInt(entry.getEntry()),
- routeStringToInt(entry.getRoutingType()))
- );
- case TYPE_AID -> result.add(
- new RoutingTableAidEntry(entry.getNfceeId(), entry.getEntry(),
- routeStringToInt(entry.getRoutingType()))
- );
- case TYPE_SYSTEMCODE -> result.add(
- new RoutingTableSystemCodeEntry(entry.getNfceeId(),
- entry.getEntry().getBytes(StandardCharsets.UTF_8),
- routeStringToInt(entry.getRoutingType()))
- );
- }
- }
- return result;
- }
-
- /**
- * API to force a routing table commit.
- * @return a {@link StatusCode} to indicate if commit routing succeeded or not
- */
- @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @CommitRoutingStatusCode
- public int forceRoutingTableCommit() {
- return NfcAdapter.callServiceReturn(
- () -> NfcAdapter.sService.commitRouting(), COMMIT_ROUTING_STATUS_FAILED);
- }
-
- private final class NfcOemExtensionCallback extends INfcOemExtensionCallback.Stub {
-
- @Override
- public void onTagConnected(boolean connected) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(connected, cb::onTagConnected, ex));
- }
-
- @Override
- public void onCardEmulationActivated(boolean isActivated) throws RemoteException {
- mCardEmulationActivated = isActivated;
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(isActivated, cb::onCardEmulationActivated, ex));
- }
-
- @Override
- public void onRfFieldDetected(boolean isActive) throws RemoteException {
- mRfFieldActivated = isActive;
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(isActive, cb::onRfFieldDetected, ex));
- }
-
- @Override
- public void onRfDiscoveryStarted(boolean isDiscoveryStarted) throws RemoteException {
- mRfDiscoveryStarted = isDiscoveryStarted;
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(isDiscoveryStarted, cb::onRfDiscoveryStarted, ex));
- }
-
- @Override
- public void onEeListenActivated(boolean isActivated) throws RemoteException {
- mEeListenActivated = isActivated;
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(isActivated, cb::onEeListenActivated, ex));
- }
-
- @Override
- public void onEeUpdated() throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(null, (Object input) -> cb.onEeUpdated(), ex));
- }
-
- @Override
- public void onStateUpdated(int state) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(state, cb::onStateUpdated, ex));
- }
-
- @Override
- public void onApplyRouting(ResultReceiver isSkipped) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(
- new ReceiverWrapper<>(isSkipped), cb::onApplyRouting, ex));
- }
- @Override
- public void onNdefRead(ResultReceiver isSkipped) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(
- new ReceiverWrapper<>(isSkipped), cb::onNdefRead, ex));
- }
- @Override
- public void onEnable(ResultReceiver isAllowed) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(
- new ReceiverWrapper<>(isAllowed), cb::onEnableRequested, ex));
- }
- @Override
- public void onDisable(ResultReceiver isAllowed) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(
- new ReceiverWrapper<>(isAllowed), cb::onDisableRequested, ex));
- }
- @Override
- public void onBootStarted() throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(null, (Object input) -> cb.onBootStarted(), ex));
- }
- @Override
- public void onEnableStarted() throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(null, (Object input) -> cb.onEnableStarted(), ex));
- }
- @Override
- public void onDisableStarted() throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(null, (Object input) -> cb.onDisableStarted(), ex));
- }
- @Override
- public void onBootFinished(int status) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(status, cb::onBootFinished, ex));
- }
- @Override
- public void onEnableFinished(int status) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(status, cb::onEnableFinished, ex));
- }
- @Override
- public void onDisableFinished(int status) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(status, cb::onDisableFinished, ex));
- }
- @Override
- public void onTagDispatch(ResultReceiver isSkipped) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(
- new ReceiverWrapper<>(isSkipped), cb::onTagDispatch, ex));
- }
- @Override
- public void onRoutingChanged(ResultReceiver isSkipped) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(
- new ReceiverWrapper<>(isSkipped), cb::onRoutingChanged, ex));
- }
- @Override
- public void onHceEventReceived(int action) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(action, cb::onHceEventReceived, ex));
- }
-
- @Override
- public void onReaderOptionChanged(boolean enabled) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(enabled, cb::onReaderOptionChanged, ex));
- }
-
- public void onRoutingTableFull() throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(null,
- (Object input) -> cb.onRoutingTableFull(), ex));
- }
-
- @Override
- public void onGetOemAppSearchIntent(List<String> packages, ResultReceiver intentConsumer)
- throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoid2ArgCallback(packages, new ReceiverWrapper<>(intentConsumer),
- cb::onGetOemAppSearchIntent, ex));
- }
-
- @Override
- public void onNdefMessage(Tag tag, NdefMessage message,
- ResultReceiver hasOemExecutableContent) throws RemoteException {
- mCallbackMap.forEach((cb, ex) -> {
- synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- try {
- ex.execute(() -> cb.onNdefMessage(
- tag, message, new ReceiverWrapper<>(hasOemExecutableContent)));
- } catch (RuntimeException exception) {
- throw exception;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- });
- }
-
- @Override
- public void onLaunchHceAppChooserActivity(String selectedAid,
- List<ApduServiceInfo> services,
- ComponentName failedComponent, String category)
- throws RemoteException {
- mCallbackMap.forEach((cb, ex) -> {
- synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- try {
- ex.execute(() -> cb.onLaunchHceAppChooserActivity(
- selectedAid, services, failedComponent, category));
- } catch (RuntimeException exception) {
- throw exception;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- });
- }
-
- @Override
- public void onLaunchHceTapAgainActivity(ApduServiceInfo service, String category)
- throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoid2ArgCallback(service, category, cb::onLaunchHceTapAgainDialog, ex));
- }
-
- @Override
- public void onLogEventNotified(OemLogItems item) throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoidCallback(item, cb::onLogEventNotified, ex));
- }
-
- @Override
- public void onExtractOemPackages(NdefMessage message, ResultReceiver packageConsumer)
- throws RemoteException {
- mCallbackMap.forEach((cb, ex) ->
- handleVoid2ArgCallback(message,
- new ReceiverWrapper<>(packageConsumer),
- cb::onExtractOemPackages, ex));
- }
-
- private <T> void handleVoidCallback(
- T input, Consumer<T> callbackMethod, Executor executor) {
- synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> callbackMethod.accept(input));
- } catch (RuntimeException ex) {
- throw ex;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- private <T1, T2> void handleVoid2ArgCallback(
- T1 input1, T2 input2, BiConsumer<T1, T2> callbackMethod, Executor executor) {
- synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> callbackMethod.accept(input1, input2));
- } catch (RuntimeException ex) {
- throw ex;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- private <S, T> S handleNonVoidCallbackWithInput(
- S defaultValue, T input, Function<T, S> callbackMethod) throws RemoteException {
- synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- S result = defaultValue;
- try {
- ExecutorService executor = Executors.newSingleThreadExecutor();
- FutureTask<S> futureTask = new FutureTask<>(() -> callbackMethod.apply(input));
- var unused = executor.submit(futureTask);
- try {
- result = futureTask.get(
- OEM_EXTENSION_RESPONSE_THRESHOLD_MS, TimeUnit.MILLISECONDS);
- } catch (ExecutionException | InterruptedException e) {
- e.printStackTrace();
- } catch (TimeoutException e) {
- Log.w(TAG, "Callback timed out: " + callbackMethod);
- e.printStackTrace();
- } finally {
- executor.shutdown();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return result;
- }
- }
-
- private <T> T handleNonVoidCallbackWithoutInput(T defaultValue, Supplier<T> callbackMethod)
- throws RemoteException {
- synchronized (mLock) {
- final long identity = Binder.clearCallingIdentity();
- T result = defaultValue;
- try {
- ExecutorService executor = Executors.newSingleThreadExecutor();
- FutureTask<T> futureTask = new FutureTask<>(callbackMethod::get);
- var unused = executor.submit(futureTask);
- try {
- result = futureTask.get(
- OEM_EXTENSION_RESPONSE_THRESHOLD_MS, TimeUnit.MILLISECONDS);
- } catch (ExecutionException | InterruptedException e) {
- e.printStackTrace();
- } catch (TimeoutException e) {
- Log.w(TAG, "Callback timed out: " + callbackMethod);
- e.printStackTrace();
- } finally {
- executor.shutdown();
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return result;
- }
- }
- }
-
- private @CardEmulation.ProtocolAndTechnologyRoute int routeStringToInt(String route) {
- if (route.equals("DH")) {
- return PROTOCOL_AND_TECHNOLOGY_ROUTE_DH;
- } else if (route.startsWith("eSE")) {
- return PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE;
- } else if (route.startsWith("SIM")) {
- return PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC;
- } else {
- throw new IllegalStateException("Unexpected value: " + route);
- }
- }
-
- private class ReceiverWrapper<T> implements Consumer<T> {
- private final ResultReceiver mResultReceiver;
-
- ReceiverWrapper(ResultReceiver resultReceiver) {
- mResultReceiver = resultReceiver;
- }
-
- @Override
- public void accept(T result) {
- if (result instanceof Boolean) {
- mResultReceiver.send((Boolean) result ? 1 : 0, null);
- } else if (result instanceof Intent) {
- Bundle bundle = new Bundle();
- bundle.putParcelable("intent", (Intent) result);
- mResultReceiver.send(0, bundle);
- } else if (result instanceof List<?> list) {
- if (list.stream().allMatch(String.class::isInstance)) {
- Bundle bundle = new Bundle();
- bundle.putStringArray("packageNames",
- list.stream().map(pkg -> (String) pkg).toArray(String[]::new));
- mResultReceiver.send(0, bundle);
- }
- }
- }
-
- @Override
- public Consumer<T> andThen(Consumer<? super T> after) {
- return Consumer.super.andThen(after);
- }
- }
-}
diff --git a/nfc/java/android/nfc/NfcRoutingTableEntry.java b/nfc/java/android/nfc/NfcRoutingTableEntry.java
deleted file mode 100644
index 4153779a8ba2..000000000000
--- a/nfc/java/android/nfc/NfcRoutingTableEntry.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-import android.nfc.cardemulation.CardEmulation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Class to represent an entry of routing table. This class is abstract and extended by
- * {@link RoutingTableTechnologyEntry}, {@link RoutingTableProtocolEntry},
- * {@link RoutingTableAidEntry} and {@link RoutingTableSystemCodeEntry}.
- *
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public abstract class NfcRoutingTableEntry {
- private final int mNfceeId;
- private final int mType;
- private final int mRouteType;
-
- /**
- * AID routing table type.
- */
- public static final int TYPE_AID = 0;
- /**
- * Protocol routing table type.
- */
- public static final int TYPE_PROTOCOL = 1;
- /**
- * Technology routing table type.
- */
- public static final int TYPE_TECHNOLOGY = 2;
- /**
- * System Code routing table type.
- */
- public static final int TYPE_SYSTEM_CODE = 3;
-
- /**
- * Possible type of this routing table entry.
- * @hide
- */
- @IntDef(prefix = "TYPE_", value = {
- TYPE_AID,
- TYPE_PROTOCOL,
- TYPE_TECHNOLOGY,
- TYPE_SYSTEM_CODE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface RoutingTableType {}
-
- /** @hide */
- protected NfcRoutingTableEntry(int nfceeId, @RoutingTableType int type,
- @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
- mNfceeId = nfceeId;
- mType = type;
- mRouteType = routeType;
- }
-
- /**
- * Gets the NFCEE Id of this entry.
- * @return an integer of NFCEE Id.
- */
- public int getNfceeId() {
- return mNfceeId;
- }
-
- /**
- * Get the type of this entry.
- * @return an integer defined in {@link RoutingTableType}
- */
- @RoutingTableType
- public int getType() {
- return mType;
- }
-
- /**
- * Get the route type of this entry.
- * @return an integer defined in
- * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute}
- */
- @CardEmulation.ProtocolAndTechnologyRoute
- public int getRouteType() {
- return mRouteType;
- }
-}
diff --git a/nfc/java/android/nfc/NfcVendorNciCallbackListener.java b/nfc/java/android/nfc/NfcVendorNciCallbackListener.java
deleted file mode 100644
index 742d75fe4bc3..000000000000
--- a/nfc/java/android/nfc/NfcVendorNciCallbackListener.java
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.NonNull;
-import android.nfc.NfcAdapter.NfcVendorNciCallback;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public final class NfcVendorNciCallbackListener extends INfcVendorNciCallback.Stub {
- private static final String TAG = "Nfc.NfcVendorNciCallbacks";
- private final INfcAdapter mAdapter;
- private boolean mIsRegistered = false;
- private final Map<NfcVendorNciCallback, Executor> mCallbackMap = new HashMap<>();
-
- public NfcVendorNciCallbackListener(@NonNull INfcAdapter adapter) {
- mAdapter = adapter;
- }
-
- public void register(@NonNull Executor executor, @NonNull NfcVendorNciCallback callback) {
- synchronized (this) {
- if (mCallbackMap.containsKey(callback)) {
- return;
- }
- mCallbackMap.put(callback, executor);
- if (!mIsRegistered) {
- try {
- mAdapter.registerVendorExtensionCallback(this);
- mIsRegistered = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to register adapter state callback");
- mCallbackMap.remove(callback);
- throw e.rethrowFromSystemServer();
- }
- }
- }
- }
-
- public void unregister(@NonNull NfcVendorNciCallback callback) {
- synchronized (this) {
- if (!mCallbackMap.containsKey(callback) || !mIsRegistered) {
- return;
- }
- if (mCallbackMap.size() == 1) {
- try {
- mAdapter.unregisterVendorExtensionCallback(this);
- mIsRegistered = false;
- mCallbackMap.remove(callback);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to unregister AdapterStateCallback with service");
- throw e.rethrowFromSystemServer();
- }
- } else {
- mCallbackMap.remove(callback);
- }
- }
- }
-
- @Override
- public void onVendorResponseReceived(int gid, int oid, @NonNull byte[] payload)
- throws RemoteException {
- synchronized (this) {
- final long identity = Binder.clearCallingIdentity();
- try {
- for (NfcVendorNciCallback callback : mCallbackMap.keySet()) {
- Executor executor = mCallbackMap.get(callback);
- executor.execute(() -> callback.onVendorNciResponse(gid, oid, payload));
- }
- } catch (RuntimeException ex) {
- throw ex;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- @Override
- public void onVendorNotificationReceived(int gid, int oid, @NonNull byte[] payload)
- throws RemoteException {
- synchronized (this) {
- final long identity = Binder.clearCallingIdentity();
- try {
- for (NfcVendorNciCallback callback : mCallbackMap.keySet()) {
- Executor executor = mCallbackMap.get(callback);
- executor.execute(() -> callback.onVendorNciNotification(gid, oid, payload));
- }
- } catch (RuntimeException ex) {
- throw ex;
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-}
diff --git a/nfc/java/android/nfc/NfcWlcStateListener.java b/nfc/java/android/nfc/NfcWlcStateListener.java
deleted file mode 100644
index 890cb090f587..000000000000
--- a/nfc/java/android/nfc/NfcWlcStateListener.java
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 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.nfc;
-
-import android.annotation.NonNull;
-import android.nfc.NfcAdapter.WlcStateListener;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.Executor;
-
-/**
- * @hide
- */
-public class NfcWlcStateListener extends INfcWlcStateListener.Stub {
- private static final String TAG = NfcWlcStateListener.class.getSimpleName();
-
- private final INfcAdapter mAdapter;
-
- private final Map<WlcStateListener, Executor> mListenerMap = new HashMap<>();
-
- private WlcListenerDeviceInfo mCurrentState = null;
- private boolean mIsRegistered = false;
-
- public NfcWlcStateListener(@NonNull INfcAdapter adapter) {
- mAdapter = adapter;
- }
-
- /**
- * Register a {@link WlcStateListener} with this
- * {@link WlcStateListener}
- *
- * @param executor an {@link Executor} to execute given listener
- * @param listener user implementation of the {@link WlcStateListener}
- */
- public void register(@NonNull Executor executor, @NonNull WlcStateListener listener) {
- synchronized (this) {
- if (mListenerMap.containsKey(listener)) {
- return;
- }
-
- mListenerMap.put(listener, executor);
-
- if (!mIsRegistered) {
- try {
- mAdapter.registerWlcStateListener(this);
- mIsRegistered = true;
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to register");
- }
- }
- }
- }
-
- /**
- * Unregister the specified {@link WlcStateListener}
- *
- * @param listener user implementation of the {@link WlcStateListener}
- */
- public void unregister(@NonNull WlcStateListener listener) {
- synchronized (this) {
- if (!mListenerMap.containsKey(listener)) {
- return;
- }
-
- mListenerMap.remove(listener);
-
- if (mListenerMap.isEmpty() && mIsRegistered) {
- try {
- mAdapter.unregisterWlcStateListener(this);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to unregister");
- }
- mIsRegistered = false;
- }
- }
- }
-
- private void sendCurrentState(@NonNull WlcStateListener listener) {
- synchronized (this) {
- Executor executor = mListenerMap.get(listener);
- final long identity = Binder.clearCallingIdentity();
- try {
- if (Flags.enableNfcCharging()) {
- executor.execute(() -> listener.onWlcStateChanged(
- mCurrentState));
- }
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- }
- }
-
- @Override
- public void onWlcStateChanged(@NonNull WlcListenerDeviceInfo wlcListenerDeviceInfo) {
- synchronized (this) {
- mCurrentState = wlcListenerDeviceInfo;
-
- for (WlcStateListener cb : mListenerMap.keySet()) {
- sendCurrentState(cb);
- }
- }
- }
-}
-
diff --git a/nfc/java/android/nfc/OemLogItems.aidl b/nfc/java/android/nfc/OemLogItems.aidl
deleted file mode 100644
index 3bcb445fc7d2..000000000000
--- a/nfc/java/android/nfc/OemLogItems.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-parcelable OemLogItems; \ No newline at end of file
diff --git a/nfc/java/android/nfc/OemLogItems.java b/nfc/java/android/nfc/OemLogItems.java
deleted file mode 100644
index 4f3e1999f5d3..000000000000
--- a/nfc/java/android/nfc/OemLogItems.java
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.time.Instant;
-
-/**
- * A log class for OEMs to get log information of NFC events.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public final class OemLogItems implements Parcelable {
- /**
- * Used when RF field state is changed.
- */
- public static final int LOG_ACTION_RF_FIELD_STATE_CHANGED = 0X01;
- /**
- * Used when NFC is toggled. Event should be set to {@link LogEvent#EVENT_ENABLE} or
- * {@link LogEvent#EVENT_DISABLE} if this action is used.
- */
- public static final int LOG_ACTION_NFC_TOGGLE = 0x0201;
- /**
- * Used when sending host routing status.
- */
- public static final int LOG_ACTION_HCE_DATA = 0x0204;
- /**
- * Used when screen state is changed.
- */
- public static final int LOG_ACTION_SCREEN_STATE_CHANGED = 0x0206;
- /**
- * Used when tag is detected.
- */
- public static final int LOG_ACTION_TAG_DETECTED = 0x03;
-
- /**
- * @hide
- */
- @IntDef(prefix = { "LOG_ACTION_" }, value = {
- LOG_ACTION_RF_FIELD_STATE_CHANGED,
- LOG_ACTION_NFC_TOGGLE,
- LOG_ACTION_HCE_DATA,
- LOG_ACTION_SCREEN_STATE_CHANGED,
- LOG_ACTION_TAG_DETECTED,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LogAction {}
-
- /**
- * Represents the event is not set.
- */
- public static final int EVENT_UNSET = 0;
- /**
- * Represents nfc enable is called.
- */
- public static final int EVENT_ENABLE = 1;
- /**
- * Represents nfc disable is called.
- */
- public static final int EVENT_DISABLE = 2;
- /** @hide */
- @IntDef(prefix = { "EVENT_" }, value = {
- EVENT_UNSET,
- EVENT_ENABLE,
- EVENT_DISABLE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface LogEvent {}
- private int mAction;
- private int mEvent;
- private int mCallingPid;
- private byte[] mCommandApdus;
- private byte[] mResponseApdus;
- private Instant mRfFieldOnTime;
- private Tag mTag;
-
- /** @hide */
- public OemLogItems(@LogAction int action, @LogEvent int event, int callingPid,
- byte[] commandApdus, byte[] responseApdus, Instant rfFieldOnTime,
- Tag tag) {
- mAction = action;
- mEvent = event;
- mTag = tag;
- mCallingPid = callingPid;
- mCommandApdus = commandApdus;
- mResponseApdus = responseApdus;
- mRfFieldOnTime = rfFieldOnTime;
- }
-
- /**
- * Describe the kinds of special objects contained in this Parcelable
- * instance's marshaled representation. For example, if the object will
- * include a file descriptor in the output of {@link #writeToParcel(Parcel, int)},
- * the return value of this method must include the
- * {@link #CONTENTS_FILE_DESCRIPTOR} bit.
- *
- * @return a bitmask indicating the set of special object types marshaled
- * by this Parcelable object instance.
- */
- @Override
- public int describeContents() {
- return 0;
- }
-
- /**
- * Flatten this object in to a Parcel.
- *
- * @param dest The Parcel in which the object should be written.
- * @param flags Additional flags about how the object should be written.
- * May be 0 or {@link #PARCELABLE_WRITE_RETURN_VALUE}.
- */
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mAction);
- dest.writeInt(mEvent);
- dest.writeInt(mCallingPid);
- dest.writeInt(mCommandApdus.length);
- dest.writeByteArray(mCommandApdus);
- dest.writeInt(mResponseApdus.length);
- dest.writeByteArray(mResponseApdus);
- dest.writeBoolean(mRfFieldOnTime != null);
- if (mRfFieldOnTime != null) {
- dest.writeLong(mRfFieldOnTime.getEpochSecond());
- dest.writeInt(mRfFieldOnTime.getNano());
- }
- dest.writeParcelable(mTag, 0);
- }
-
- /** @hide */
- public static class Builder {
- private final OemLogItems mItem;
-
- public Builder(@LogAction int type) {
- mItem = new OemLogItems(type, EVENT_UNSET, 0, new byte[0], new byte[0], null, null);
- }
-
- /** Setter of the log action. */
- public OemLogItems.Builder setAction(@LogAction int action) {
- mItem.mAction = action;
- return this;
- }
-
- /** Setter of the log calling event. */
- public OemLogItems.Builder setCallingEvent(@LogEvent int event) {
- mItem.mEvent = event;
- return this;
- }
-
- /** Setter of the log calling Pid. */
- public OemLogItems.Builder setCallingPid(int pid) {
- mItem.mCallingPid = pid;
- return this;
- }
-
- /** Setter of APDU command. */
- public OemLogItems.Builder setApduCommand(byte[] apdus) {
- mItem.mCommandApdus = apdus;
- return this;
- }
-
- /** Setter of RF field on time. */
- public OemLogItems.Builder setRfFieldOnTime(Instant time) {
- mItem.mRfFieldOnTime = time;
- return this;
- }
-
- /** Setter of APDU response. */
- public OemLogItems.Builder setApduResponse(byte[] apdus) {
- mItem.mResponseApdus = apdus;
- return this;
- }
-
- /** Setter of dispatched tag. */
- public OemLogItems.Builder setTag(Tag tag) {
- mItem.mTag = tag;
- return this;
- }
-
- /** Builds an {@link OemLogItems} instance. */
- public OemLogItems build() {
- return mItem;
- }
- }
-
- /**
- * Gets the action of this log.
- * @return one of {@link LogAction}
- */
- @LogAction
- public int getAction() {
- return mAction;
- }
-
- /**
- * Gets the event of this log. This will be set to {@link LogEvent#EVENT_ENABLE} or
- * {@link LogEvent#EVENT_DISABLE} only when action is set to
- * {@link LogAction#LOG_ACTION_NFC_TOGGLE}
- * @return one of {@link LogEvent}
- */
- @LogEvent
- public int getEvent() {
- return mEvent;
- }
-
- /**
- * Gets the calling Pid of this log. This field will be set only when action is set to
- * {@link LogAction#LOG_ACTION_NFC_TOGGLE}
- * @return calling Pid
- */
- public int getCallingPid() {
- return mCallingPid;
- }
-
- /**
- * Gets the command APDUs of this log. This field will be set only when action is set to
- * {@link LogAction#LOG_ACTION_HCE_DATA}
- * @return a byte array of command APDUs with the same format as
- * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])}
- */
- @Nullable
- public byte[] getCommandApdu() {
- return mCommandApdus;
- }
-
- /**
- * Gets the response APDUs of this log. This field will be set only when action is set to
- * {@link LogAction#LOG_ACTION_HCE_DATA}
- * @return a byte array of response APDUs with the same format as
- * {@link android.nfc.cardemulation.HostApduService#sendResponseApdu(byte[])}
- */
- @Nullable
- public byte[] getResponseApdu() {
- return mResponseApdus;
- }
-
- /**
- * Gets the RF field event time in this log in millisecond. This field will be set only when
- * action is set to {@link LogAction#LOG_ACTION_RF_FIELD_STATE_CHANGED}
- * @return an {@link Instant} of RF field event time.
- */
- @Nullable
- public Instant getRfFieldEventTimeMillis() {
- return mRfFieldOnTime;
- }
-
- /**
- * Gets the tag of this log. This field will be set only when action is set to
- * {@link LogAction#LOG_ACTION_TAG_DETECTED}
- * @return a detected {@link Tag} in {@link #LOG_ACTION_TAG_DETECTED} case. Return
- * null otherwise.
- */
- @Nullable
- public Tag getTag() {
- return mTag;
- }
-
- private String byteToHex(byte[] bytes) {
- char[] HexArray = "0123456789ABCDEF".toCharArray();
- char[] hexChars = new char[bytes.length * 2];
- for (int j = 0; j < bytes.length; j++) {
- int v = bytes[j] & 0xFF;
- hexChars[j * 2] = HexArray[v >>> 4];
- hexChars[j * 2 + 1] = HexArray[v & 0x0F];
- }
- return new String(hexChars);
- }
-
- @Override
- public String toString() {
- return "[mCommandApdus: "
- + ((mCommandApdus != null) ? byteToHex(mCommandApdus) : "null")
- + "[mResponseApdus: "
- + ((mResponseApdus != null) ? byteToHex(mResponseApdus) : "null")
- + ", mCallingApi= " + mEvent
- + ", mAction= " + mAction
- + ", mCallingPId = " + mCallingPid
- + ", mRfFieldOnTime= " + mRfFieldOnTime;
- }
- private OemLogItems(Parcel in) {
- this.mAction = in.readInt();
- this.mEvent = in.readInt();
- this.mCallingPid = in.readInt();
- this.mCommandApdus = new byte[in.readInt()];
- in.readByteArray(this.mCommandApdus);
- this.mResponseApdus = new byte[in.readInt()];
- in.readByteArray(this.mResponseApdus);
- boolean isRfFieldOnTimeSet = in.readBoolean();
- if (isRfFieldOnTimeSet) {
- this.mRfFieldOnTime = Instant.ofEpochSecond(in.readLong(), in.readInt());
- } else {
- this.mRfFieldOnTime = null;
- }
- this.mTag = in.readParcelable(Tag.class.getClassLoader(), Tag.class);
- }
-
- public static final @NonNull Parcelable.Creator<OemLogItems> CREATOR =
- new Parcelable.Creator<OemLogItems>() {
- @Override
- public OemLogItems createFromParcel(Parcel in) {
- return new OemLogItems(in);
- }
-
- @Override
- public OemLogItems[] newArray(int size) {
- return new OemLogItems[size];
- }
- };
-
-}
diff --git a/nfc/java/android/nfc/Placeholder.java b/nfc/java/android/nfc/Placeholder.java
deleted file mode 100644
index 3509644ac106..000000000000
--- a/nfc/java/android/nfc/Placeholder.java
+++ /dev/null
@@ -1,27 +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.nfc;
-
-/**
- * Placeholder class so new framework-nfc module isn't empty, will be removed once module is
- * populated.
- *
- * @hide
- *
- */
-public class Placeholder {
-}
diff --git a/nfc/java/android/nfc/RoutingStatus.java b/nfc/java/android/nfc/RoutingStatus.java
deleted file mode 100644
index 4a1b1f3cecbc..000000000000
--- a/nfc/java/android/nfc/RoutingStatus.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.nfc.cardemulation.CardEmulation;
-
-/**
- * A class indicating default route, ISO-DEP route and off-host route.
- *
- * @hide
- */
-@SystemApi
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-public class RoutingStatus {
- private final @CardEmulation.ProtocolAndTechnologyRoute int mDefaultRoute;
- private final @CardEmulation.ProtocolAndTechnologyRoute int mDefaultIsoDepRoute;
- private final @CardEmulation.ProtocolAndTechnologyRoute int mDefaultOffHostRoute;
-
- RoutingStatus(@CardEmulation.ProtocolAndTechnologyRoute int mDefaultRoute,
- @CardEmulation.ProtocolAndTechnologyRoute int mDefaultIsoDepRoute,
- @CardEmulation.ProtocolAndTechnologyRoute int mDefaultOffHostRoute) {
- this.mDefaultRoute = mDefaultRoute;
- this.mDefaultIsoDepRoute = mDefaultIsoDepRoute;
- this.mDefaultOffHostRoute = mDefaultOffHostRoute;
- }
-
- /**
- * Getter of the default route.
- * @return an integer defined in
- * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute}
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @CardEmulation.ProtocolAndTechnologyRoute
- public int getDefaultRoute() {
- return mDefaultRoute;
- }
-
- /**
- * Getter of the default ISO-DEP route.
- * @return an integer defined in
- * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute}
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @CardEmulation.ProtocolAndTechnologyRoute
- public int getDefaultIsoDepRoute() {
- return mDefaultIsoDepRoute;
- }
-
- /**
- * Getter of the default off-host route.
- * @return an integer defined in
- * {@link android.nfc.cardemulation.CardEmulation.ProtocolAndTechnologyRoute}
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @CardEmulation.ProtocolAndTechnologyRoute
- public int getDefaultOffHostRoute() {
- return mDefaultOffHostRoute;
- }
-
-}
diff --git a/nfc/java/android/nfc/RoutingTableAidEntry.java b/nfc/java/android/nfc/RoutingTableAidEntry.java
deleted file mode 100644
index be94f9fc117c..000000000000
--- a/nfc/java/android/nfc/RoutingTableAidEntry.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.nfc.cardemulation.CardEmulation;
-
-/**
- * Represents an Application ID (AID) entry in current routing table.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public class RoutingTableAidEntry extends NfcRoutingTableEntry {
- private final String mValue;
-
- /** @hide */
- public RoutingTableAidEntry(int nfceeId, String value,
- @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
- super(nfceeId, TYPE_AID, routeType);
- this.mValue = value;
- }
-
- /**
- * Gets AID value.
- * @return String of AID
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @NonNull
- public String getAid() {
- return mValue;
- }
-}
diff --git a/nfc/java/android/nfc/RoutingTableProtocolEntry.java b/nfc/java/android/nfc/RoutingTableProtocolEntry.java
deleted file mode 100644
index a68d8c167865..000000000000
--- a/nfc/java/android/nfc/RoutingTableProtocolEntry.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-import android.nfc.cardemulation.CardEmulation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Represents a protocol entry in current routing table.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public class RoutingTableProtocolEntry extends NfcRoutingTableEntry {
- /**
- * Protocol undetermined.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_UNDETERMINED = 0;
- /**
- * T1T Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_T1T = 1;
- /**
- * T2T Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_T2T = 2;
- /**
- * T3T Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_T3T = 3;
- /**
- * ISO-DEP Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_ISO_DEP = 4;
- /**
- * DEP Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_NFC_DEP = 5;
- /**
- * T5T Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_T5T = 6;
- /**
- * NDEF Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_NDEF = 7;
- /**
- * Unsupported Protocol
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int PROTOCOL_UNSUPPORTED = -1;
-
- /**
- *
- * @hide
- */
- @IntDef(prefix = { "PROTOCOL_" }, value = {
- PROTOCOL_UNDETERMINED,
- PROTOCOL_T1T,
- PROTOCOL_T2T,
- PROTOCOL_T3T,
- PROTOCOL_ISO_DEP,
- PROTOCOL_NFC_DEP,
- PROTOCOL_T5T,
- PROTOCOL_NDEF,
- PROTOCOL_UNSUPPORTED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ProtocolValue {}
-
- private final @ProtocolValue int mValue;
-
- /** @hide */
- public RoutingTableProtocolEntry(int nfceeId, @ProtocolValue int value,
- @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
- super(nfceeId, TYPE_PROTOCOL, routeType);
- this.mValue = value;
- }
-
- /**
- * Gets Protocol value.
- * @return Protocol defined in {@link ProtocolValue}
- */
- @ProtocolValue
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public int getProtocol() {
- return mValue;
- }
-
- /** @hide */
- @ProtocolValue
- public static int protocolStringToInt(String protocolString) {
- return switch (protocolString) {
- case "PROTOCOL_T1T" -> PROTOCOL_T1T;
- case "PROTOCOL_T2T" -> PROTOCOL_T2T;
- case "PROTOCOL_T3T" -> PROTOCOL_T3T;
- case "PROTOCOL_ISO_DEP" -> PROTOCOL_ISO_DEP;
- case "PROTOCOL_NFC_DEP" -> PROTOCOL_NFC_DEP;
- case "PROTOCOL_T5T" -> PROTOCOL_T5T;
- case "PROTOCOL_NDEF" -> PROTOCOL_NDEF;
- case "PROTOCOL_UNDETERMINED" -> PROTOCOL_UNDETERMINED;
- default -> PROTOCOL_UNSUPPORTED;
- };
- }
-}
diff --git a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java b/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
deleted file mode 100644
index 06cc0a5f26f1..000000000000
--- a/nfc/java/android/nfc/RoutingTableSystemCodeEntry.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.nfc.cardemulation.CardEmulation;
-
-/**
- * Represents a system code entry in current routing table, where system codes are two-byte values
- * used in NFC-F technology (a type of NFC communication) to identify specific
- * device configurations.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public class RoutingTableSystemCodeEntry extends NfcRoutingTableEntry {
- private final byte[] mValue;
-
- /** @hide */
- public RoutingTableSystemCodeEntry(int nfceeId, byte[] value,
- @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
- super(nfceeId, TYPE_SYSTEM_CODE, routeType);
- this.mValue = value;
- }
-
- /**
- * Gets system code value.
- * @return Byte array of system code
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- @NonNull
- public byte[] getSystemCode() {
- return mValue;
- }
-}
diff --git a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java b/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
deleted file mode 100644
index 86239ce7a6b2..000000000000
--- a/nfc/java/android/nfc/RoutingTableTechnologyEntry.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.SystemApi;
-import android.nfc.cardemulation.CardEmulation;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Represents a technology entry in current routing table.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public class RoutingTableTechnologyEntry extends NfcRoutingTableEntry {
- /**
- * Technology-A.
- * <p>Tech-A is mostly used for payment and ticketing applications. It supports various
- * Tag platforms including Type 1, Type 2 and Type 4A tags. </p>
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int TECHNOLOGY_A = 0;
- /**
- * Technology-B which is based on ISO/IEC 14443-3 standard.
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int TECHNOLOGY_B = 1;
- /**
- * Technology-F.
- * <p>Tech-F is a standard which supports Type 3 Tags and NFC-DEP protocol etc.</p>
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int TECHNOLOGY_F = 2;
- /**
- * Technology-V.
- * <p>Tech-V is an NFC technology used for communication with passive tags that operate
- * at a longer range than other NFC technologies. </p>
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int TECHNOLOGY_V = 3;
- /**
- * Unsupported technology
- */
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public static final int TECHNOLOGY_UNSUPPORTED = -1;
-
- /**
- *
- * @hide
- */
- @IntDef(prefix = { "TECHNOLOGY_" }, value = {
- TECHNOLOGY_A,
- TECHNOLOGY_B,
- TECHNOLOGY_F,
- TECHNOLOGY_V,
- TECHNOLOGY_UNSUPPORTED
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface TechnologyValue{}
-
- private final @TechnologyValue int mValue;
-
- /** @hide */
- public RoutingTableTechnologyEntry(int nfceeId, @TechnologyValue int value,
- @CardEmulation.ProtocolAndTechnologyRoute int routeType) {
- super(nfceeId, TYPE_TECHNOLOGY, routeType);
- this.mValue = value;
- }
-
- /**
- * Gets technology value.
- * @return technology value
- */
- @TechnologyValue
- @FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
- public int getTechnology() {
- return mValue;
- }
-
- /** @hide */
- @TechnologyValue
- public static int techStringToInt(String tech) {
- return switch (tech) {
- case "TECHNOLOGY_A" -> TECHNOLOGY_A;
- case "TECHNOLOGY_B" -> TECHNOLOGY_B;
- case "TECHNOLOGY_F" -> TECHNOLOGY_F;
- case "TECHNOLOGY_V" -> TECHNOLOGY_V;
- default -> TECHNOLOGY_UNSUPPORTED;
- };
- }
-}
diff --git a/nfc/java/android/nfc/T4tNdefNfcee.java b/nfc/java/android/nfc/T4tNdefNfcee.java
deleted file mode 100644
index 05a30aad76fc..000000000000
--- a/nfc/java/android/nfc/T4tNdefNfcee.java
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.annotation.WorkerThread;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This class is used for performing T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
- * NFCEE (NFC Execution Environment) operations.
- * This can be used to write NDEF data to emulate a T4T tag in an NFCEE
- * (NFC Execution Environment - eSE, SIM, etc). Refer to the NFC forum specification
- * "NFCForum-TS-NCI-2.3 section 10.4" and "NFCForum-TS-T4T-1.1 section 4.2" for more details.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public final class T4tNdefNfcee {
- private static final String TAG = "NdefNfcee";
- static T4tNdefNfcee sNdefNfcee;
-
- private T4tNdefNfcee() {
- }
-
- /**
- * Helper to get an instance of this class.
- *
- * @return
- * @hide
- */
- @NonNull
- public static T4tNdefNfcee getInstance() {
- if (sNdefNfcee == null) {
- sNdefNfcee = new T4tNdefNfcee();
- }
- return sNdefNfcee;
- }
-
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data is successful.
- */
- public static final int WRITE_DATA_SUCCESS = 0;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to unknown reasons.
- */
- public static final int WRITE_DATA_ERROR_INTERNAL = -1;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to ongoing rf activity.
- */
- public static final int WRITE_DATA_ERROR_RF_ACTIVATED = -2;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to Nfc off.
- */
- public static final int WRITE_DATA_ERROR_NFC_NOT_ON = -3;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to invalid file id.
- */
- public static final int WRITE_DATA_ERROR_INVALID_FILE_ID = -4;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to invalid length.
- */
- public static final int WRITE_DATA_ERROR_INVALID_LENGTH = -5;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to core connection create failure.
- */
- public static final int WRITE_DATA_ERROR_CONNECTION_FAILED = -6;
- /**
- * Return flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to empty payload.
- */
- public static final int WRITE_DATA_ERROR_EMPTY_PAYLOAD = -7;
- /**
- * Returns flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail due to invalid ndef format.
- */
- public static final int WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED = -8;
- /**
- * Returns flag for {@link #writeData(int, byte[])}.
- * It indicates write data fail if a concurrent NDEF NFCEE operation is ongoing.
- */
- public static final int WRITE_DATA_ERROR_DEVICE_BUSY = -9;
-
- /**
- * Possible return values for {@link #writeData(int, byte[])}.
- *
- * @hide
- */
- @IntDef(prefix = { "WRITE_DATA_" }, value = {
- WRITE_DATA_SUCCESS,
- WRITE_DATA_ERROR_INTERNAL,
- WRITE_DATA_ERROR_RF_ACTIVATED,
- WRITE_DATA_ERROR_NFC_NOT_ON,
- WRITE_DATA_ERROR_INVALID_FILE_ID,
- WRITE_DATA_ERROR_INVALID_LENGTH,
- WRITE_DATA_ERROR_CONNECTION_FAILED,
- WRITE_DATA_ERROR_EMPTY_PAYLOAD,
- WRITE_DATA_ERROR_NDEF_VALIDATION_FAILED,
- WRITE_DATA_ERROR_DEVICE_BUSY,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface WriteDataStatus{}
-
- /**
- * This API performs writes of T4T data to NFCEE.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread.</p>
- * <p>Applications must send complete Ndef Message payload, do not need to fragment
- * the payload, it will be automatically fragmented and defragmented by
- * {@link #writeData} if it exceeds max message length limits</p>
- *
- * @param fileId File id (Refer NFC Forum Type 4 Tag Specification
- * Section 4.2 File Identifiers and Access Conditions
- * for more information) to which to write.
- * @param data This should be valid Ndef Message format.
- * Refer to Nfc forum NDEF specification NDEF Message section
- * @return status of the operation.
- * @hide
- */
- @SystemApi
- @WorkerThread
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public @WriteDataStatus int writeData(@IntRange(from = 0, to = 65535) int fileId,
- @NonNull byte[] data) {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sNdefNfceeService.writeData(fileId, data), WRITE_DATA_ERROR_INTERNAL);
- }
-
- /**
- * This API performs reading of T4T content of Nfcee.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread.</p>
- *
- * @param fileId File Id (Refer
- * Section 4.2 File Identifiers and Access Conditions
- * for more information) from which to read.
- * @return - Returns complete Ndef message if success
- * Refer to Nfc forum NDEF specification NDEF Message section
- * @throws IllegalStateException if read fails because the fileId is invalid
- * or if a concurrent operation is in progress.
- * @hide
- */
- @SystemApi
- @WorkerThread
- @NonNull
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public byte[] readData(@IntRange(from = 0, to = 65535) int fileId) {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sNdefNfceeService.readData(fileId), null);
- }
-
- /**
- * Return flag for {@link #clearNdefData()}.
- * It indicates clear data is successful.
- */
- public static final int CLEAR_DATA_SUCCESS = 1;
- /**
- * Return flag for {@link #clearNdefData()}.
- * It indicates clear data failed due to internal error while processing the clear.
- */
- public static final int CLEAR_DATA_FAILED_INTERNAL = 0;
- /**
- * Return flag for {@link #clearNdefData()}.
- * It indicates clear data failed if a concurrent NDEF NFCEE operation is ongoing.
- */
- public static final int CLEAR_DATA_FAILED_DEVICE_BUSY = -1;
-
-
- /**
- * Possible return values for {@link #clearNdefData()}.
- *
- * @hide
- */
- @IntDef(prefix = { "CLEAR_DATA_" }, value = {
- CLEAR_DATA_SUCCESS,
- CLEAR_DATA_FAILED_INTERNAL,
- CLEAR_DATA_FAILED_DEVICE_BUSY,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ClearDataStatus{}
-
- /**
- * This API will set all the T4T NDEF NFCEE data to zero.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread.
- *
- * <p>This API can be called regardless of NDEF file lock state.
- * </p>
- * @return status of the operation
- *
- * @hide
- */
- @SystemApi
- @WorkerThread
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public @ClearDataStatus int clearData() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sNdefNfceeService.clearNdefData(), CLEAR_DATA_FAILED_INTERNAL);
- }
-
- /**
- * Returns whether NDEF NFCEE operation is ongoing or not.
- *
- * @return true if NDEF NFCEE operation is ongoing, else false.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean isOperationOngoing() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sNdefNfceeService.isNdefOperationOngoing(), false);
- }
-
- /**
- * This Api is to check the status of NDEF NFCEE emulation feature is
- * supported or not.
- *
- * @return true if NDEF NFCEE emulation feature is supported, else false.
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- public boolean isSupported() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sNdefNfceeService.isNdefNfceeEmulationSupported(), false);
- }
-
- /**
- * This API performs reading of T4T NDEF NFCEE CC file content.
- *
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
- *
- * @return Returns CC file content if success or null if failed to read.
- * @throws IllegalStateException if the device is busy.
- * @hide
- */
- @SystemApi
- @WorkerThread
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @Nullable
- public T4tNdefNfceeCcFileInfo readCcfile() {
- return NfcAdapter.callServiceReturn(() ->
- NfcAdapter.sNdefNfceeService.readCcfile(), null);
- }
-}
diff --git a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java b/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
deleted file mode 100644
index ce67f8f9aea7..000000000000
--- a/nfc/java/android/nfc/T4tNdefNfceeCcFileInfo.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.IntRange;
-import android.annotation.NonNull;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * This class is used to represence T4T (Type-4 Tag) NDEF (NFC Data Exchange Format)
- * NFCEE (NFC Execution Environment) CC (Capability Container) File data.
- * The CC file stores metadata about the T4T tag being emulated.
- *
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
- * @hide
- */
-@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION)
-@SystemApi
-public final class T4tNdefNfceeCcFileInfo implements Parcelable {
- /**
- * Indicates the size of this capability container (called “CC File”)<p>
- */
- private int mCcLength;
- /**
- * Indicates the mapping specification version<p>
- */
- private int mVersion;
- /**
- * Indicates the NDEF File Identifier<p>
- */
- private int mFileId;
- /**
- * Indicates the maximum Max NDEF file size<p>
- */
- private int mMaxSize;
- /**
- * Indicates the read access condition<p>
- */
- private boolean mIsReadAllowed;
- /**
- * Indicates the write access condition<p>
- */
- private boolean mIsWriteAllowed;
-
- /**
- * Constructor to be used by NFC service and internal classes.
- * @hide
- */
- public T4tNdefNfceeCcFileInfo(int cclen, int version,
- int ndefFileId, int ndefMaxSize,
- boolean isReadAllowed, boolean isWriteAllowed) {
- mCcLength = cclen;
- mVersion = version;
- mFileId = ndefFileId;
- mMaxSize = ndefMaxSize;
- mIsReadAllowed = isReadAllowed;
- mIsWriteAllowed = isWriteAllowed;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mCcLength);
- dest.writeInt(mVersion);
- dest.writeInt(mFileId);
- dest.writeInt(mMaxSize);
- dest.writeBoolean(mIsReadAllowed);
- dest.writeBoolean(mIsWriteAllowed);
- }
-
- /**
- * Indicates the size of this capability container (called “CC File”).
- *
- * @return length of the CC file.
- */
- @IntRange(from = 0xf, to = 0x7fff)
- public int getCcFileLength() {
- return mCcLength;
- }
-
- /**
- * T4T tag mapping version 2.0.
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
- */
- public static final int VERSION_2_0 = 0x20;
- /**
- * T4T tag mapping version 2.0.
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.4" for more details.
- */
- public static final int VERSION_3_0 = 0x30;
-
- /**
- * Possible return values for {@link #getVersion()}.
- * @hide
- */
- @IntDef(prefix = { "VERSION_" }, value = {
- VERSION_2_0,
- VERSION_3_0,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Version{}
-
- /**
- * Indicates the mapping version of the T4T tag supported.
- *
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.5" for more details.
- *
- * @return version of the specification
- */
- @Version
- public int getVersion() {
- return mVersion;
- }
-
- /**
- * Indicates the NDEF File Identifier. This is the identifier used in the last invocation of
- * {@link T4tNdefNfcee#writeData(int, byte[])}
- *
- * @return FileId of the data stored or -1 if no data is present.
- */
- @IntRange(from = -1, to = 65535)
- public int getFileId() {
- return mFileId;
- }
-
- /**
- * Indicates the maximum size of T4T NDEF data that can be written to the NFCEE.
- *
- * @return max size of the contents.
- */
- @IntRange(from = 0x5, to = 0x7fff)
- public int getMaxSize() {
- return mMaxSize;
- }
-
- /**
- * Indicates the read access condition.
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
- * @return boolean true if read access is allowed, otherwise false.
- */
- public boolean isReadAllowed() {
- return mIsReadAllowed;
- }
-
- /**
- * Indicates the write access condition.
- * Refer to the NFC forum specification "NFCForum-TS-T4T-1.1 section 4.2" for more details.
- * @return boolean if write access is allowed, otherwise false.
- */
- public boolean isWriteAllowed() {
- return mIsWriteAllowed;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final @NonNull Parcelable.Creator<T4tNdefNfceeCcFileInfo> CREATOR =
- new Parcelable.Creator<>() {
- @Override
- public T4tNdefNfceeCcFileInfo createFromParcel(Parcel in) {
-
- // NdefNfceeCcFileInfo fields
- int cclen = in.readInt();
- int version = in.readInt();
- int ndefFileId = in.readInt();
- int ndefMaxSize = in.readInt();
- boolean isReadAllowed = in.readBoolean();
- boolean isWriteAllowed = in.readBoolean();
-
- return new T4tNdefNfceeCcFileInfo(cclen, version,
- ndefFileId, ndefMaxSize,
- isReadAllowed, isWriteAllowed);
- }
-
- @Override
- public T4tNdefNfceeCcFileInfo[] newArray(int size) {
- return new T4tNdefNfceeCcFileInfo[size];
- }
- };
-}
diff --git a/nfc/java/android/nfc/Tag.aidl b/nfc/java/android/nfc/Tag.aidl
deleted file mode 100644
index 312261ebe76d..000000000000
--- a/nfc/java/android/nfc/Tag.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-parcelable Tag; \ No newline at end of file
diff --git a/nfc/java/android/nfc/Tag.java b/nfc/java/android/nfc/Tag.java
deleted file mode 100644
index 500038f14d9d..000000000000
--- a/nfc/java/android/nfc/Tag.java
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc;
-
-import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.nfc.tech.IsoDep;
-import android.nfc.tech.MifareClassic;
-import android.nfc.tech.MifareUltralight;
-import android.nfc.tech.Ndef;
-import android.nfc.tech.NdefFormatable;
-import android.nfc.tech.NfcA;
-import android.nfc.tech.NfcB;
-import android.nfc.tech.NfcBarcode;
-import android.nfc.tech.NfcF;
-import android.nfc.tech.NfcV;
-import android.nfc.tech.TagTechnology;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.HashMap;
-
-/**
- * Represents an NFC tag that has been discovered.
- * <p>
- * {@link Tag} is an immutable object that represents the state of a NFC tag at
- * the time of discovery. It can be used as a handle to {@link TagTechnology} classes
- * to perform advanced operations, or directly queried for its ID via {@link #getId} and the
- * set of technologies it contains via {@link #getTechList}. Arrays passed to and
- * returned by this class are <em>not</em> cloned, so be careful not to modify them.
- * <p>
- * A new tag object is created every time a tag is discovered (comes into range), even
- * if it is the same physical tag. If a tag is removed and then returned into range, then
- * only the most recent tag object can be successfully used to create a {@link TagTechnology}.
- *
- * <h3>Tag Dispatch</h3>
- * When a tag is discovered, a {@link Tag} object is created and passed to a
- * single activity via the {@link NfcAdapter#EXTRA_TAG} extra in an
- * {@link android.content.Intent} via {@link Context#startActivity}. A four stage dispatch is used
- * to select the
- * most appropriate activity to handle the tag. The Android OS executes each stage in order,
- * and completes dispatch as soon as a single matching activity is found. If there are multiple
- * matching activities found at any one stage then the Android activity chooser dialog is shown
- * to allow the user to select the activity to receive the tag.
- *
- * <p>The Tag dispatch mechanism was designed to give a high probability of dispatching
- * a tag to the correct activity without showing the user an activity chooser dialog.
- * This is important for NFC interactions because they are very transient -- if a user has to
- * move the Android device to choose an application then the connection will likely be broken.
- *
- * <h4>1. Foreground activity dispatch</h4>
- * A foreground activity that has called
- * {@link NfcAdapter#enableForegroundDispatch NfcAdapter.enableForegroundDispatch()} is
- * given priority. See the documentation on
- * {@link NfcAdapter#enableForegroundDispatch NfcAdapter.enableForegroundDispatch()} for
- * its usage.
- * <h4>2. NDEF data dispatch</h4>
- * If the tag contains NDEF data the system inspects the first {@link NdefRecord} in the first
- * {@link NdefMessage}. If the record is a URI, SmartPoster, or MIME data
- * {@link Context#startActivity} is called with {@link NfcAdapter#ACTION_NDEF_DISCOVERED}. For URI
- * and SmartPoster records the URI is put into the intent's data field. For MIME records the MIME
- * type is put in the intent's type field. This allows activities to register to be launched only
- * when data they know how to handle is present on a tag. This is the preferred method of handling
- * data on a tag since NDEF data can be stored on many types of tags and doesn't depend on a
- * specific tag technology.
- * See {@link NfcAdapter#ACTION_NDEF_DISCOVERED} for more detail. If the tag does not contain
- * NDEF data, or if no activity is registered
- * for {@link NfcAdapter#ACTION_NDEF_DISCOVERED} with a matching data URI or MIME type then dispatch
- * moves to stage 3.
- * <h4>3. Tag Technology dispatch</h4>
- * {@link Context#startActivity} is called with {@link NfcAdapter#ACTION_TECH_DISCOVERED} to
- * dispatch the tag to an activity that can handle the technologies present on the tag.
- * Technologies are defined as sub-classes of {@link TagTechnology}, see the package
- * {@link android.nfc.tech}. The Android OS looks for an activity that can handle one or
- * more technologies in the tag. See {@link NfcAdapter#ACTION_TECH_DISCOVERED} for more detail.
- * <h4>4. Fall-back dispatch</h4>
- * If no activity has been matched then {@link Context#startActivity} is called with
- * {@link NfcAdapter#ACTION_TAG_DISCOVERED}. This is intended as a fall-back mechanism.
- * See {@link NfcAdapter#ACTION_TAG_DISCOVERED}.
- *
- * <h3>NFC Tag Background</h3>
- * An NFC tag is a passive NFC device, powered by the NFC field of this Android device while
- * it is in range. Tag's can come in many forms, such as stickers, cards, key fobs, or
- * even embedded in a more sophisticated device.
- * <p>
- * Tags can have a wide range of capabilities. Simple tags just offer read/write semantics,
- * and contain some one time
- * programmable areas to make read-only. More complex tags offer math operations
- * and per-sector access control and authentication. The most sophisticated tags
- * contain operating environments allowing complex interactions with the
- * code executing on the tag. Use {@link TagTechnology} classes to access a broad
- * range of capabilities available in NFC tags.
- * <p>
- */
-public final class Tag implements Parcelable {
- @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
- final byte[] mId;
- final int[] mTechList;
- final String[] mTechStringList;
- final Bundle[] mTechExtras;
- final int mServiceHandle; // for use by NFC service, 0 indicates a mock
- final long mCookie; // for accessibility checking
- final INfcTag mTagService; // interface to NFC service, will be null if mock tag
-
- int mConnectedTechnology;
-
- /**
- * Hidden constructor to be used by NFC service and internal classes.
- * @hide
- */
- public Tag(byte[] id, int[] techList, Bundle[] techListExtras, int serviceHandle,
- long cookie, INfcTag tagService) {
- if (techList == null) {
- throw new IllegalArgumentException("rawTargets cannot be null");
- }
- mId = id;
- mTechList = Arrays.copyOf(techList, techList.length);
- mTechStringList = generateTechStringList(techList);
- // Ensure mTechExtras is as long as mTechList
- mTechExtras = Arrays.copyOf(techListExtras, techList.length);
- mServiceHandle = serviceHandle;
- mCookie = cookie;
- mTagService = tagService;
- mConnectedTechnology = -1;
-
- if (tagService == null) {
- return;
- }
- }
-
- /**
- * Construct a mock Tag.
- * <p>This is an application constructed tag, so NfcAdapter methods on this Tag may fail
- * with {@link IllegalArgumentException} since it does not represent a physical Tag.
- * <p>This constructor might be useful for mock testing.
- * @param id The tag identifier, can be null
- * @param techList must not be null
- * @return freshly constructed tag
- * @hide
- */
- public static Tag createMockTag(byte[] id, int[] techList, Bundle[] techListExtras,
- long cookie) {
- // set serviceHandle to 0 and tagService to null to indicate mock tag
- return new Tag(id, techList, techListExtras, 0, cookie, null);
- }
-
- private String[] generateTechStringList(int[] techList) {
- final int size = techList.length;
- String[] strings = new String[size];
- for (int i = 0; i < size; i++) {
- switch (techList[i]) {
- case TagTechnology.ISO_DEP:
- strings[i] = IsoDep.class.getName();
- break;
- case TagTechnology.MIFARE_CLASSIC:
- strings[i] = MifareClassic.class.getName();
- break;
- case TagTechnology.MIFARE_ULTRALIGHT:
- strings[i] = MifareUltralight.class.getName();
- break;
- case TagTechnology.NDEF:
- strings[i] = Ndef.class.getName();
- break;
- case TagTechnology.NDEF_FORMATABLE:
- strings[i] = NdefFormatable.class.getName();
- break;
- case TagTechnology.NFC_A:
- strings[i] = NfcA.class.getName();
- break;
- case TagTechnology.NFC_B:
- strings[i] = NfcB.class.getName();
- break;
- case TagTechnology.NFC_F:
- strings[i] = NfcF.class.getName();
- break;
- case TagTechnology.NFC_V:
- strings[i] = NfcV.class.getName();
- break;
- case TagTechnology.NFC_BARCODE:
- strings[i] = NfcBarcode.class.getName();
- break;
- default:
- throw new IllegalArgumentException("Unknown tech type " + techList[i]);
- }
- }
- return strings;
- }
-
- static int[] getTechCodesFromStrings(String[] techStringList) throws IllegalArgumentException {
- if (techStringList == null) {
- throw new IllegalArgumentException("List cannot be null");
- }
- int[] techIntList = new int[techStringList.length];
- HashMap<String, Integer> stringToCodeMap = getTechStringToCodeMap();
- for (int i = 0; i < techStringList.length; i++) {
- Integer code = stringToCodeMap.get(techStringList[i]);
-
- if (code == null) {
- throw new IllegalArgumentException("Unknown tech type " + techStringList[i]);
- }
-
- techIntList[i] = code.intValue();
- }
- return techIntList;
- }
-
- private static HashMap<String, Integer> getTechStringToCodeMap() {
- HashMap<String, Integer> techStringToCodeMap = new HashMap<String, Integer>();
-
- techStringToCodeMap.put(IsoDep.class.getName(), TagTechnology.ISO_DEP);
- techStringToCodeMap.put(MifareClassic.class.getName(), TagTechnology.MIFARE_CLASSIC);
- techStringToCodeMap.put(MifareUltralight.class.getName(), TagTechnology.MIFARE_ULTRALIGHT);
- techStringToCodeMap.put(Ndef.class.getName(), TagTechnology.NDEF);
- techStringToCodeMap.put(NdefFormatable.class.getName(), TagTechnology.NDEF_FORMATABLE);
- techStringToCodeMap.put(NfcA.class.getName(), TagTechnology.NFC_A);
- techStringToCodeMap.put(NfcB.class.getName(), TagTechnology.NFC_B);
- techStringToCodeMap.put(NfcF.class.getName(), TagTechnology.NFC_F);
- techStringToCodeMap.put(NfcV.class.getName(), TagTechnology.NFC_V);
- techStringToCodeMap.put(NfcBarcode.class.getName(), TagTechnology.NFC_BARCODE);
-
- return techStringToCodeMap;
- }
-
- /**
- * For use by NfcService only.
- * @hide
- */
- @UnsupportedAppUsage
- public int getServiceHandle() {
- return mServiceHandle;
- }
-
- /**
- * For use by NfcService only.
- * @hide
- */
- public int[] getTechCodeList() {
- return mTechList;
- }
-
- /**
- * Get the Tag Identifier (if it has one).
- * <p>The tag identifier is a low level serial number, used for anti-collision
- * and identification.
- * <p> Most tags have a stable unique identifier
- * (UID), but some tags will generate a random ID every time they are discovered
- * (RID), and there are some tags with no ID at all (the byte array will be zero-sized).
- * <p> The size and format of an ID is specific to the RF technology used by the tag.
- * <p> This function retrieves the ID as determined at discovery time, and does not
- * perform any further RF communication or block.
- * @return ID as byte array, never null
- */
- public byte[] getId() {
- return mId;
- }
-
- /**
- * Get the technologies available in this tag, as fully qualified class names.
- * <p>
- * A technology is an implementation of the {@link TagTechnology} interface,
- * and can be instantiated by calling the static <code>get(Tag)</code>
- * method on the implementation with this Tag. The {@link TagTechnology}
- * object can then be used to perform advanced, technology-specific operations on a tag.
- * <p>
- * Android defines a mandatory set of technologies that must be correctly
- * enumerated by all Android NFC devices, and an optional
- * set of proprietary technologies.
- * See {@link TagTechnology} for more details.
- * <p>
- * The ordering of the returned array is undefined and should not be relied upon.
- * @return an array of fully-qualified {@link TagTechnology} class-names.
- */
- public String[] getTechList() {
- return mTechStringList;
- }
-
- /**
- * Rediscover the technologies available on this tag.
- * <p>
- * The technologies that are available on a tag may change due to
- * operations being performed on a tag. For example, formatting a
- * tag as NDEF adds the {@link Ndef} technology. The {@link rediscover}
- * method reenumerates the available technologies on the tag
- * and returns a new {@link Tag} object containing these technologies.
- * <p>
- * You may not be connected to any of this {@link Tag}'s technologies
- * when calling this method.
- * This method guarantees that you will be returned the same Tag
- * if it is still in the field.
- * <p>May cause RF activity and may block. Must not be called
- * from the main application thread. A blocked call will be canceled with
- * {@link IOException} by calling {@link #close} from another thread.
- * <p>Does not remove power from the RF field, so a tag having a random
- * ID should not change its ID.
- * @return the rediscovered tag object.
- * @throws IOException if the tag cannot be rediscovered
- * @hide
- */
- // TODO See if we need TagLostException
- // TODO Unhide for ICS
- // TODO Update documentation to make sure it matches with the final
- // implementation.
- public Tag rediscover() throws IOException {
- if (getConnectedTechnology() != -1) {
- throw new IllegalStateException("Close connection to the technology first!");
- }
-
- if (mTagService == null) {
- throw new IOException("Mock tags don't support this operation.");
- }
- try {
- Tag newTag = mTagService.rediscover(getServiceHandle());
- if (newTag != null) {
- return newTag;
- } else {
- throw new IOException("Failed to rediscover tag");
- }
- } catch (RemoteException e) {
- throw new IOException("NFC service dead");
- }
- }
-
-
- /** @hide */
- public boolean hasTech(int techType) {
- for (int tech : mTechList) {
- if (tech == techType) return true;
- }
- return false;
- }
-
- /** @hide */
- public Bundle getTechExtras(int tech) {
- int pos = -1;
- for (int idx = 0; idx < mTechList.length; idx++) {
- if (mTechList[idx] == tech) {
- pos = idx;
- break;
- }
- }
- if (pos < 0) {
- return null;
- }
-
- return mTechExtras[pos];
- }
-
- /** @hide */
- @UnsupportedAppUsage
- public INfcTag getTagService() {
- if (mTagService == null) {
- return null;
- }
-
- try {
- if (!mTagService.isTagUpToDate(mCookie)) {
- String id_str = "";
- for (int i = 0; i < mId.length; i++) {
- id_str = id_str + String.format("%02X ", mId[i]);
- }
- String msg = "Permission Denial: Tag ( ID: " + id_str + ") is out of date";
- throw new SecurityException(msg);
- }
- } catch (RemoteException e) {
- throw e.rethrowAsRuntimeException();
- }
- return mTagService;
- }
-
- /**
- * Human-readable description of the tag, for debugging.
- */
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder("TAG: Tech [");
- String[] techList = getTechList();
- int length = techList.length;
- for (int i = 0; i < length; i++) {
- sb.append(techList[i]);
- if (i < length - 1) {
- sb.append(", ");
- }
- }
- sb.append("]");
- return sb.toString();
- }
-
- /*package*/ static byte[] readBytesWithNull(Parcel in) {
- int len = in.readInt();
- byte[] result = null;
- if (len >= 0) {
- result = new byte[len];
- in.readByteArray(result);
- }
- return result;
- }
-
- /*package*/ static void writeBytesWithNull(Parcel out, byte[] b) {
- if (b == null) {
- out.writeInt(-1);
- return;
- }
- out.writeInt(b.length);
- out.writeByteArray(b);
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- // Null mTagService means this is a mock tag
- int isMock = (mTagService == null)?1:0;
-
- writeBytesWithNull(dest, mId);
- dest.writeInt(mTechList.length);
- dest.writeIntArray(mTechList);
- dest.writeTypedArray(mTechExtras, 0);
- dest.writeInt(mServiceHandle);
- dest.writeLong(mCookie);
- dest.writeInt(isMock);
- if (isMock == 0) {
- dest.writeStrongBinder(mTagService.asBinder());
- }
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<Tag> CREATOR =
- new Parcelable.Creator<Tag>() {
- @Override
- public Tag createFromParcel(Parcel in) {
- INfcTag tagService;
-
- // Tag fields
- byte[] id = Tag.readBytesWithNull(in);
- int[] techList = new int[in.readInt()];
- in.readIntArray(techList);
- Bundle[] techExtras = in.createTypedArray(Bundle.CREATOR);
- int serviceHandle = in.readInt();
- long cookie = in.readLong();
- int isMock = in.readInt();
- if (isMock == 0) {
- tagService = INfcTag.Stub.asInterface(in.readStrongBinder());
- }
- else {
- tagService = null;
- }
-
- return new Tag(id, techList, techExtras, serviceHandle, cookie, tagService);
- }
-
- @Override
- public Tag[] newArray(int size) {
- return new Tag[size];
- }
- };
-
- /**
- * For internal use only.
- *
- * @hide
- */
- public synchronized boolean setConnectedTechnology(int technology) {
- if (mConnectedTechnology != -1) {
- return false;
- }
- mConnectedTechnology = technology;
- return true;
- }
-
- /**
- * For internal use only.
- *
- * @hide
- */
- public int getConnectedTechnology() {
- return mConnectedTechnology;
- }
-
- /**
- * For internal use only.
- *
- * @hide
- */
- public void setTechnologyDisconnected() {
- mConnectedTechnology = -1;
- }
-}
diff --git a/nfc/java/android/nfc/TagLostException.java b/nfc/java/android/nfc/TagLostException.java
deleted file mode 100644
index 1981d7c0c6e0..000000000000
--- a/nfc/java/android/nfc/TagLostException.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2011, 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.nfc;
-
-import java.io.IOException;
-
-public class TagLostException extends IOException {
- public TagLostException() {
- super();
- }
-
- public TagLostException(String message) {
- super(message);
- }
-}
diff --git a/nfc/java/android/nfc/TechListParcel.aidl b/nfc/java/android/nfc/TechListParcel.aidl
deleted file mode 100644
index 92e646f220f0..000000000000
--- a/nfc/java/android/nfc/TechListParcel.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-parcelable TechListParcel; \ No newline at end of file
diff --git a/nfc/java/android/nfc/TechListParcel.java b/nfc/java/android/nfc/TechListParcel.java
deleted file mode 100644
index 9f01559bd344..000000000000
--- a/nfc/java/android/nfc/TechListParcel.java
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class TechListParcel implements Parcelable {
-
- private String[][] mTechLists;
-
- public TechListParcel(String[]... strings) {
- mTechLists = strings;
- }
-
- public String[][] getTechLists() {
- return mTechLists;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- int count = mTechLists.length;
- dest.writeInt(count);
- for (int i = 0; i < count; i++) {
- String[] techList = mTechLists[i];
- dest.writeStringArray(techList);
- }
- }
-
- public static final @android.annotation.NonNull Creator<TechListParcel> CREATOR = new Creator<TechListParcel>() {
- @Override
- public TechListParcel createFromParcel(Parcel source) {
- int count = source.readInt();
- String[][] techLists = new String[count][];
- for (int i = 0; i < count; i++) {
- techLists[i] = source.createStringArray();
- }
- return new TechListParcel(techLists);
- }
-
- @Override
- public TechListParcel[] newArray(int size) {
- return new TechListParcel[size];
- }
- };
-}
diff --git a/nfc/java/android/nfc/TransceiveResult.aidl b/nfc/java/android/nfc/TransceiveResult.aidl
deleted file mode 100644
index 98f92ee03eef..000000000000
--- a/nfc/java/android/nfc/TransceiveResult.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2011 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.nfc;
-
-parcelable TransceiveResult;
diff --git a/nfc/java/android/nfc/TransceiveResult.java b/nfc/java/android/nfc/TransceiveResult.java
deleted file mode 100644
index 7992094e6ba1..000000000000
--- a/nfc/java/android/nfc/TransceiveResult.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (C) 2011, 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.nfc;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.io.IOException;
-
-/**
- * Class used to pipe transceive result from the NFC service.
- *
- * @hide
- */
-public final class TransceiveResult implements Parcelable {
- public static final int RESULT_SUCCESS = 0;
- public static final int RESULT_FAILURE = 1;
- public static final int RESULT_TAGLOST = 2;
- public static final int RESULT_EXCEEDED_LENGTH = 3;
-
- final int mResult;
- final byte[] mResponseData;
-
- public TransceiveResult(final int result, final byte[] data) {
- mResult = result;
- mResponseData = data;
- }
-
- public byte[] getResponseOrThrow() throws IOException {
- switch (mResult) {
- case RESULT_SUCCESS:
- return mResponseData;
- case RESULT_TAGLOST:
- throw new TagLostException("Tag was lost.");
- case RESULT_EXCEEDED_LENGTH:
- throw new IOException("Transceive length exceeds supported maximum");
- default:
- throw new IOException("Transceive failed");
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel dest, int flags) {
- dest.writeInt(mResult);
- if (mResult == RESULT_SUCCESS) {
- dest.writeInt(mResponseData.length);
- dest.writeByteArray(mResponseData);
- }
- }
-
- public static final @android.annotation.NonNull Parcelable.Creator<TransceiveResult> CREATOR =
- new Parcelable.Creator<TransceiveResult>() {
- @Override
- public TransceiveResult createFromParcel(Parcel in) {
- int result = in.readInt();
- byte[] responseData;
-
- if (result == RESULT_SUCCESS) {
- int responseLength = in.readInt();
- responseData = new byte[responseLength];
- in.readByteArray(responseData);
- } else {
- responseData = null;
- }
- return new TransceiveResult(result, responseData);
- }
-
- @Override
- public TransceiveResult[] newArray(int size) {
- return new TransceiveResult[size];
- }
- };
-
-}
diff --git a/nfc/java/android/nfc/WlcListenerDeviceInfo.aidl b/nfc/java/android/nfc/WlcListenerDeviceInfo.aidl
deleted file mode 100644
index 7f2ca545007b..000000000000
--- a/nfc/java/android/nfc/WlcListenerDeviceInfo.aidl
+++ /dev/null
@@ -1,19 +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.nfc;
-
-parcelable WlcListenerDeviceInfo;
diff --git a/nfc/java/android/nfc/WlcListenerDeviceInfo.java b/nfc/java/android/nfc/WlcListenerDeviceInfo.java
deleted file mode 100644
index 45315f812250..000000000000
--- a/nfc/java/android/nfc/WlcListenerDeviceInfo.java
+++ /dev/null
@@ -1,145 +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.nfc;
-
-import android.annotation.FlaggedApi;
-import android.annotation.FloatRange;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Contains information of the nfc wireless charging listener device information.
- */
-@FlaggedApi(Flags.FLAG_ENABLE_NFC_CHARGING)
-public final class WlcListenerDeviceInfo implements Parcelable {
- /**
- * Device is currently not connected with any WlcListenerDevice.
- */
- public static final int STATE_DISCONNECTED = 1;
-
- /**
- * Device is currently connected with a WlcListenerDevice and is charging it.
- */
- public static final int STATE_CONNECTED_CHARGING = 2;
-
- /**
- * Device is currently connected with a WlcListenerDevice without charging it.
- */
- public static final int STATE_CONNECTED_DISCHARGING = 3;
-
- /**
- * Possible states from {@link #getState}.
- * @hide
- */
- @IntDef(prefix = { "STATE_" }, value = {
- STATE_DISCONNECTED,
- STATE_CONNECTED_CHARGING,
- STATE_CONNECTED_DISCHARGING
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface WlcListenerState{}
-
- private int mProductId;
- private double mTemperature;
- private double mBatteryLevel;
- private int mState;
-
- /**
- * Create a new object containing wlc listener information.
- *
- * @param productId code for the device vendor
- * @param temperature current temperature
- * @param batteryLevel current battery level
- * @param state current state
- */
- public WlcListenerDeviceInfo(int productId, double temperature, double batteryLevel,
- @WlcListenerState int state) {
- this.mProductId = productId;
- this.mTemperature = temperature;
- this.mBatteryLevel = batteryLevel;
- this.mState = state;
- }
-
- /**
- * ProductId of the WLC listener device.
- * @return integer that is converted from USI Stylus VendorID[11:0].
- */
- public int getProductId() {
- return mProductId;
- }
-
- /**
- * Temperature of the WLC listener device.
- * @return the value represents the temperature in °C.
- */
- public double getTemperature() {
- return mTemperature;
- }
-
- /**
- * BatteryLevel of the WLC listener device.
- * @return battery level in percentage [0-100]
- */
- public @FloatRange(from = 0.0, to = 100.0) double getBatteryLevel() {
- return mBatteryLevel;
- }
-
- /**
- * State of the WLC listener device.
- */
- public @WlcListenerState int getState() {
- return mState;
- }
-
- private WlcListenerDeviceInfo(Parcel in) {
- this.mProductId = in.readInt();
- this.mTemperature = in.readDouble();
- this.mBatteryLevel = in.readDouble();
- this.mState = in.readInt();
- }
-
- public static final @NonNull Parcelable.Creator<WlcListenerDeviceInfo> CREATOR =
- new Parcelable.Creator<WlcListenerDeviceInfo>() {
- @Override
- public WlcListenerDeviceInfo createFromParcel(Parcel in) {
- return new WlcListenerDeviceInfo(in);
- }
-
- @Override
- public WlcListenerDeviceInfo[] newArray(int size) {
- return new WlcListenerDeviceInfo[size];
- }
- };
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mProductId);
- dest.writeDouble(mTemperature);
- dest.writeDouble(mBatteryLevel);
- dest.writeInt(mState);
- }
-}
diff --git a/nfc/java/android/nfc/cardemulation/CardEmulation.java b/nfc/java/android/nfc/cardemulation/CardEmulation.java
deleted file mode 100644
index fee9c5bfa328..000000000000
--- a/nfc/java/android/nfc/cardemulation/CardEmulation.java
+++ /dev/null
@@ -1,1497 +0,0 @@
-/*
- * Copyright (C) 2013 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.nfc.cardemulation;
-
-import android.Manifest;
-import android.annotation.CallbackExecutor;
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresFeature;
-import android.annotation.RequiresPermission;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SystemApi;
-import android.annotation.UserHandleAware;
-import android.annotation.UserIdInt;
-import android.app.Activity;
-import android.app.role.RoleManager;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.nfc.ComponentNameAndUser;
-import android.nfc.Constants;
-import android.nfc.Flags;
-import android.nfc.INfcCardEmulation;
-import android.nfc.INfcEventCallback;
-import android.nfc.NfcAdapter;
-import android.os.Build;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.telephony.SubscriptionManager;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HashMap;
-import java.util.HexFormat;
-import java.util.List;
-import java.util.Locale;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.regex.Pattern;
-
-/**
- * This class can be used to query the state of
- * NFC card emulation services.
- *
- * For a general introduction into NFC card emulation,
- * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
- * NFC card emulation developer guide</a>.</p>
- *
- * <p class="note">Use of this class requires the
- * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
- * on the device.
- */
-public final class CardEmulation {
- private static final Pattern AID_PATTERN = Pattern.compile("[0-9A-Fa-f]{10,32}\\*?\\#?");
- private static final Pattern PLPF_PATTERN = Pattern.compile("[0-9A-Fa-f,\\?,\\*\\.]*");
-
- static final String TAG = "CardEmulation";
-
- /**
- * Activity action: ask the user to change the default
- * card emulation service for a certain category. This will
- * show a dialog that asks the user whether they want to
- * replace the current default service with the service
- * identified with the ComponentName specified in
- * {@link #EXTRA_SERVICE_COMPONENT}, for the category
- * specified in {@link #EXTRA_CATEGORY}. There is an optional
- * extra field using {@link Intent#EXTRA_USER} to specify
- * the {@link UserHandle} of the user that owns the app.
- *
- * @deprecated Please use {@link android.app.role.RoleManager#createRequestRoleIntent(String)}
- * with {@link android.app.role.RoleManager#ROLE_WALLET} parameter
- * and {@link Activity#startActivityForResult(Intent, int)} instead.
- */
- @Deprecated
- @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
- public static final String ACTION_CHANGE_DEFAULT =
- "android.nfc.cardemulation.action.ACTION_CHANGE_DEFAULT";
-
- /**
- * The category extra for {@link #ACTION_CHANGE_DEFAULT}.
- *
- * @see #ACTION_CHANGE_DEFAULT
- */
- public static final String EXTRA_CATEGORY = "category";
-
- /**
- * The service {@link ComponentName} object passed in as an
- * extra for {@link #ACTION_CHANGE_DEFAULT}.
- *
- * @see #ACTION_CHANGE_DEFAULT
- */
- public static final String EXTRA_SERVICE_COMPONENT = "component";
-
- /**
- * Category used for NFC payment services.
- */
- public static final String CATEGORY_PAYMENT = "payment";
-
- /**
- * Category that can be used for all other card emulation
- * services.
- */
- public static final String CATEGORY_OTHER = "other";
-
- /**
- * Return value for {@link #getSelectionModeForCategory(String)}.
- *
- * <p>In this mode, the user has set a default service for this
- * category.
- *
- * <p>When using ISO-DEP card emulation with {@link HostApduService}
- * or {@link OffHostApduService}, if a remote NFC device selects
- * any of the Application IDs (AIDs)
- * that the default service has registered in this category,
- * that service will automatically be bound to to handle
- * the transaction.
- */
- public static final int SELECTION_MODE_PREFER_DEFAULT = 0;
-
- /**
- * Return value for {@link #getSelectionModeForCategory(String)}.
- *
- * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
- * or {@link OffHostApduService}, whenever an Application ID (AID) of this category
- * is selected, the user is asked which service they want to use to handle
- * the transaction, even if there is only one matching service.
- */
- public static final int SELECTION_MODE_ALWAYS_ASK = 1;
-
- /**
- * Return value for {@link #getSelectionModeForCategory(String)}.
- *
- * <p>In this mode, when using ISO-DEP card emulation with {@link HostApduService}
- * or {@link OffHostApduService}, the user will only be asked to select a service
- * if the Application ID (AID) selected by the reader has been registered by multiple
- * services. If there is only one service that has registered for the AID,
- * that service will be invoked directly.
- */
- public static final int SELECTION_MODE_ASK_IF_CONFLICT = 2;
- /**
- * Route to Device Host (DH).
- */
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DH = 0;
- /**
- * Route to eSE.
- */
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE = 1;
- /**
- * Route to UICC.
- */
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC = 2;
-
- /**
- * Route to the default value in config file.
- */
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT = 3;
-
- /**
- * Route unset.
- */
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public static final int PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET = -1;
-
- /**
- * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
- * succeeded.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
- public static final int SET_SERVICE_ENABLED_STATUS_OK = 0;
-
- /**
- * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
- * failed due to the unsupported feature.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
- public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED = 1;
-
- /**
- * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
- * failed due to the invalid service.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
- public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE = 2;
-
- /**
- * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
- * failed due to the service is already set to the requested status.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
- public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET = 3;
-
- /**
- * Status code returned when {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
- * failed due to unknown error.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
- public static final int SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR = 4;
-
- /**
- * Status code returned by {@link #setServiceEnabledForCategoryOther(ComponentName, boolean)}
- * @hide
- */
- @IntDef(prefix = "SET_SERVICE_ENABLED_STATUS_", value = {
- SET_SERVICE_ENABLED_STATUS_OK,
- SET_SERVICE_ENABLED_STATUS_FAILURE_FEATURE_UNSUPPORTED,
- SET_SERVICE_ENABLED_STATUS_FAILURE_INVALID_SERVICE,
- SET_SERVICE_ENABLED_STATUS_FAILURE_ALREADY_SET,
- SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SetServiceEnabledStatusCode {}
-
- /**
- * Property name used to indicate that an application wants to allow associated services
- * to share the same AID routing priority when this application is the role holder.
- * <p>
- * Example:
- * <pre>
- * {@code
- * <application>
- * ...
- * <property android:name="android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY"
- * android:value="true"/>
- * </application>
- * }
- * </pre>
- */
- @FlaggedApi(Flags.FLAG_NFC_ASSOCIATED_ROLE_SERVICES)
- public static final String PROPERTY_ALLOW_SHARED_ROLE_PRIORITY =
- "android.nfc.cardemulation.PROPERTY_ALLOW_SHARED_ROLE_PRIORITY";
-
- static boolean sIsInitialized = false;
- static HashMap<Context, CardEmulation> sCardEmus = new HashMap<Context, CardEmulation>();
- static INfcCardEmulation sService;
-
- final Context mContext;
-
- private CardEmulation(Context context, INfcCardEmulation service) {
- mContext = context.getApplicationContext();
- sService = service;
- }
-
- /**
- * Helper to get an instance of this class.
- *
- * @param adapter A reference to an NfcAdapter object.
- * @return
- */
- public static synchronized CardEmulation getInstance(NfcAdapter adapter) {
- if (adapter == null) throw new NullPointerException("NfcAdapter is null");
- Context context = adapter.getContext();
- if (context == null) {
- Log.e(TAG, "NfcAdapter context is null.");
- throw new UnsupportedOperationException();
- }
- if (!sIsInitialized) {
- PackageManager pm = context.getPackageManager();
- if (pm == null) {
- Log.e(TAG, "Cannot get PackageManager");
- throw new UnsupportedOperationException();
- }
- if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
- Log.e(TAG, "This device does not support card emulation");
- throw new UnsupportedOperationException();
- }
- sIsInitialized = true;
- }
- CardEmulation manager = sCardEmus.get(context);
- if (manager == null) {
- // Get card emu service
- INfcCardEmulation service = adapter.getCardEmulationService();
- if (service == null) {
- Log.e(TAG, "This device does not implement the INfcCardEmulation interface.");
- throw new UnsupportedOperationException();
- }
- manager = new CardEmulation(context, service);
- sCardEmus.put(context, manager);
- }
- return manager;
- }
-
- /**
- * Allows an application to query whether a service is currently
- * the default service to handle a card emulation category.
- *
- * <p>Note that if {@link #getSelectionModeForCategory(String)}
- * returns {@link #SELECTION_MODE_ALWAYS_ASK} or {@link #SELECTION_MODE_ASK_IF_CONFLICT},
- * this method will always return false. That is because in these
- * selection modes a default can't be set at the category level. For categories where
- * the selection mode is {@link #SELECTION_MODE_ALWAYS_ASK} or
- * {@link #SELECTION_MODE_ASK_IF_CONFLICT}, use
- * {@link #isDefaultServiceForAid(ComponentName, String)} to determine whether a service
- * is the default for a specific AID.
- *
- * @param service The ComponentName of the service
- * @param category The category
- * @return whether service is currently the default service for the category.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- */
- public boolean isDefaultServiceForCategory(ComponentName service, String category) {
- return callServiceReturn(() ->
- sService.isDefaultServiceForCategory(
- mContext.getUser().getIdentifier(), service, category), false);
- }
-
- /**
- *
- * Allows an application to query whether a service is currently
- * the default handler for a specified ISO7816-4 Application ID.
- *
- * @param service The ComponentName of the service
- * @param aid The ISO7816-4 Application ID
- * @return whether the service is the default handler for the specified AID
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- */
- public boolean isDefaultServiceForAid(ComponentName service, String aid) {
- return callServiceReturn(() ->
- sService.isDefaultServiceForAid(
- mContext.getUser().getIdentifier(), service, aid), false);
- }
-
- /**
- * <p>
- * Returns whether the user has allowed AIDs registered in the
- * specified category to be handled by a service that is preferred
- * by the foreground application, instead of by a pre-configured default.
- *
- * Foreground applications can set such preferences using the
- * {@link #setPreferredService(Activity, ComponentName)} method.
- * <p class="note">
- * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, this method will always
- * return true.
- *
- * @param category The category, e.g. {@link #CATEGORY_PAYMENT}
- * @return whether AIDs in the category can be handled by a service
- * specified by the foreground app.
- */
- @SuppressWarnings("NonUserGetterCalled")
- public boolean categoryAllowsForegroundPreference(String category) {
- Context contextAsUser = mContext.createContextAsUser(
- UserHandle.of(UserHandle.myUserId()), 0);
-
- RoleManager roleManager = contextAsUser.getSystemService(RoleManager.class);
- if (roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)) {
- return true;
- }
-
- if (CATEGORY_PAYMENT.equals(category)) {
- boolean preferForeground = false;
- try {
- preferForeground = Settings.Secure.getInt(
- contextAsUser.getContentResolver(),
- Constants.SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND) != 0;
- } catch (SettingNotFoundException e) {
- }
- return preferForeground;
- } else {
- // Allowed for all other categories
- return true;
- }
- }
-
- /**
- * Returns the service selection mode for the passed in category.
- * Valid return values are:
- * <p>{@link #SELECTION_MODE_PREFER_DEFAULT} the user has requested a default
- * service for this category, which will be preferred.
- * <p>{@link #SELECTION_MODE_ALWAYS_ASK} the user has requested to be asked
- * every time what service they would like to use in this category.
- * <p>{@link #SELECTION_MODE_ASK_IF_CONFLICT} the user will only be asked
- * to pick a service if there is a conflict.
- *
- * <p class="note">
- * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the default service defined
- * by the holder of {@link android.app.role.RoleManager#ROLE_WALLET} and is category agnostic.
- *
- * @param category The category, for example {@link #CATEGORY_PAYMENT}
- * @return the selection mode for the passed in category
- */
- public int getSelectionModeForCategory(String category) {
- if (CATEGORY_PAYMENT.equals(category)) {
- boolean paymentRegistered = callServiceReturn(() ->
- sService.isDefaultPaymentRegistered(), false);
- if (paymentRegistered) {
- return SELECTION_MODE_PREFER_DEFAULT;
- } else {
- return SELECTION_MODE_ALWAYS_ASK;
- }
- } else {
- return SELECTION_MODE_ASK_IF_CONFLICT;
- }
- }
- /**
- * Sets whether when this service becomes the preferred service, if the NFC stack
- * should enable observe mode or disable observe mode. The default is to not enable observe
- * mode when a service either the foreground default service or the default payment service so
- * not calling this method will preserve that behavior.
- *
- * @param service The component name of the service
- * @param enable Whether the service should default to observe mode or not
- * @return whether the change was successful.
- */
- @FlaggedApi(Flags.FLAG_NFC_OBSERVE_MODE)
- public boolean setShouldDefaultToObserveModeForService(@NonNull ComponentName service,
- boolean enable) {
- return callServiceReturn(() ->
- sService.setShouldDefaultToObserveModeForService(
- mContext.getUser().getIdentifier(), service, enable), false);
- }
-
- /**
- * Register a polling loop filter (PLF) for a HostApduService and indicate whether it should
- * auto-transact or not. The PLF can be sequence of an
- * even number of at least 2 hexadecimal numbers (0-9, A-F or a-f), representing a series of
- * bytes. When non-standard polling loop frame matches this sequence exactly, it may be
- * delivered to {@link HostApduService#processPollingFrames(List)}. If auto-transact
- * is set to true and this service is currently preferred or there are no other services
- * registered for this filter then observe mode will also be disabled.
- * @param service The HostApduService to register the filter for
- * @param pollingLoopFilter The filter to register
- * @param autoTransact true to have the NFC stack automatically disable observe mode and allow
- * transactions to proceed when this filter matches, false otherwise
- * @return true if the filter was registered, false otherwise
- * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public boolean registerPollingLoopFilterForService(@NonNull ComponentName service,
- @NonNull String pollingLoopFilter, boolean autoTransact) {
- final String pollingLoopFilterV = validatePollingLoopFilter(pollingLoopFilter);
- return callServiceReturn(() ->
- sService.registerPollingLoopFilterForService(
- mContext.getUser().getIdentifier(), service, pollingLoopFilterV, autoTransact),
- false);
- }
-
- /**
- * Unregister a polling loop filter (PLF) for a HostApduService. If the PLF had previously been
- * registered via {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)}
- * for this service it will be removed.
- * @param service The HostApduService to unregister the filter for
- * @param pollingLoopFilter The filter to unregister
- * @return true if the filter was removed, false otherwise
- * @throws IllegalArgumentException if the passed in string doesn't parse to at least one byte
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public boolean removePollingLoopFilterForService(@NonNull ComponentName service,
- @NonNull String pollingLoopFilter) {
- final String pollingLoopFilterV = validatePollingLoopFilter(pollingLoopFilter);
- return callServiceReturn(() ->
- sService.removePollingLoopFilterForService(
- mContext.getUser().getIdentifier(), service, pollingLoopFilterV), false);
- }
-
-
- /**
- * Register a polling loop pattern filter (PLPF) for a HostApduService and indicate whether it
- * should auto-transact or not. The pattern may include the characters 0-9 and A-F as well as
- * the regular expression operators `.`, `?` and `*`. When the beginning of anon-standard
- * polling loop frame matches this sequence exactly, it may be delivered to
- * {@link HostApduService#processPollingFrames(List)}. If auto-transact is set to true and this
- * service is currently preferred or there are no other services registered for this filter
- * then observe mode will also be disabled.
- * @param service The HostApduService to register the filter for
- * @param pollingLoopPatternFilter The pattern filter to register, must to be compatible with
- * {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers
- * and `.`, `?` and `*` operators
- * @param autoTransact true to have the NFC stack automatically disable observe mode and allow
- * transactions to proceed when this filter matches, false otherwise
- * @return true if the filter was registered, false otherwise
- * @throws IllegalArgumentException if the filter containst elements other than hexadecimal
- * numbers and `.`, `?` and `*` operators
- * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public boolean registerPollingLoopPatternFilterForService(@NonNull ComponentName service,
- @NonNull String pollingLoopPatternFilter, boolean autoTransact) {
- final String pollingLoopPatternFilterV =
- validatePollingLoopPatternFilter(pollingLoopPatternFilter);
- return callServiceReturn(() ->
- sService.registerPollingLoopPatternFilterForService(
- mContext.getUser().getIdentifier(), service, pollingLoopPatternFilterV,
- autoTransact),
- false);
- }
-
- /**
- * Unregister a polling loop pattern filter (PLPF) for a HostApduService. If the PLF had
- * previously been registered via
- * {@link #registerPollingLoopFilterForService(ComponentName, String, boolean)} for this
- * service it will be removed.
- * @param service The HostApduService to unregister the filter for
- * @param pollingLoopPatternFilter The filter to unregister, must to be compatible with
- * {@link java.util.regex.Pattern#compile(String)} and only contain hexadecimal numbers
- * and`.`, `?` and `*` operators
- * @return true if the filter was removed, false otherwise
- * @throws IllegalArgumentException if the filter containst elements other than hexadecimal
- * numbers and `.`, `?` and `*` operators
- * @throws java.util.regex.PatternSyntaxException if the regex syntax is invalid
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public boolean removePollingLoopPatternFilterForService(@NonNull ComponentName service,
- @NonNull String pollingLoopPatternFilter) {
- final String pollingLoopPatternFilterV =
- validatePollingLoopPatternFilter(pollingLoopPatternFilter);
- return callServiceReturn(() ->
- sService.removePollingLoopPatternFilterForService(
- mContext.getUser().getIdentifier(), service, pollingLoopPatternFilterV), false);
- }
-
- /**
- * Registers a list of AIDs for a specific category for the
- * specified service.
- *
- * <p>If a list of AIDs for that category was previously
- * registered for this service (either statically
- * through the manifest, or dynamically by using this API),
- * that list of AIDs will be replaced with this one.
- *
- * <p>Note that you can only register AIDs for a service that
- * is running under the same UID as the caller of this API. Typically
- * this means you need to call this from the same
- * package as the service itself, though UIDs can also
- * be shared between packages using shared UIDs.
- *
- * @param service The component name of the service
- * @param category The category of AIDs to be registered
- * @param aids A list containing the AIDs to be registered
- * @return whether the registration was successful.
- */
- public boolean registerAidsForService(ComponentName service, String category,
- List<String> aids) {
- final AidGroup aidGroup = new AidGroup(aids, category);
- return callServiceReturn(() ->
- sService.registerAidGroupForService(
- mContext.getUser().getIdentifier(), service, aidGroup), false);
- }
-
- /**
- * Unsets the off-host Secure Element for the given service.
- *
- * <p>Note that this will only remove Secure Element that was dynamically
- * set using the {@link #setOffHostForService(ComponentName, String)}
- * and resets it to a value that was statically assigned using manifest.
- *
- * <p>Note that you can only unset off-host SE for a service that
- * is running under the same UID as the caller of this API. Typically
- * this means you need to call this from the same
- * package as the service itself, though UIDs can also
- * be shared between packages using shared UIDs.
- *
- * @param service The component name of the service
- * @return whether the registration was successful.
- */
- @RequiresPermission(android.Manifest.permission.NFC)
- @NonNull
- public boolean unsetOffHostForService(@NonNull ComponentName service) {
- return callServiceReturn(() ->
- sService.unsetOffHostForService(
- mContext.getUser().getIdentifier(), service), false);
- }
-
- /**
- * Sets the off-host Secure Element for the given service.
- *
- * <p>If off-host SE was initially set (either statically
- * through the manifest, or dynamically by using this API),
- * it will be replaced with this one. All AIDs registered by
- * this service will be re-routed to this Secure Element if
- * successful. AIDs that was statically assigned using manifest
- * will re-route to off-host SE that stated in manifest after NFC
- * toggle.
- *
- * <p>Note that you can only set off-host SE for a service that
- * is running under the same UID as the caller of this API. Typically
- * this means you need to call this from the same
- * package as the service itself, though UIDs can also
- * be shared between packages using shared UIDs.
- *
- * <p>Registeration will be successful only if the Secure Element
- * exists on the device.
- *
- * @param service The component name of the service
- * @param offHostSecureElement Secure Element to register the AID to. Only accept strings with
- * prefix SIM or prefix eSE.
- * Ref: GSMA TS.26 - NFC Handset Requirements
- * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be
- * SIM[smartcard slot]
- * (e.g. SIM/SIM1, SIM2… SIMn).
- * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be
- * eSE[number]
- * (e.g. eSE/eSE1, eSE2, etc.).
- * @return whether the registration was successful.
- */
- @RequiresPermission(android.Manifest.permission.NFC)
- @NonNull
- public boolean setOffHostForService(@NonNull ComponentName service,
- @NonNull String offHostSecureElement) {
- NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
- if (adapter == null || offHostSecureElement == null) {
- return false;
- }
-
- List<String> validSE = adapter.getSupportedOffHostSecureElements();
- if ((offHostSecureElement.startsWith("eSE") && !validSE.contains("eSE"))
- || (offHostSecureElement.startsWith("SIM") && !validSE.contains("SIM"))) {
- return false;
- }
-
- if (!offHostSecureElement.startsWith("eSE") && !offHostSecureElement.startsWith("SIM")) {
- return false;
- }
-
- if (offHostSecureElement.equals("eSE")) {
- offHostSecureElement = "eSE1";
- } else if (offHostSecureElement.equals("SIM")) {
- offHostSecureElement = "SIM1";
- }
- final String offHostSecureElementV = new String(offHostSecureElement);
- return callServiceReturn(() ->
- sService.setOffHostForService(
- mContext.getUser().getIdentifier(), service, offHostSecureElementV), false);
- }
-
- /**
- * Retrieves the currently registered AIDs for the specified
- * category for a service.
- *
- * <p>Note that this will only return AIDs that were dynamically
- * registered using {@link #registerAidsForService(ComponentName, String, List)}
- * method. It will *not* return AIDs that were statically registered
- * in the manifest.
- *
- * @param service The component name of the service
- * @param category The category for which the AIDs were registered,
- * e.g. {@link #CATEGORY_PAYMENT}
- * @return The list of AIDs registered for this category, or null if it couldn't be found.
- */
- public List<String> getAidsForService(ComponentName service, String category) {
- AidGroup group = callServiceReturn(() ->
- sService.getAidGroupForService(
- mContext.getUser().getIdentifier(), service, category), null);
- return (group != null ? group.getAids() : null);
- }
-
- /**
- * Removes a previously registered list of AIDs for the specified category for the
- * service provided.
- *
- * <p>Note that this will only remove AIDs that were dynamically
- * registered using the {@link #registerAidsForService(ComponentName, String, List)}
- * method. It will *not* remove AIDs that were statically registered in
- * the manifest. If dynamically registered AIDs are removed using
- * this method, and a statically registered AID group for the same category
- * exists in the manifest, the static AID group will become active again.
- *
- * @param service The component name of the service
- * @param category The category of the AIDs to be removed, e.g. {@link #CATEGORY_PAYMENT}
- * @return whether the group was successfully removed.
- */
- public boolean removeAidsForService(ComponentName service, String category) {
- return callServiceReturn(() ->
- sService.removeAidGroupForService(
- mContext.getUser().getIdentifier(), service, category), false);
- }
-
- /**
- * Allows a foreground application to specify which card emulation service
- * should be preferred while a specific Activity is in the foreground.
- *
- * <p>The specified Activity must currently be in resumed state. A good
- * paradigm is to call this method in your {@link Activity#onResume}, and to call
- * {@link #unsetPreferredService(Activity)} in your {@link Activity#onPause}.
- *
- * <p>This method call will fail in two specific scenarios:
- * <ul>
- * <li> If the service registers one or more AIDs in the {@link #CATEGORY_PAYMENT}
- * category, but the user has indicated that foreground apps are not allowed
- * to override the default payment service.
- * <li> If the service registers one or more AIDs in the {@link #CATEGORY_OTHER}
- * category that are also handled by the default payment service, and the
- * user has indicated that foreground apps are not allowed to override the
- * default payment service.
- * </ul>
- *
- * <p> Use {@link #categoryAllowsForegroundPreference(String)} to determine
- * whether foreground apps can override the default payment service.
- *
- * <p>Note that this preference is not persisted by the OS, and hence must be
- * called every time the Activity is resumed.
- *
- * @param activity The activity which prefers this service to be invoked
- * @param service The service to be preferred while this activity is in the foreground
- * @return whether the registration was successful
- */
- public boolean setPreferredService(Activity activity, ComponentName service) {
- // Verify the activity is in the foreground before calling into NfcService
- if (activity == null || service == null) {
- throw new NullPointerException("activity or service or category is null");
- }
- return callServiceReturn(() -> sService.setPreferredService(service), false);
- }
-
- /**
- * Unsets the preferred service for the specified Activity.
- *
- * <p>Note that the specified Activity must still be in resumed
- * state at the time of this call. A good place to call this method
- * is in your {@link Activity#onPause} implementation.
- *
- * @param activity The activity which the service was registered for
- * @return true when successful
- */
- public boolean unsetPreferredService(Activity activity) {
- if (activity == null) {
- throw new NullPointerException("activity is null");
- }
- return callServiceReturn(() -> sService.unsetPreferredService(), false);
- }
-
- /**
- * Some devices may allow an application to register all
- * AIDs that starts with a certain prefix, e.g.
- * "A000000004*" to register all MasterCard AIDs.
- *
- * Use this method to determine whether this device
- * supports registering AID prefixes.
- *
- * @return whether AID prefix registering is supported on this device.
- */
- public boolean supportsAidPrefixRegistration() {
- return callServiceReturn(() -> sService.supportsAidPrefixRegistration(), false);
- }
-
- /**
- * Retrieves the registered AIDs for the preferred payment service.
- *
- * @return The list of AIDs registered for this category, or null if it couldn't be found.
- */
- @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
- @Nullable
- public List<String> getAidsForPreferredPaymentService() {
- ApduServiceInfo serviceInfo = callServiceReturn(() ->
- sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null);
- return (serviceInfo != null ? serviceInfo.getAids() : null);
- }
-
- /**
- * Retrieves the route destination for the preferred payment service.
- *
- * <p class="note">
- * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service
- * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This
- * will return the route for one of the services registered by the role holder (if any). If
- * there are multiple services registered, it is unspecified which of those will be used to
- * determine the route.
- *
- * @return The route destination secure element name of the preferred payment service.
- * HCE payment: "Host"
- * OffHost payment: 1. String with prefix SIM or prefix eSE string.
- * Ref: GSMA TS.26 - NFC Handset Requirements
- * TS26_NFC_REQ_069: For UICC, Secure Element Name SHALL be
- * SIM[smartcard slot]
- * (e.g. SIM/SIM1, SIM2… SIMn).
- * TS26_NFC_REQ_070: For embedded SE, Secure Element Name SHALL be
- * eSE[number]
- * (e.g. eSE/eSE1, eSE2, etc.).
- * 2. "OffHost" if the payment service does not specify secure element
- * name.
- */
- @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
- @Nullable
- public String getRouteDestinationForPreferredPaymentService() {
- ApduServiceInfo serviceInfo = callServiceReturn(() ->
- sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null);
- if (serviceInfo != null) {
- if (!serviceInfo.isOnHost()) {
- return serviceInfo.getOffHostSecureElement() == null ?
- "OffHost" : serviceInfo.getOffHostSecureElement();
- }
- return "Host";
- }
- return null;
- }
-
- /**
- * Returns a user-visible description of the preferred payment service.
- *
- * <p class="note">
- * Starting with {@link Build.VERSION_CODES#VANILLA_ICE_CREAM}, the preferred payment service
- * no longer exists and is replaced by {@link android.app.role.RoleManager#ROLE_WALLET}. This
- * will return the description for one of the services registered by the role holder (if any).
- * If there are multiple services registered, it is unspecified which of those will be used
- * to obtain the service description here.
- *
- * @return the preferred payment service description
- */
- @RequiresPermission(Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
- @Nullable
- public CharSequence getDescriptionForPreferredPaymentService() {
- ApduServiceInfo serviceInfo = callServiceReturn(() ->
- sService.getPreferredPaymentService(mContext.getUser().getIdentifier()), null);
- return (serviceInfo != null ? serviceInfo.getDescription() : null);
- }
-
- /**
- * @hide
- */
- public boolean setDefaultServiceForCategory(ComponentName service, String category) {
- return callServiceReturn(() ->
- sService.setDefaultServiceForCategory(
- mContext.getUser().getIdentifier(), service, category), false);
- }
-
- /**
- * @hide
- */
- public boolean setDefaultForNextTap(ComponentName service) {
- return callServiceReturn(() ->
- sService.setDefaultForNextTap(
- mContext.getUser().getIdentifier(), service), false);
- }
-
- /**
- * @hide
- */
- public boolean setDefaultForNextTap(int userId, ComponentName service) {
- return callServiceReturn(() ->
- sService.setDefaultForNextTap(userId, service), false);
- }
-
- /**
- * @hide
- */
- public List<ApduServiceInfo> getServices(String category) {
- return callServiceReturn(() ->
- sService.getServices(
- mContext.getUser().getIdentifier(), category), null);
- }
-
- /**
- * Retrieves list of services registered of the provided category for the provided user.
- *
- * @param category Category string, one of {@link #CATEGORY_PAYMENT} or {@link #CATEGORY_OTHER}
- * @param userId the user handle of the user whose information is being requested.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_NFC_MAINLINE)
- @NonNull
- public List<ApduServiceInfo> getServices(@NonNull String category, @UserIdInt int userId) {
- return callServiceReturn(() ->
- sService.getServices(userId, category), null);
- }
-
- /**
- * Tests the validity of the polling loop filter.
- * @param pollingLoopFilter The polling loop filter to test.
- *
- * @hide
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static @NonNull String validatePollingLoopFilter(@NonNull String pollingLoopFilter) {
- // Verify hex characters
- byte[] plfBytes = HexFormat.of().parseHex(pollingLoopFilter);
- if (plfBytes.length == 0) {
- throw new IllegalArgumentException(
- "Polling loop filter must contain at least one byte.");
- }
- return HexFormat.of().withUpperCase().formatHex(plfBytes);
- }
-
- /**
- * Tests the validity of the polling loop pattern filter.
- * @param pollingLoopPatternFilter The polling loop filter to test.
- *
- * @hide
- */
- @FlaggedApi(Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static @NonNull String validatePollingLoopPatternFilter(
- @NonNull String pollingLoopPatternFilter) {
- // Verify hex characters
- if (!PLPF_PATTERN.matcher(pollingLoopPatternFilter).matches()) {
- throw new IllegalArgumentException(
- "Polling loop pattern filters may only contain hexadecimal numbers, ?s and *s");
- }
- return Pattern.compile(pollingLoopPatternFilter.toUpperCase(Locale.ROOT)).toString();
- }
-
- /**
- * A valid AID according to ISO/IEC 7816-4:
- * <ul>
- * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
- * <li>Consist of only hex characters
- * <li>Additionally, we allow an asterisk at the end, to indicate
- * a prefix
- * <li>Additinally we allow an (#) at symbol at the end, to indicate
- * a subset
- * </ul>
- *
- * @hide
- */
- public static boolean isValidAid(String aid) {
- if (aid == null)
- return false;
-
- // If a prefix/subset AID, the total length must be odd (even # of AID chars + '*')
- if ((aid.endsWith("*") || aid.endsWith("#")) && ((aid.length() % 2) == 0)) {
- Log.e(TAG, "AID " + aid + " is not a valid AID.");
- return false;
- }
-
- // If not a prefix/subset AID, the total length must be even (even # of AID chars)
- if ((!(aid.endsWith("*") || aid.endsWith("#"))) && ((aid.length() % 2) != 0)) {
- Log.e(TAG, "AID " + aid + " is not a valid AID.");
- return false;
- }
-
- // Verify hex characters
- if (!AID_PATTERN.matcher(aid).matches()) {
- Log.e(TAG, "AID " + aid + " is not a valid AID.");
- return false;
- }
-
- return true;
- }
-
- /**
- * Allows to set or unset preferred service (category other) to avoid AID Collision. The user
- * should use corresponding context using {@link Context#createContextAsUser(UserHandle, int)}
- *
- * @param service The ComponentName of the service
- * @param status true to enable, false to disable
- * @return status code defined in {@link SetServiceEnabledStatusCode}
- *
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_NFC_SET_SERVICE_ENABLED_FOR_CATEGORY_OTHER)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @SetServiceEnabledStatusCode
- public int setServiceEnabledForCategoryOther(@NonNull ComponentName service,
- boolean status) {
- return callServiceReturn(() ->
- sService.setServiceEnabledForCategoryOther(mContext.getUser().getIdentifier(),
- service, status), SET_SERVICE_ENABLED_STATUS_FAILURE_UNKNOWN_ERROR);
- }
-
- /** @hide */
- @IntDef(prefix = "PROTOCOL_AND_TECHNOLOGY_ROUTE_",
- value = {
- PROTOCOL_AND_TECHNOLOGY_ROUTE_DH,
- PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE,
- PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC,
- PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET,
- PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ProtocolAndTechnologyRoute {}
-
- /**
- * Setting NFC controller routing table, which includes Protocol Route and Technology Route,
- * while this Activity is in the foreground.
- *
- * The parameter set to {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET}
- * can be used to keep current values for that entry. Either
- * Protocol Route or Technology Route should be override when calling this API, otherwise
- * throw {@link IllegalArgumentException}.
- * <p>
- * Example usage in an Activity that requires to set proto route to "ESE" and keep tech route:
- * <pre>
- * protected void onResume() {
- * mNfcAdapter.overrideRoutingTable(
- * this, {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE},
- * {@link #PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET});
- * }</pre>
- * </p>
- * Also activities must call {@link #recoverRoutingTable(Activity)}
- * when it goes to the background. Only the package of the
- * currently preferred service (the service set as preferred by the current foreground
- * application via {@link CardEmulation#setPreferredService(Activity, ComponentName)} or the
- * current Default Wallet Role Holder {@link RoleManager#ROLE_WALLET}),
- * otherwise a call to this method will fail and throw {@link SecurityException}.
- * @param activity The Activity that requests NFC controller routing table to be changed.
- * @param protocol ISO-DEP route destination, where the possible inputs are defined
- * in {@link ProtocolAndTechnologyRoute}.
- * @param technology Tech-A, Tech-B and Tech-F route destination, where the possible inputs
- * are defined in {@link ProtocolAndTechnologyRoute}
- * @throws SecurityException if the caller is not the preferred NFC service
- * @throws IllegalArgumentException if the activity is not resumed or the caller is not in the
- * foreground.
- * <p>
- * This is a high risk API and only included to support mainline effort
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public void overrideRoutingTable(
- @NonNull Activity activity, @ProtocolAndTechnologyRoute int protocol,
- @ProtocolAndTechnologyRoute int technology) {
- if (!activity.isResumed()) {
- throw new IllegalArgumentException("Activity must be resumed.");
- }
- String protocolRoute = routeIntToString(protocol);
- String technologyRoute = routeIntToString(technology);
- callService(() ->
- sService.overrideRoutingTable(
- mContext.getUser().getIdentifier(),
- protocolRoute,
- technologyRoute,
- mContext.getPackageName()));
- }
-
- /**
- * Restore the NFC controller routing table,
- * which was changed by {@link #overrideRoutingTable(Activity, int, int)}
- *
- * @param activity The Activity that requested NFC controller routing table to be changed.
- * @throws IllegalArgumentException if the caller is not in the foreground.
- *
- * @hide
- */
- @SystemApi
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(Flags.FLAG_NFC_OVERRIDE_RECOVER_ROUTING_TABLE)
- public void recoverRoutingTable(@NonNull Activity activity) {
- if (!activity.isResumed()) {
- throw new IllegalArgumentException("Activity must be resumed.");
- }
- callService(() ->
- sService.recoverRoutingTable(
- mContext.getUser().getIdentifier()));
- }
-
- /**
- * Is EUICC supported as a Secure Element EE which supports off host card emulation.
- *
- * @return true if the device supports EUICC for off host card emulation, false otherwise.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public boolean isEuiccSupported() {
- return callServiceReturn(() -> sService.isEuiccSupported(), false);
- }
-
- /**
- * Setting the default subscription ID succeeded.
- * @hide
- */
- @SystemApi
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public static final int SET_SUBSCRIPTION_ID_STATUS_SUCCESS = 0;
-
- /**
- * Setting the default subscription ID failed because the subscription ID is invalid.
- * @hide
- */
- @SystemApi
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID = 1;
-
- /**
- * Setting the default subscription ID failed because there was an internal error processing
- * the request. For ex: NFC service died in the middle of handling the API.
- * @hide
- */
- @SystemApi
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR = 2;
-
- /**
- * Setting the default subscription ID failed because this feature is not supported on the
- * device.
- * @hide
- */
- @SystemApi
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public static final int SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED = 3;
-
- /**
- * Setting the default subscription ID failed because of unknown error.
- * @hide
- */
- @SystemApi
- @FlaggedApi(Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public static final int SET_SUBSCRIPTION_ID_STATUS_UNKNOWN = -1;
-
- /** @hide */
- @IntDef(prefix = "SET_SUBSCRIPTION_ID_STATUS_",
- value = {
- SET_SUBSCRIPTION_ID_STATUS_SUCCESS,
- SET_SUBSCRIPTION_ID_STATUS_FAILED_INVALID_SUBSCRIPTION_ID,
- SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR,
- SET_SUBSCRIPTION_ID_STATUS_FAILED_NOT_SUPPORTED,
- SET_SUBSCRIPTION_ID_STATUS_UNKNOWN
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface SetSubscriptionIdStatus {}
-
- /**
- * Sets the system's default NFC subscription id.
- *
- * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this sets the
- * default UICC NFCEE that will handle NFC offhost CE transactions </p>
- *
- * @param subscriptionId the default NFC subscription Id to set. User can get subscription id
- * from {@link SubscriptionManager#getSubscriptionId(int)}
- * @return status of the operation.
- *
- * @throws UnsupportedOperationException If the device does not have
- * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
- * @hide
- */
- @SystemApi
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
- @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS)
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public @SetSubscriptionIdStatus int setDefaultNfcSubscriptionId(int subscriptionId) {
- return callServiceReturn(() ->
- sService.setDefaultNfcSubscriptionId(
- subscriptionId, mContext.getPackageName()),
- SET_SUBSCRIPTION_ID_STATUS_FAILED_INTERNAL_ERROR);
- }
-
- /**
- * Returns the system's default NFC subscription id.
- *
- * <p> For devices with multiple UICC/EUICC that is configured to be NFCEE, this returns the
- * default UICC NFCEE that will handle NFC offhost CE transactions </p>
- * <p> If the device has no UICC that can serve as NFCEE, this will return
- * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID}.</p>
- *
- * @return the default NFC subscription Id if set,
- * {@link SubscriptionManager#INVALID_SUBSCRIPTION_ID} otherwise.
- *
- * @throws UnsupportedOperationException If the device does not have
- * {@link PackageManager#FEATURE_TELEPHONY_SUBSCRIPTION}.
- */
- @RequiresFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)
- @FlaggedApi(android.nfc.Flags.FLAG_ENABLE_CARD_EMULATION_EUICC)
- public int getDefaultNfcSubscriptionId() {
- return callServiceReturn(() ->
- sService.getDefaultNfcSubscriptionId(mContext.getPackageName()),
- SubscriptionManager.INVALID_SUBSCRIPTION_ID);
- }
-
- /**
- * Returns the value of {@link Settings.Secure#NFC_PAYMENT_DEFAULT_COMPONENT}.
- *
- * @param context A context
- * @return A ComponentName for the setting value, or null.
- *
- * @hide
- */
- @SystemApi
- @UserHandleAware
- @RequiresPermission(android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO)
- @SuppressWarnings("AndroidFrameworkClientSidePermissionCheck")
- @FlaggedApi(android.permission.flags.Flags.FLAG_WALLET_ROLE_ENABLED)
- @Nullable
- public static ComponentName getPreferredPaymentService(@NonNull Context context) {
- context.checkCallingOrSelfPermission(Manifest.permission.NFC_PREFERRED_PAYMENT_INFO);
- String defaultPaymentComponent = Settings.Secure.getString(context.getContentResolver(),
- Constants.SETTINGS_SECURE_NFC_PAYMENT_DEFAULT_COMPONENT);
-
- if (defaultPaymentComponent == null) {
- return null;
- }
-
- return ComponentName.unflattenFromString(defaultPaymentComponent);
- }
-
- /** @hide */
- interface ServiceCall {
- void call() throws RemoteException;
- }
- /** @hide */
- public static void callService(ServiceCall call) {
- try {
- if (sService == null) {
- NfcAdapter.attemptDeadServiceRecovery(
- new RemoteException("NFC CardEmulation Service is null"));
- sService = NfcAdapter.getCardEmulationService();
- }
- call.call();
- } catch (RemoteException e) {
- NfcAdapter.attemptDeadServiceRecovery(e);
- sService = NfcAdapter.getCardEmulationService();
- try {
- call.call();
- } catch (RemoteException ee) {
- ee.rethrowAsRuntimeException();
- }
- }
- }
- /** @hide */
- interface ServiceCallReturn<T> {
- T call() throws RemoteException;
- }
- /** @hide */
- public static <T> T callServiceReturn(ServiceCallReturn<T> call, T defaultReturn) {
- try {
- if (sService == null) {
- NfcAdapter.attemptDeadServiceRecovery(
- new RemoteException("NFC CardEmulation Service is null"));
- sService = NfcAdapter.getCardEmulationService();
- }
- return call.call();
- } catch (RemoteException e) {
- NfcAdapter.attemptDeadServiceRecovery(e);
- sService = NfcAdapter.getCardEmulationService();
- // Try one more time
- try {
- return call.call();
- } catch (RemoteException ee) {
- ee.rethrowAsRuntimeException();
- }
- }
- return defaultReturn;
- }
-
- /** @hide */
- public static String routeIntToString(@ProtocolAndTechnologyRoute int route) {
- return switch (route) {
- case PROTOCOL_AND_TECHNOLOGY_ROUTE_DH -> "DH";
- case PROTOCOL_AND_TECHNOLOGY_ROUTE_ESE -> "eSE";
- case PROTOCOL_AND_TECHNOLOGY_ROUTE_UICC -> "SIM";
- case PROTOCOL_AND_TECHNOLOGY_ROUTE_UNSET -> null;
- case PROTOCOL_AND_TECHNOLOGY_ROUTE_DEFAULT -> "default";
- default -> throw new IllegalStateException("Unexpected value: " + route);
- };
- }
-
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public static final int NFC_INTERNAL_ERROR_UNKNOWN = 0;
-
- /**
- * This error is reported when the NFC command watchdog restarts the NFC stack.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public static final int NFC_INTERNAL_ERROR_NFC_CRASH_RESTART = 1;
-
- /**
- * This error is reported when the NFC controller does not respond or there's an NCI transport
- * error.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public static final int NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR = 2;
-
- /**
- * This error is reported when the NFC stack times out while waiting for a response to a command
- * sent to the NFC hardware.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public static final int NFC_INTERNAL_ERROR_COMMAND_TIMEOUT = 3;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- @IntDef(prefix = "NFC_INTERNAL_ERROR_", value = {
- NFC_INTERNAL_ERROR_UNKNOWN,
- NFC_INTERNAL_ERROR_NFC_CRASH_RESTART,
- NFC_INTERNAL_ERROR_NFC_HARDWARE_ERROR,
- NFC_INTERNAL_ERROR_COMMAND_TIMEOUT,
- })
- public @interface NfcInternalErrorType {}
-
- /** Listener for preferred service state changes. */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public interface NfcEventCallback {
- /**
- * This method is called when this package gains or loses preferred Nfc service status,
- * either the Default Wallet Role holder (see {@link
- * android.app.role.RoleManager#ROLE_WALLET}) or the preferred service of the foreground
- * activity set with {@link #setPreferredService(Activity, ComponentName)}
- *
- * @param isPreferred true is this service has become the preferred Nfc service, false if it
- * is no longer the preferred service
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onPreferredServiceChanged(boolean isPreferred) {}
-
- /**
- * This method is called when observe mode has been enabled or disabled.
- *
- * @param isEnabled true if observe mode has been enabled, false if it has been disabled
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onObserveModeStateChanged(boolean isEnabled) {}
-
- /**
- * This method is called when an AID conflict is detected during an NFC transaction. This
- * can happen when multiple services are registered for the same AID. If your service is
- * registered for this AID you may want to instruct users to bring your app to the
- * foreground and ensure you call {@link #setPreferredService(Activity, ComponentName)}
- * to ensure the transaction is routed to your service.
- *
- * @param aid The AID that is in conflict
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onAidConflictOccurred(@NonNull String aid) {}
-
- /**
- * This method is called when an AID is not routed to any service during an NFC
- * transaction. This can happen when no service is registered for the given AID.
- *
- * @param aid the AID that was not routed
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onAidNotRouted(@NonNull String aid) {}
-
- /**
- * This method is called when the NFC state changes.
- *
- * @see NfcAdapter#getAdapterState()
- *
- * @param state The new NFC state
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onNfcStateChanged(@NfcAdapter.AdapterState int state) {}
- /**
- * This method is called when the NFC controller is in card emulation mode and an NFC
- * reader's field is either detected or lost.
- *
- * @param isDetected true if an NFC reader is detected, false if it is lost
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onRemoteFieldChanged(boolean isDetected) {}
-
- /**
- * This method is called when an internal error is reported by the NFC stack.
- *
- * No action is required in response to these events as the NFC stack will automatically
- * attempt to recover. These errors are reported for informational purposes only.
- *
- * Note that these errors can be reported when performing various internal NFC operations
- * (such as during device shutdown) and cannot always be explicitly correlated with NFC
- * transaction failures.
- *
- * @param errorType The type of the internal error
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- default void onInternalErrorReported(@NfcInternalErrorType int errorType) {}
- }
-
- private final ArrayMap<NfcEventCallback, Executor> mNfcEventCallbacks = new ArrayMap<>();
-
- final INfcEventCallback mINfcEventCallback =
- new INfcEventCallback.Stub() {
- public void onPreferredServiceChanged(ComponentNameAndUser componentNameAndUser) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- boolean isPreferred =
- componentNameAndUser != null
- && componentNameAndUser.getUserId()
- == mContext.getUser().getIdentifier()
- && componentNameAndUser.getComponentName() != null
- && Objects.equals(
- mContext.getPackageName(),
- componentNameAndUser.getComponentName()
- .getPackageName());
- callListeners(listener -> listener.onPreferredServiceChanged(isPreferred));
- }
-
- public void onObserveModeStateChanged(boolean isEnabled) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- callListeners(listener -> listener.onObserveModeStateChanged(isEnabled));
- }
-
- public void onAidConflictOccurred(String aid) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- callListeners(listener -> listener.onAidConflictOccurred(aid));
- }
-
- public void onAidNotRouted(String aid) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- callListeners(listener -> listener.onAidNotRouted(aid));
- }
-
- public void onNfcStateChanged(int state) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- callListeners(listener -> listener.onNfcStateChanged(state));
- }
-
- public void onRemoteFieldChanged(boolean isDetected) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- callListeners(listener -> listener.onRemoteFieldChanged(isDetected));
- }
-
- public void onInternalErrorReported(@NfcInternalErrorType int errorType) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- callListeners(listener -> listener.onInternalErrorReported(errorType));
- }
-
- interface ListenerCall {
- void invoke(NfcEventCallback listener);
- }
-
- private void callListeners(ListenerCall listenerCall) {
- synchronized (mNfcEventCallbacks) {
- mNfcEventCallbacks.forEach(
- (listener, executor) -> {
- executor.execute(() -> listenerCall.invoke(listener));
- });
- }
- }
- };
-
- /**
- * Register a listener for NFC Events.
- *
- * @param executor The Executor to run the call back with
- * @param listener The listener to register
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public void registerNfcEventCallback(
- @NonNull @CallbackExecutor Executor executor, @NonNull NfcEventCallback listener) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- synchronized (mNfcEventCallbacks) {
- mNfcEventCallbacks.put(listener, executor);
- if (mNfcEventCallbacks.size() == 1) {
- callService(() -> sService.registerNfcEventCallback(mINfcEventCallback));
- }
- }
- }
-
- /**
- * Unregister a preferred service listener that was previously registered with {@link
- * #registerNfcEventCallback(Executor, NfcEventCallback)}
- *
- * @param listener The previously registered listener to unregister
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_EVENT_LISTENER)
- public void unregisterNfcEventCallback(@NonNull NfcEventCallback listener) {
- if (!android.nfc.Flags.nfcEventListener()) {
- return;
- }
- synchronized (mNfcEventCallbacks) {
- mNfcEventCallbacks.remove(listener);
- if (mNfcEventCallbacks.size() == 0) {
- callService(() -> sService.unregisterNfcEventCallback(mINfcEventCallback));
- }
- }
- }
-}
diff --git a/nfc/java/android/nfc/cardemulation/HostApduService.java b/nfc/java/android/nfc/cardemulation/HostApduService.java
deleted file mode 100644
index fbf2203b40b4..000000000000
--- a/nfc/java/android/nfc/cardemulation/HostApduService.java
+++ /dev/null
@@ -1,446 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc.cardemulation;
-
-import android.annotation.FlaggedApi;
-import android.annotation.NonNull;
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.annotation.SuppressLint;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.nfc.NfcAdapter;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * <p>HostApduService is a convenience {@link Service} class that can be
- * extended to emulate an NFC card inside an Android
- * service component.
- *
- * <div class="special reference">
- * <h3>Developer Guide</h3>
- * For a general introduction to card emulation, see
- * <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
- * Host-based Card Emulation</a>.</p>
- * </div>
- *
- * <h3>NFC Protocols</h3>
- * <p>Cards emulated by this class are based on the NFC-Forum ISO-DEP
- * protocol (based on ISO/IEC 14443-4) and support processing
- * command Application Protocol Data Units (APDUs) as
- * defined in the ISO/IEC 7816-4 specification.
- *
- * <h3>Service selection</h3>
- * <p>When a remote NFC device wants to talk to your
- * service, it sends a so-called
- * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification.
- * The AID is an application identifier defined in ISO/IEC 7816-4.
- *
- * <p>The registration procedure for AIDs is defined in the
- * ISO/IEC 7816-5 specification. If you don't want to register an
- * AID, you are free to use AIDs in the proprietary range:
- * bits 8-5 of the first byte must each be set to '1'. For example,
- * "0xF00102030405" is a proprietary AID. If you do use proprietary
- * AIDs, it is recommended to choose an AID of at least 6 bytes,
- * to reduce the risk of collisions with other applications that
- * might be using proprietary AIDs as well.
- *
- * <h3>AID groups</h3>
- * <p>In some cases, a service may need to register multiple AIDs
- * to implement a certain application, and it needs to be sure
- * that it is the default handler for all of these AIDs (as opposed
- * to some AIDs in the group going to another service).
- *
- * <p>An AID group is a list of AIDs that should be considered as
- * belonging together by the OS. For all AIDs in an AID group, the
- * OS will guarantee one of the following:
- * <ul>
- * <li>All AIDs in the group are routed to this service
- * <li>No AIDs in the group are routed to this service
- * </ul>
- * In other words, there is no in-between state, where some AIDs
- * in the group can be routed to this service, and some to another.
- * <h3>AID groups and categories</h3>
- * <p>Each AID group can be associated with a category. This allows
- * the Android OS to classify services, and it allows the user to
- * set defaults at the category level instead of the AID level.
- *
- * <p>You can use
- * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)}
- * to determine if your service is the default handler for a category.
- *
- * <p>In this version of the platform, the only known categories
- * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}.
- * AID groups without a category, or with a category that is not recognized
- * by the current platform version, will automatically be
- * grouped into the {@link CardEmulation#CATEGORY_OTHER} category.
- * <h3>Service AID registration</h3>
- * <p>To tell the platform which AIDs groups
- * are requested by this service, a {@link #SERVICE_META_DATA}
- * entry must be included in the declaration of the service. An
- * example of a HostApduService manifest declaration is shown below:
- * <pre> &lt;service android:name=".MyHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"&gt;
- * &lt;intent-filter&gt;
- * &lt;action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/&gt;
- * &lt;/intent-filter&gt;
- * &lt;meta-data android:name="android.nfc.cardemulation.host_apdu_service" android:resource="@xml/apduservice"/&gt;
- * &lt;/service&gt;</pre>
- *
- * This meta-data tag points to an apduservice.xml file.
- * An example of this file with a single AID group declaration is shown below:
- * <pre>
- * &lt;host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
- * android:description="@string/servicedesc" android:requireDeviceUnlock="false"&gt;
- * &lt;aid-group android:description="@string/aiddescription" android:category="other">
- * &lt;aid-filter android:name="F0010203040506"/&gt;
- * &lt;aid-filter android:name="F0394148148100"/&gt;
- * &lt;/aid-group&gt;
- * &lt;/host-apdu-service&gt;
- * </pre>
- *
- * <p>The {@link android.R.styleable#HostApduService &lt;host-apdu-service&gt;} is required
- * to contain a
- * {@link android.R.styleable#HostApduService_description &lt;android:description&gt;}
- * attribute that contains a user-friendly description of the service that may be shown in UI.
- * The
- * {@link android.R.styleable#HostApduService_requireDeviceUnlock &lt;requireDeviceUnlock&gt;}
- * attribute can be used to specify that the device must be unlocked before this service
- * can be invoked to handle APDUs.
- * <p>The {@link android.R.styleable#HostApduService &lt;host-apdu-service&gt;} must
- * contain one or more {@link android.R.styleable#AidGroup &lt;aid-group&gt;} tags.
- * Each {@link android.R.styleable#AidGroup &lt;aid-group&gt;} must contain one or
- * more {@link android.R.styleable#AidFilter &lt;aid-filter&gt;} tags, each of which
- * contains a single AID. The AID must be specified in hexadecimal format, and contain
- * an even number of characters.
- * <h3>AID conflict resolution</h3>
- * Multiple HostApduServices may be installed on a single device, and the same AID
- * can be registered by more than one service. The Android platform resolves AID
- * conflicts depending on which category an AID belongs to. Each category may
- * have a different conflict resolution policy. For example, for some categories
- * the user may be able to select a default service in the Android settings UI.
- * For other categories, to policy may be to always ask the user which service
- * is to be invoked in case of conflict.
- *
- * To query the conflict resolution policy for a certain category, see
- * {@link CardEmulation#getSelectionModeForCategory(String)}.
- *
- * <h3>Data exchange</h3>
- * <p>Once the platform has resolved a "SELECT AID" command APDU to a specific
- * service component, the "SELECT AID" command APDU and all subsequent
- * command APDUs will be sent to that service through
- * {@link #processCommandApdu(byte[], Bundle)}, until either:
- * <ul>
- * <li>The NFC link is broken</li>
- * <li>A "SELECT AID" APDU is received which resolves to another service</li>
- * </ul>
- * These two scenarios are indicated by a call to {@link #onDeactivated(int)}.
- *
- * <p class="note">Use of this class requires the
- * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
- * on the device.
- *
- */
-public abstract class HostApduService extends Service {
- /**
- * The {@link Intent} action that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.nfc.cardemulation.action.HOST_APDU_SERVICE";
-
- /**
- * The name of the meta-data element that contains
- * more information about this service.
- */
- public static final String SERVICE_META_DATA =
- "android.nfc.cardemulation.host_apdu_service";
-
- /**
- * Reason for {@link #onDeactivated(int)}.
- * Indicates deactivation was due to the NFC link
- * being lost.
- */
- public static final int DEACTIVATION_LINK_LOSS = 0;
-
- /**
- * Reason for {@link #onDeactivated(int)}.
- *
- * <p>Indicates deactivation was due to a different AID
- * being selected (which implicitly deselects the AID
- * currently active on the logical channel).
- *
- * <p>Note that this next AID may still be resolved to this
- * service, in which case {@link #processCommandApdu(byte[], Bundle)}
- * will be called again.
- */
- public static final int DEACTIVATION_DESELECTED = 1;
-
- static final String TAG = "ApduService";
-
- /**
- * MSG_COMMAND_APDU is sent by NfcService when
- * a 7816-4 command APDU has been received.
- *
- * @hide
- */
- public static final int MSG_COMMAND_APDU = 0;
-
- /**
- * MSG_RESPONSE_APDU is sent to NfcService to send
- * a response APDU back to the remote device.
- *
- * @hide
- */
- public static final int MSG_RESPONSE_APDU = 1;
-
- /**
- * MSG_DEACTIVATED is sent by NfcService when
- * the current session is finished; either because
- * another AID was selected that resolved to
- * another service, or because the NFC link
- * was deactivated.
- *
- * @hide
- */
- public static final int MSG_DEACTIVATED = 2;
-
- /**
- *
- * @hide
- */
- public static final int MSG_UNHANDLED = 3;
-
- /**
- * @hide
- */
- public static final int MSG_POLLING_LOOP = 4;
-
-
- /**
- * @hide
- */
- public static final String KEY_DATA = "data";
-
- /**
- * @hide
- */
- public static final String KEY_POLLING_LOOP_FRAMES_BUNDLE =
- "android.nfc.cardemulation.POLLING_FRAMES";
-
- /**
- * Messenger interface to NfcService for sending responses.
- * Only accessed on main thread by the message handler.
- *
- * @hide
- */
- Messenger mNfcService = null;
-
- final Messenger mMessenger = new Messenger(new MsgHandler());
-
- final class MsgHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_COMMAND_APDU:
- Bundle dataBundle = msg.getData();
- if (dataBundle == null) {
- return;
- }
- if (mNfcService == null) mNfcService = msg.replyTo;
-
- byte[] apdu = dataBundle.getByteArray(KEY_DATA);
- if (apdu != null) {
- HostApduService has = HostApduService.this;
- byte[] responseApdu = processCommandApdu(apdu, null);
- if (responseApdu != null) {
- if (mNfcService == null) {
- Log.e(TAG, "Response not sent; service was deactivated.");
- return;
- }
- Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU);
- Bundle responseBundle = new Bundle();
- responseBundle.putByteArray(KEY_DATA, responseApdu);
- responseMsg.setData(responseBundle);
- responseMsg.replyTo = mMessenger;
- try {
- mNfcService.send(responseMsg);
- } catch (RemoteException e) {
- Log.e(TAG, "Response not sent; RemoteException calling into " +
- "NfcService.");
- }
- }
- } else {
- Log.e(TAG, "Received MSG_COMMAND_APDU without data.");
- }
- break;
- case MSG_RESPONSE_APDU:
- if (mNfcService == null) {
- Log.e(TAG, "Response not sent; service was deactivated.");
- return;
- }
- try {
- msg.replyTo = mMessenger;
- mNfcService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling into NfcService.");
- }
- break;
- case MSG_DEACTIVATED:
- // Make sure we won't call into NfcService again
- mNfcService = null;
- onDeactivated(msg.arg1);
- break;
- case MSG_UNHANDLED:
- if (mNfcService == null) {
- Log.e(TAG, "notifyUnhandled not sent; service was deactivated.");
- return;
- }
- try {
- msg.replyTo = mMessenger;
- mNfcService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling into NfcService.");
- }
- break;
- case MSG_POLLING_LOOP:
- if (android.nfc.Flags.nfcReadPollingLoop()) {
- ArrayList<PollingFrame> pollingFrames =
- msg.getData().getParcelableArrayList(
- KEY_POLLING_LOOP_FRAMES_BUNDLE, PollingFrame.class);
- processPollingFrames(pollingFrames);
- }
- break;
- default:
- super.handleMessage(msg);
- }
- }
- }
-
- @Override
- public final IBinder onBind(Intent intent) {
- return mMessenger.getBinder();
- }
-
- /**
- * Sends a response APDU back to the remote device.
- *
- * <p>Note: this method may be called from any thread and will not block.
- * @param responseApdu A byte-array containing the reponse APDU.
- */
- public final void sendResponseApdu(byte[] responseApdu) {
- Message responseMsg = Message.obtain(null, MSG_RESPONSE_APDU);
- Bundle dataBundle = new Bundle();
- dataBundle.putByteArray(KEY_DATA, responseApdu);
- responseMsg.setData(dataBundle);
- try {
- mMessenger.send(responseMsg);
- } catch (RemoteException e) {
- Log.e("TAG", "Local messenger has died.");
- }
- }
-
- /**
- * Calling this method allows the service to tell the OS
- * that it won't be able to complete this transaction -
- * for example, because it requires data connectivity
- * that is not present at that moment.
- *
- * The OS may use this indication to give the user a list
- * of alternative applications that can handle the last
- * AID that was selected. If the user would select an
- * application from the list, that action by itself
- * will not cause the default to be changed; the selected
- * application will be invoked for the next tap only.
- *
- * If there are no other applications that can handle
- * this transaction, the OS will show an error dialog
- * indicating your service could not complete the
- * transaction.
- *
- * <p>Note: this method may be called anywhere between
- * the first {@link #processCommandApdu(byte[], Bundle)}
- * call and a {@link #onDeactivated(int)} call.
- */
- public final void notifyUnhandled() {
- Message unhandledMsg = Message.obtain(null, MSG_UNHANDLED);
- try {
- mMessenger.send(unhandledMsg);
- } catch (RemoteException e) {
- Log.e("TAG", "Local messenger has died.");
- }
- }
-
- /**
- * This method is called when polling frames have been received from a
- * remote device. If the device is in observe mode, the service should
- * call {@link NfcAdapter#allowTransaction()} once it is ready to proceed
- * with the transaction. If the device is not in observe mode, the service
- * can use this polling frame information to determine how to proceed if it
- * subsequently has {@link #processCommandApdu(byte[], Bundle)} called. The
- * service must override this method inorder to receive polling frames,
- * otherwise the base implementation drops the frame.
- *
- * @param frame A description of the polling frame.
- */
- @SuppressLint("OnNameExpected")
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public void processPollingFrames(@NonNull List<PollingFrame> frame) {
- }
-
- /**
- * <p>This method will be called when a command APDU has been received
- * from a remote device. A response APDU can be provided directly
- * by returning a byte-array in this method. Note that in general
- * response APDUs must be sent as quickly as possible, given the fact
- * that the user is likely holding their device over an NFC reader
- * when this method is called.
- *
- * <p class="note">If there are multiple services that have registered for the same
- * AIDs in their meta-data entry, you will only get called if the user has
- * explicitly selected your service, either as a default or just for the next tap.
- *
- * <p class="note">This method is running on the main thread of your application.
- * If you cannot return a response APDU immediately, return null
- * and use the {@link #sendResponseApdu(byte[])} method later.
- *
- * @param commandApdu The APDU that was received from the remote device
- * @param extras A bundle containing extra data. May be null.
- * @return a byte-array containing the response APDU, or null if no
- * response APDU can be sent at this point.
- */
- public abstract byte[] processCommandApdu(byte[] commandApdu, Bundle extras);
-
- /**
- * This method will be called in two possible scenarios:
- * <li>The NFC link has been deactivated or lost
- * <li>A different AID has been selected and was resolved to a different
- * service component
- * @param reason Either {@link #DEACTIVATION_LINK_LOSS} or {@link #DEACTIVATION_DESELECTED}
- */
- public abstract void onDeactivated(int reason);
-
-}
diff --git a/nfc/java/android/nfc/cardemulation/HostNfcFService.java b/nfc/java/android/nfc/cardemulation/HostNfcFService.java
deleted file mode 100644
index 65b5ca77de62..000000000000
--- a/nfc/java/android/nfc/cardemulation/HostNfcFService.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc.cardemulation;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
-import android.content.ComponentName;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.RemoteException;
-import android.util.Log;
-
-/**
- * <p>HostNfcFService is a convenience {@link Service} class that can be
- * extended to emulate an NFC-F card inside an Android service component.
- *
- * <h3>NFC Protocols</h3>
- * <p>Cards emulated by this class are based on the NFC-Forum NFC-F
- * protocol (based on the JIS-X 6319-4 specification.)</p>
- *
- * <h3>System Code and NFCID2 registration</h3>
- * <p>A {@link HostNfcFService HostNfcFService service} can register
- * exactly one System Code and one NFCID2. For details about the use of
- * System Code and NFCID2, see the NFC Forum Digital specification.</p>
- * <p>To statically register a System Code and NFCID2 with the service, a {@link #SERVICE_META_DATA}
- * entry must be included in the declaration of the service.
- *
- * <p>All {@link HostNfcFService HostNfcFService} declarations in the manifest must require the
- * {@link android.Manifest.permission#BIND_NFC_SERVICE} permission
- * in their &lt;service&gt; tag, to ensure that only the platform can bind to your service.</p>
- *
- * <p>An example of a HostNfcFService manifest declaration is shown below:
- *
- * <pre> &lt;service android:name=".MyHostNfcFService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"&gt;
- * &lt;intent-filter&gt;
- * &lt;action android:name="android.nfc.cardemulation.action.HOST_NFCF_SERVICE"/&gt;
- * &lt;/intent-filter&gt;
- * &lt;meta-data android:name="android.nfc.cardemulation.host_nfcf_service" android:resource="@xml/nfcfservice"/&gt;
- * &lt;/service&gt;</pre>
- *
- * This meta-data tag points to an nfcfservice.xml file.
- * An example of this file with a System Code and NFCID2 declaration is shown below:
- * <pre>
- * &lt;host-nfcf-service xmlns:android="http://schemas.android.com/apk/res/android"
- * android:description="@string/servicedesc"&gt;
- * &lt;system-code-filter android:name="4000"/&gt;
- * &lt;nfcid2-filter android:name="02FE000000000000"/&gt;
- &lt;t3tPmm-filter android:name="FFFFFFFFFFFFFFFF"/&gt;
- * &lt;/host-nfcf-service&gt;
- * </pre>
- *
- * <p>The {@link android.R.styleable#HostNfcFService &lt;host-nfcf-service&gt;} is required
- * to contain a
- * {@link android.R.styleable#HostApduService_description &lt;android:description&gt;}
- * attribute that contains a user-friendly description of the service that may be shown in UI.
- * <p>The {@link android.R.styleable#HostNfcFService &lt;host-nfcf-service&gt;} must
- * contain:
- * <ul>
- * <li>Exactly one {@link android.R.styleable#SystemCodeFilter &lt;system-code-filter&gt;} tag.</li>
- * <li>Exactly one {@link android.R.styleable#Nfcid2Filter &lt;nfcid2-filter&gt;} tag.</li>
- * <li>Zero or one {@link android.R.styleable#T3tPmmFilter &lt;t3tPmm-filter&gt;} tag.</li>
- * </ul>
- * </p>
- *
- * <p>Alternatively, the System Code and NFCID2 can be dynamically registererd for a service
- * by using the {@link NfcFCardEmulation#registerSystemCodeForService(ComponentName, String)} and
- * {@link NfcFCardEmulation#setNfcid2ForService(ComponentName, String)} methods.
- * </p>
- *
- * <h3>Service selection</h3>
- * <p>When a remote NFC devices wants to communicate with your service, it
- * sends a SENSF_REQ command to the NFC controller, requesting a System Code.
- * If a {@link NfcFCardEmulation NfcFCardEmulation service} has registered
- * this system code and has been enabled by the foreground application, the
- * NFC controller will respond with the NFCID2 that is registered for this service.
- * The reader can then continue data exchange with this service by using the NFCID2.</p>
- *
- * <h3>Data exchange</h3>
- * <p>After service selection, all frames addressed to the NFCID2 of this service will
- * be sent through {@link #processNfcFPacket(byte[], Bundle)}, until the NFC link is
- * broken.<p>
- *
- * <p>When the NFC link is broken, {@link #onDeactivated(int)} will be called.</p>
- */
-public abstract class HostNfcFService extends Service {
- /**
- * The {@link Intent} action that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.nfc.cardemulation.action.HOST_NFCF_SERVICE";
-
- /**
- * The name of the meta-data element that contains
- * more information about this service.
- */
- public static final String SERVICE_META_DATA =
- "android.nfc.cardemulation.host_nfcf_service";
-
- /**
- * Reason for {@link #onDeactivated(int)}.
- * Indicates deactivation was due to the NFC link
- * being lost.
- */
- public static final int DEACTIVATION_LINK_LOSS = 0;
-
- static final String TAG = "NfcFService";
-
- /**
- * MSG_COMMAND_PACKET is sent by NfcService when
- * a NFC-F command packet has been received.
- *
- * @hide
- */
- public static final int MSG_COMMAND_PACKET = 0;
-
- /**
- * MSG_RESPONSE_PACKET is sent to NfcService to send
- * a response packet back to the remote device.
- *
- * @hide
- */
- public static final int MSG_RESPONSE_PACKET = 1;
-
- /**
- * MSG_DEACTIVATED is sent by NfcService when
- * the current session is finished; because
- * the NFC link was deactivated.
- *
- * @hide
- */
- public static final int MSG_DEACTIVATED = 2;
-
- /**
- * @hide
- */
- public static final String KEY_DATA = "data";
-
- /**
- * @hide
- */
- public static final String KEY_MESSENGER = "messenger";
-
- /**
- * Messenger interface to NfcService for sending responses.
- * Only accessed on main thread by the message handler.
- *
- * @hide
- */
- Messenger mNfcService = null;
-
- final Messenger mMessenger = new Messenger(new MsgHandler());
-
- final class MsgHandler extends Handler {
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_COMMAND_PACKET:
- Bundle dataBundle = msg.getData();
- if (dataBundle == null) {
- return;
- }
- if (mNfcService == null) mNfcService = msg.replyTo;
-
- byte[] packet = dataBundle.getByteArray(KEY_DATA);
- if (packet != null) {
- byte[] responsePacket = processNfcFPacket(packet, null);
- if (responsePacket != null) {
- if (mNfcService == null) {
- Log.e(TAG, "Response not sent; service was deactivated.");
- return;
- }
- Message responseMsg = Message.obtain(null, MSG_RESPONSE_PACKET);
- Bundle responseBundle = new Bundle();
- responseBundle.putByteArray(KEY_DATA, responsePacket);
- responseMsg.setData(responseBundle);
- responseMsg.replyTo = mMessenger;
- try {
- mNfcService.send(responseMsg);
- } catch (RemoteException e) {
- Log.e("TAG", "Response not sent; RemoteException calling into " +
- "NfcService.");
- }
- }
- } else {
- Log.e(TAG, "Received MSG_COMMAND_PACKET without data.");
- }
- break;
- case MSG_RESPONSE_PACKET:
- if (mNfcService == null) {
- Log.e(TAG, "Response not sent; service was deactivated.");
- return;
- }
- try {
- msg.replyTo = mMessenger;
- mNfcService.send(msg);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException calling into NfcService.");
- }
- break;
- case MSG_DEACTIVATED:
- // Make sure we won't call into NfcService again
- mNfcService = null;
- onDeactivated(msg.arg1);
- break;
- default:
- super.handleMessage(msg);
- }
- }
- }
-
- @Override
- public final IBinder onBind(Intent intent) {
- return mMessenger.getBinder();
- }
-
- /**
- * Sends a response packet back to the remote device.
- *
- * <p>Note: this method may be called from any thread and will not block.
- * @param responsePacket A byte-array containing the response packet.
- */
- public final void sendResponsePacket(byte[] responsePacket) {
- Message responseMsg = Message.obtain(null, MSG_RESPONSE_PACKET);
- Bundle dataBundle = new Bundle();
- dataBundle.putByteArray(KEY_DATA, responsePacket);
- responseMsg.setData(dataBundle);
- try {
- mMessenger.send(responseMsg);
- } catch (RemoteException e) {
- Log.e("TAG", "Local messenger has died.");
- }
- }
-
- /**
- * <p>This method will be called when a NFC-F packet has been received
- * from a remote device. A response packet can be provided directly
- * by returning a byte-array in this method. Note that in general
- * response packets must be sent as quickly as possible, given the fact
- * that the user is likely holding their device over an NFC reader
- * when this method is called.
- *
- * <p class="note">This method is running on the main thread of your application.
- * If you cannot return a response packet immediately, return null
- * and use the {@link #sendResponsePacket(byte[])} method later.
- *
- * @param commandPacket The NFC-F packet that was received from the remote device
- * @param extras A bundle containing extra data. May be null.
- * @return a byte-array containing the response packet, or null if no
- * response packet can be sent at this point.
- */
- public abstract byte[] processNfcFPacket(byte[] commandPacket, Bundle extras);
-
- /**
- * This method will be called in following possible scenarios:
- * <li>The NFC link has been lost
- * @param reason {@link #DEACTIVATION_LINK_LOSS}
- */
- public abstract void onDeactivated(int reason);
-}
diff --git a/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java b/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java
deleted file mode 100644
index 48bbf5b61052..000000000000
--- a/nfc/java/android/nfc/cardemulation/NfcFCardEmulation.java
+++ /dev/null
@@ -1,473 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc.cardemulation;
-
-import android.app.Activity;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.nfc.INfcFCardEmulation;
-import android.nfc.NfcAdapter;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * This class can be used to query the state of
- * NFC-F card emulation services.
- *
- * For a general introduction into NFC card emulation,
- * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
- * NFC card emulation developer guide</a>.</p>
- *
- * <p class="note">Use of this class requires the
- * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION_NFCF}
- * to be present on the device.
- */
-public final class NfcFCardEmulation {
- static final String TAG = "NfcFCardEmulation";
-
- static boolean sIsInitialized = false;
- static HashMap<Context, NfcFCardEmulation> sCardEmus = new HashMap<Context, NfcFCardEmulation>();
- static INfcFCardEmulation sService;
-
- final Context mContext;
-
- private NfcFCardEmulation(Context context, INfcFCardEmulation service) {
- mContext = context.getApplicationContext();
- sService = service;
- }
-
- /**
- * Helper to get an instance of this class.
- *
- * @param adapter A reference to an NfcAdapter object.
- * @return
- */
- public static synchronized NfcFCardEmulation getInstance(NfcAdapter adapter) {
- if (adapter == null) throw new NullPointerException("NfcAdapter is null");
- Context context = adapter.getContext();
- if (context == null) {
- Log.e(TAG, "NfcAdapter context is null.");
- throw new UnsupportedOperationException();
- }
- if (!sIsInitialized) {
- PackageManager pm = context.getPackageManager();
- if (pm == null) {
- Log.e(TAG, "Cannot get PackageManager");
- throw new UnsupportedOperationException();
- }
- if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) {
- Log.e(TAG, "This device does not support NFC-F card emulation");
- throw new UnsupportedOperationException();
- }
- sIsInitialized = true;
- }
- NfcFCardEmulation manager = sCardEmus.get(context);
- if (manager == null) {
- // Get card emu service
- INfcFCardEmulation service = adapter.getNfcFCardEmulationService();
- if (service == null) {
- Log.e(TAG, "This device does not implement the INfcFCardEmulation interface.");
- throw new UnsupportedOperationException();
- }
- manager = new NfcFCardEmulation(context, service);
- sCardEmus.put(context, manager);
- }
- return manager;
- }
-
- /**
- * Retrieves the current System Code for the specified service.
- *
- * <p>Before calling {@link #registerSystemCodeForService(ComponentName, String)},
- * the System Code contained in the Manifest file is returned. After calling
- * {@link #registerSystemCodeForService(ComponentName, String)}, the System Code
- * registered there is returned. After calling
- * {@link #unregisterSystemCodeForService(ComponentName)}, "null" is returned.
- *
- * @param service The component name of the service
- * @return the current System Code
- */
- public String getSystemCodeForService(ComponentName service) throws RuntimeException {
- if (service == null) {
- throw new NullPointerException("service is null");
- }
- try {
- return sService.getSystemCodeForService(mContext.getUser().getIdentifier(), service);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return null;
- }
- try {
- return sService.getSystemCodeForService(mContext.getUser().getIdentifier(),
- service);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return null;
- }
- }
- }
-
- /**
- * Registers a System Code for the specified service.
- *
- * <p>The System Code must be in range from "4000" to "4FFF" (excluding "4*FF").
- *
- * <p>If a System Code was previously registered for this service
- * (either statically through the manifest, or dynamically by using this API),
- * it will be replaced with this one.
- *
- * <p>Even if the same System Code is already registered for another service,
- * this method succeeds in registering the System Code.
- *
- * <p>Note that you can only register a System Code for a service that
- * is running under the same UID as the caller of this API. Typically
- * this means you need to call this from the same
- * package as the service itself, though UIDs can also
- * be shared between packages using shared UIDs.
- *
- * @param service The component name of the service
- * @param systemCode The System Code to be registered
- * @return whether the registration was successful.
- */
- public boolean registerSystemCodeForService(ComponentName service, String systemCode)
- throws RuntimeException {
- if (service == null || systemCode == null) {
- throw new NullPointerException("service or systemCode is null");
- }
- try {
- return sService.registerSystemCodeForService(mContext.getUser().getIdentifier(),
- service, systemCode);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.registerSystemCodeForService(mContext.getUser().getIdentifier(),
- service, systemCode);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return false;
- }
- }
- }
-
- /**
- * Removes a registered System Code for the specified service.
- *
- * @param service The component name of the service
- * @return whether the System Code was successfully removed.
- */
- public boolean unregisterSystemCodeForService(ComponentName service) throws RuntimeException {
- if (service == null) {
- throw new NullPointerException("service is null");
- }
- try {
- return sService.removeSystemCodeForService(mContext.getUser().getIdentifier(), service);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.removeSystemCodeForService(mContext.getUser().getIdentifier(),
- service);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return false;
- }
- }
- }
-
- /**
- * Retrieves the current NFCID2 for the specified service.
- *
- * <p>Before calling {@link #setNfcid2ForService(ComponentName, String)},
- * the NFCID2 contained in the Manifest file is returned. If "random" is specified
- * in the Manifest file, a random number assigned by the system at installation time
- * is returned. After setting an NFCID2
- * with {@link #setNfcid2ForService(ComponentName, String)}, this NFCID2 is returned.
- *
- * @param service The component name of the service
- * @return the current NFCID2
- */
- public String getNfcid2ForService(ComponentName service) throws RuntimeException {
- if (service == null) {
- throw new NullPointerException("service is null");
- }
- try {
- return sService.getNfcid2ForService(mContext.getUser().getIdentifier(), service);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return null;
- }
- try {
- return sService.getNfcid2ForService(mContext.getUser().getIdentifier(), service);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return null;
- }
- }
- }
-
- /**
- * Set a NFCID2 for the specified service.
- *
- * <p>The NFCID2 must be in range from "02FE000000000000" to "02FEFFFFFFFFFFFF".
- *
- * <p>If a NFCID2 was previously set for this service
- * (either statically through the manifest, or dynamically by using this API),
- * it will be replaced.
- *
- * <p>Note that you can only set the NFCID2 for a service that
- * is running under the same UID as the caller of this API. Typically
- * this means you need to call this from the same
- * package as the service itself, though UIDs can also
- * be shared between packages using shared UIDs.
- *
- * @param service The component name of the service
- * @param nfcid2 The NFCID2 to be registered
- * @return whether the setting was successful.
- */
- public boolean setNfcid2ForService(ComponentName service, String nfcid2)
- throws RuntimeException {
- if (service == null || nfcid2 == null) {
- throw new NullPointerException("service or nfcid2 is null");
- }
- try {
- return sService.setNfcid2ForService(mContext.getUser().getIdentifier(),
- service, nfcid2);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.setNfcid2ForService(mContext.getUser().getIdentifier(),
- service, nfcid2);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return false;
- }
- }
- }
-
- /**
- * Allows a foreground application to specify which card emulation service
- * should be enabled while a specific Activity is in the foreground.
- *
- * <p>The specified HCE-F service is only enabled when the corresponding application is
- * in the foreground and this method has been called. When the application is moved to
- * the background, {@link #disableService(Activity)} is called, or
- * NFCID2 or System Code is replaced, the HCE-F service is disabled.
- *
- * <p>The specified Activity must currently be in resumed state. A good
- * paradigm is to call this method in your {@link Activity#onResume}, and to call
- * {@link #disableService(Activity)} in your {@link Activity#onPause}.
- *
- * <p>Note that this preference is not persisted by the OS, and hence must be
- * called every time the Activity is resumed.
- *
- * @param activity The activity which prefers this service to be invoked
- * @param service The service to be preferred while this activity is in the foreground
- * @return whether the registration was successful
- */
- public boolean enableService(Activity activity, ComponentName service) throws RuntimeException {
- if (activity == null || service == null) {
- throw new NullPointerException("activity or service is null");
- }
- // Verify the activity is in the foreground before calling into NfcService
- if (!activity.isResumed()) {
- throw new IllegalArgumentException("Activity must be resumed.");
- }
- try {
- return sService.enableNfcFForegroundService(service);
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.enableNfcFForegroundService(service);
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return false;
- }
- }
- }
-
- /**
- * Disables the service for the specified Activity.
- *
- * <p>Note that the specified Activity must still be in resumed
- * state at the time of this call. A good place to call this method
- * is in your {@link Activity#onPause} implementation.
- *
- * @param activity The activity which the service was registered for
- * @return true when successful
- */
- public boolean disableService(Activity activity) throws RuntimeException {
- if (activity == null) {
- throw new NullPointerException("activity is null");
- }
- if (!activity.isResumed()) {
- throw new IllegalArgumentException("Activity must be resumed.");
- }
- try {
- return sService.disableNfcFForegroundService();
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return false;
- }
- try {
- return sService.disableNfcFForegroundService();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- ee.rethrowAsRuntimeException();
- return false;
- }
- }
- }
-
- /**
- * @hide
- */
- public List<NfcFServiceInfo> getNfcFServices() {
- try {
- return sService.getNfcFServices(mContext.getUser().getIdentifier());
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return null;
- }
- try {
- return sService.getNfcFServices(mContext.getUser().getIdentifier());
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- return null;
- }
- }
- }
-
- /**
- * @hide
- */
- public int getMaxNumOfRegisterableSystemCodes() {
- try {
- return sService.getMaxNumOfRegisterableSystemCodes();
- } catch (RemoteException e) {
- // Try one more time
- recoverService();
- if (sService == null) {
- Log.e(TAG, "Failed to recover CardEmulationService.");
- return -1;
- }
- try {
- return sService.getMaxNumOfRegisterableSystemCodes();
- } catch (RemoteException ee) {
- Log.e(TAG, "Failed to reach CardEmulationService.");
- return -1;
- }
- }
- }
-
- /**
- * @hide
- */
- public static boolean isValidSystemCode(String systemCode) {
- if (systemCode == null) {
- return false;
- }
- if (systemCode.length() != 4) {
- Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
- return false;
- }
- // check if the value is between "4000" and "4FFF" (excluding "4*FF")
- if (!systemCode.startsWith("4") || systemCode.toUpperCase().endsWith("FF")) {
- Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
- return false;
- }
- try {
- Integer.parseInt(systemCode, 16);
- } catch (NumberFormatException e) {
- Log.e(TAG, "System Code " + systemCode + " is not a valid System Code.");
- return false;
- }
- return true;
- }
-
- /**
- * @hide
- */
- public static boolean isValidNfcid2(String nfcid2) {
- if (nfcid2 == null) {
- return false;
- }
- if (nfcid2.length() != 16) {
- Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
- return false;
- }
- // check if the the value starts with "02FE"
- if (!nfcid2.toUpperCase().startsWith("02FE")) {
- Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
- return false;
- }
- try {
- Long.parseLong(nfcid2, 16);
- } catch (NumberFormatException e) {
- Log.e(TAG, "NFCID2 " + nfcid2 + " is not a valid NFCID2.");
- return false;
- }
- return true;
- }
-
- void recoverService() {
- NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
- sService = adapter.getNfcFCardEmulationService();
- }
-
-}
-
diff --git a/nfc/java/android/nfc/cardemulation/OffHostApduService.java b/nfc/java/android/nfc/cardemulation/OffHostApduService.java
deleted file mode 100644
index 8d8a17270523..000000000000
--- a/nfc/java/android/nfc/cardemulation/OffHostApduService.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2015 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.nfc.cardemulation;
-
-import android.annotation.SdkConstant;
-import android.annotation.SdkConstant.SdkConstantType;
-import android.app.Service;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.IBinder;
-
-/**
- * <p>OffHostApduService is a convenience {@link Service} class that can be
- * extended to describe one or more NFC applications that are residing
- * off-host, for example on an embedded secure element or a UICC.
- *
- * <div class="special reference">
- * <h3>Developer Guide</h3>
- * For a general introduction into the topic of card emulation,
- * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html">
- * NFC card emulation developer guide.</a></p>
- * </div>
- *
- * <h3>NFC Protocols</h3>
- * <p>Off-host applications represented by this class are based on the NFC-Forum ISO-DEP
- * protocol (based on ISO/IEC 14443-4) and support processing
- * command Application Protocol Data Units (APDUs) as
- * defined in the ISO/IEC 7816-4 specification.
- *
- * <h3>Service selection</h3>
- * <p>When a remote NFC device wants to talk to your
- * off-host NFC application, it sends a so-called
- * "SELECT AID" APDU as defined in the ISO/IEC 7816-4 specification.
- * The AID is an application identifier defined in ISO/IEC 7816-4.
- *
- * <p>The registration procedure for AIDs is defined in the
- * ISO/IEC 7816-5 specification. If you don't want to register an
- * AID, you are free to use AIDs in the proprietary range:
- * bits 8-5 of the first byte must each be set to '1'. For example,
- * "0xF00102030405" is a proprietary AID. If you do use proprietary
- * AIDs, it is recommended to choose an AID of at least 6 bytes,
- * to reduce the risk of collisions with other applications that
- * might be using proprietary AIDs as well.
- *
- * <h3>AID groups</h3>
- * <p>In some cases, an off-host environment may need to register multiple AIDs
- * to implement a certain application, and it needs to be sure
- * that it is the default handler for all of these AIDs (as opposed
- * to some AIDs in the group going to another service).
- *
- * <p>An AID group is a list of AIDs that should be considered as
- * belonging together by the OS. For all AIDs in an AID group, the
- * OS will guarantee one of the following:
- * <ul>
- * <li>All AIDs in the group are routed to the off-host execution environment
- * <li>No AIDs in the group are routed to the off-host execution environment
- * </ul>
- * In other words, there is no in-between state, where some AIDs
- * in the group can be routed to this off-host execution environment,
- * and some to another or a host-based {@link HostApduService}.
- * <h3>AID groups and categories</h3>
- * <p>Each AID group can be associated with a category. This allows
- * the Android OS to classify services, and it allows the user to
- * set defaults at the category level instead of the AID level.
- *
- * <p>You can use
- * {@link CardEmulation#isDefaultServiceForCategory(android.content.ComponentName, String)}
- * to determine if your off-host service is the default handler for a category.
- *
- * <p>In this version of the platform, the only known categories
- * are {@link CardEmulation#CATEGORY_PAYMENT} and {@link CardEmulation#CATEGORY_OTHER}.
- * AID groups without a category, or with a category that is not recognized
- * by the current platform version, will automatically be
- * grouped into the {@link CardEmulation#CATEGORY_OTHER} category.
- *
- * <h3>Service AID registration</h3>
- * <p>To tell the platform which AIDs
- * reside off-host and are managed by this service, a {@link #SERVICE_META_DATA}
- * entry must be included in the declaration of the service. An
- * example of a OffHostApduService manifest declaration is shown below:
- * <pre> &lt;service android:name=".MyOffHostApduService" android:exported="true" android:permission="android.permission.BIND_NFC_SERVICE"&gt;
- * &lt;intent-filter&gt;
- * &lt;action android:name="android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE"/&gt;
- * &lt;/intent-filter&gt;
- * &lt;meta-data android:name="android.nfc.cardemulation.off_host_apdu_service" android:resource="@xml/apduservice"/&gt;
- * &lt;/service&gt;</pre>
- *
- * This meta-data tag points to an apduservice.xml file.
- * An example of this file with a single AID group declaration is shown below:
- * <pre>
- * &lt;offhost-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
- * android:description="@string/servicedesc"&gt;
- * &lt;aid-group android:description="@string/subscription" android:category="other">
- * &lt;aid-filter android:name="F0010203040506"/&gt;
- * &lt;aid-filter android:name="F0394148148100"/&gt;
- * &lt;/aid-group&gt;
- * &lt;/offhost-apdu-service&gt;
- * </pre>
- *
- * <p>The {@link android.R.styleable#OffHostApduService &lt;offhost-apdu-service&gt;} is required
- * to contain a
- * {@link android.R.styleable#OffHostApduService_description &lt;android:description&gt;}
- * attribute that contains a user-friendly description of the service that may be shown in UI.
- *
- * <p>The {@link android.R.styleable#OffHostApduService &lt;offhost-apdu-service&gt;} must
- * contain one or more {@link android.R.styleable#AidGroup &lt;aid-group&gt;} tags.
- * Each {@link android.R.styleable#AidGroup &lt;aid-group&gt;} must contain one or
- * more {@link android.R.styleable#AidFilter &lt;aid-filter&gt;} tags, each of which
- * contains a single AID. The AID must be specified in hexadecimal format, and contain
- * an even number of characters.
- *
- * <p>This registration will allow the service to be included
- * as an option for being the default handler for categories.
- * The Android OS will take care of correctly
- * routing the AIDs to the off-host execution environment,
- * based on which service the user has selected to be the handler for a certain category.
- *
- * <p>The service may define additional actions outside of the
- * Android namespace that provide further interaction with
- * the off-host execution environment.
- *
- * <p class="note">Use of this class requires the
- * {@link PackageManager#FEATURE_NFC_HOST_CARD_EMULATION} to be present
- * on the device.
- */
-public abstract class OffHostApduService extends Service {
- /**
- * The {@link Intent} action that must be declared as handled by the service.
- */
- @SdkConstant(SdkConstantType.SERVICE_ACTION)
- public static final String SERVICE_INTERFACE =
- "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE";
-
- /**
- * The name of the meta-data element that contains
- * more information about this service.
- */
- public static final String SERVICE_META_DATA =
- "android.nfc.cardemulation.off_host_apdu_service";
-
- /**
- * The Android platform itself will not bind to this service,
- * but merely uses its declaration to keep track of what AIDs
- * the service is interested in. This information is then used
- * to present the user with a list of applications that can handle
- * an AID, as well as correctly route those AIDs either to the host (in case
- * the user preferred a {@link HostApduService}), or to an off-host
- * execution environment (in case the user preferred a {@link OffHostApduService}.
- *
- * Implementers may define additional actions outside of the
- * Android namespace that allow further interactions with
- * the off-host execution environment. Such implementations
- * would need to override this method.
- */
- public abstract IBinder onBind(Intent intent);
-}
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.aidl b/nfc/java/android/nfc/cardemulation/PollingFrame.aidl
deleted file mode 100644
index 8e09f8baaff2..000000000000
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- * 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.nfc.cardemulation;
-
-parcelable PollingFrame; \ No newline at end of file
diff --git a/nfc/java/android/nfc/cardemulation/PollingFrame.java b/nfc/java/android/nfc/cardemulation/PollingFrame.java
deleted file mode 100644
index 5dcc84ccf8b9..000000000000
--- a/nfc/java/android/nfc/cardemulation/PollingFrame.java
+++ /dev/null
@@ -1,283 +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.nfc.cardemulation;
-
-import android.annotation.FlaggedApi;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.HexFormat;
-import java.util.List;
-
-/**
- * Polling Frames represent data about individual frames of an NFC polling loop. These frames will
- * be delivered to subclasses of {@link HostApduService} that have registered filters with
- * {@link CardEmulation#registerPollingLoopFilterForService(ComponentName, String, boolean)} that
- * match a given frame in a loop and will be delivered through calls to
- * {@link HostApduService#processPollingFrames(List)}.
- */
-@FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
-public final class PollingFrame implements Parcelable {
-
- /**
- * @hide
- */
- @IntDef(prefix = { "POLLING_LOOP_TYPE_"},
- value = {
- POLLING_LOOP_TYPE_A,
- POLLING_LOOP_TYPE_B,
- POLLING_LOOP_TYPE_F,
- POLLING_LOOP_TYPE_OFF,
- POLLING_LOOP_TYPE_ON,
- POLLING_LOOP_TYPE_UNKNOWN
- })
- @Retention(RetentionPolicy.SOURCE)
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public @interface PollingFrameType {}
-
- /**
- * POLLING_LOOP_TYPE_A is the value associated with the key
- * POLLING_LOOP_TYPE in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
- * when the polling loop is for NFC-A.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static final int POLLING_LOOP_TYPE_A = 'A';
-
- /**
- * POLLING_LOOP_TYPE_B is the value associated with the key
- * POLLING_LOOP_TYPE in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
- * when the polling loop is for NFC-B.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static final int POLLING_LOOP_TYPE_B = 'B';
-
- /**
- * POLLING_LOOP_TYPE_F is the value associated with the key
- * POLLING_LOOP_TYPE in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
- * when the polling loop is for NFC-F.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static final int POLLING_LOOP_TYPE_F = 'F';
-
- /**
- * POLLING_LOOP_TYPE_ON is the value associated with the key
- * POLLING_LOOP_TYPE in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
- * when the polling loop turns on.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static final int POLLING_LOOP_TYPE_ON = 'O';
-
- /**
- * POLLING_LOOP_TYPE_OFF is the value associated with the key
- * POLLING_LOOP_TYPE in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
- * when the polling loop turns off.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static final int POLLING_LOOP_TYPE_OFF = 'X';
-
- /**
- * POLLING_LOOP_TYPE_UNKNOWN is the value associated with the key
- * POLLING_LOOP_TYPE in the Bundle passed to {@link HostApduService#processPollingFrames(List)}
- * when the polling loop frame isn't recognized.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- public static final int POLLING_LOOP_TYPE_UNKNOWN = 'U';
-
- /**
- * KEY_POLLING_LOOP_TYPE is the Bundle key for the type of
- * polling loop frame in the Bundle included in MSG_POLLING_LOOP.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- private static final String KEY_POLLING_LOOP_TYPE = "android.nfc.cardemulation.TYPE";
-
- /**
- * KEY_POLLING_LOOP_DATA is the Bundle key for the raw data of captured from
- * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- private static final String KEY_POLLING_LOOP_DATA = "android.nfc.cardemulation.DATA";
-
- /**
- * KEY_POLLING_LOOP_GAIN is the Bundle key for the field strength of
- * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- private static final String KEY_POLLING_LOOP_GAIN = "android.nfc.cardemulation.GAIN";
-
- /**
- * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for the timestamp of
- * the polling loop frame in the Bundle included in MSG_POLLING_LOOP.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- private static final String KEY_POLLING_LOOP_TIMESTAMP = "android.nfc.cardemulation.TIMESTAMP";
-
- /**
- * KEY_POLLING_LOOP_TIMESTAMP is the Bundle key for whether this polling frame triggered
- * autoTransact in the Bundle included in MSG_POLLING_LOOP.
- */
- @FlaggedApi(android.nfc.Flags.FLAG_NFC_READ_POLLING_LOOP)
- private static final String KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT =
- "android.nfc.cardemulation.TRIGGERED_AUTOTRANSACT";
-
-
- @PollingFrameType
- private final int mType;
- private final byte[] mData;
- private final int mGain;
- private final long mTimestamp;
- private boolean mTriggeredAutoTransact;
-
- public static final @NonNull Parcelable.Creator<PollingFrame> CREATOR =
- new Parcelable.Creator<>() {
- @Override
- public PollingFrame createFromParcel(Parcel source) {
- return new PollingFrame(source.readBundle());
- }
-
- @Override
- public PollingFrame[] newArray(int size) {
- return new PollingFrame[size];
- }
- };
-
- private PollingFrame(Bundle frame) {
- mType = frame.getInt(KEY_POLLING_LOOP_TYPE);
- byte[] data = frame.getByteArray(KEY_POLLING_LOOP_DATA);
- mData = (data == null) ? new byte[0] : data;
- mGain = frame.getInt(KEY_POLLING_LOOP_GAIN, -1);
- mTimestamp = frame.getLong(KEY_POLLING_LOOP_TIMESTAMP);
- mTriggeredAutoTransact = frame.containsKey(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT)
- && frame.getBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT);
- }
-
- /**
- * Constructor for Polling Frames.
- *
- * @param type the type of the frame
- * @param data a byte array of the data contained in the frame
- * @param gain the vendor-specific gain of the field
- * @param timestampMicros the timestamp in microseconds
- * @param triggeredAutoTransact whether or not this frame triggered the device to start a
- * transaction automatically
- *
- * @hide
- */
- public PollingFrame(@PollingFrameType int type, @Nullable byte[] data,
- int gain, long timestampMicros, boolean triggeredAutoTransact) {
- mType = type;
- mData = data == null ? new byte[0] : data;
- mGain = gain;
- mTimestamp = timestampMicros;
- mTriggeredAutoTransact = triggeredAutoTransact;
- }
-
- /**
- * Returns the type of frame for this polling loop frame.
- * The possible return values are:
- * <ul>
- * <li>{@link #POLLING_LOOP_TYPE_ON}</li>
- * <li>{@link #POLLING_LOOP_TYPE_OFF}</li>
- * <li>{@link #POLLING_LOOP_TYPE_A}</li>
- * <li>{@link #POLLING_LOOP_TYPE_B}</li>
- * <li>{@link #POLLING_LOOP_TYPE_F}</li>
- * </ul>
- */
- public @PollingFrameType int getType() {
- return mType;
- }
-
- /**
- * Returns the raw data from the polling type frame.
- */
- public @NonNull byte[] getData() {
- return mData;
- }
-
- /**
- * Returns the gain representing the field strength of the NFC field when this polling loop
- * frame was observed.
- * @return the gain or -1 if there is no gain measurement associated with this frame.
- */
- public int getVendorSpecificGain() {
- return mGain;
- }
-
- /**
- * Returns the timestamp of when the polling loop frame was observed, in microseconds. These
- * timestamps are relative and should only be used for comparing the timing of frames relative
- * to each other.
- * @return the timestamp in microseconds
- */
- public long getTimestamp() {
- return mTimestamp;
- }
-
- /**
- * @hide
- */
- public void setTriggeredAutoTransact(boolean triggeredAutoTransact) {
- mTriggeredAutoTransact = triggeredAutoTransact;
- }
-
- /**
- * Returns whether this frame triggered the device to automatically disable observe mode and
- * allow one transaction.
- */
- public boolean getTriggeredAutoTransact() {
- return mTriggeredAutoTransact;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeBundle(toBundle());
- }
-
- /**
- * @return a Bundle representing this frame
- */
- private Bundle toBundle() {
- Bundle frame = new Bundle();
- frame.putInt(KEY_POLLING_LOOP_TYPE, getType());
- if (getVendorSpecificGain() != -1) {
- frame.putInt(KEY_POLLING_LOOP_GAIN, (byte) getVendorSpecificGain());
- }
- frame.putByteArray(KEY_POLLING_LOOP_DATA, getData());
- frame.putLong(KEY_POLLING_LOOP_TIMESTAMP, getTimestamp());
- frame.putBoolean(KEY_POLLING_LOOP_TRIGGERED_AUTOTRANSACT, getTriggeredAutoTransact());
- return frame;
- }
-
- @Override
- public String toString() {
- return "PollingFrame { Type: " + (char) getType()
- + ", gain: " + getVendorSpecificGain()
- + ", timestamp: " + Long.toUnsignedString(getTimestamp())
- + ", data: [" + HexFormat.ofDelimiter(" ").formatHex(getData()) + "] }";
- }
-}
diff --git a/nfc/java/android/nfc/cardemulation/Utils.java b/nfc/java/android/nfc/cardemulation/Utils.java
deleted file mode 100644
index 202e1cfb48f6..000000000000
--- a/nfc/java/android/nfc/cardemulation/Utils.java
+++ /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.
- */
-
-package android.nfc.cardemulation;
-
-import android.annotation.NonNull;
-import android.content.ComponentName;
-import android.content.ComponentNameProto;
-import android.util.proto.ProtoOutputStream;
-
-/** @hide */
-public final class Utils {
- private Utils() {
- }
-
- /** Copied from {@link ComponentName#dumpDebug(ProtoOutputStream, long)} */
- public static void dumpDebugComponentName(
- @NonNull ComponentName componentName, @NonNull ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- proto.write(ComponentNameProto.PACKAGE_NAME, componentName.getPackageName());
- proto.write(ComponentNameProto.CLASS_NAME, componentName.getClassName());
- proto.end(token);
- }
-}
diff --git a/nfc/java/android/nfc/dta/NfcDta.java b/nfc/java/android/nfc/dta/NfcDta.java
deleted file mode 100644
index 88016623434d..000000000000
--- a/nfc/java/android/nfc/dta/NfcDta.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc.dta;
-
-import android.content.Context;
-import android.nfc.INfcDta;
-import android.nfc.NfcAdapter;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.HashMap;
-
-/**
- * This class provides the primary API for DTA operations.
- * @hide
- */
-public final class NfcDta {
- private static final String TAG = "NfcDta";
-
- private static INfcDta sService;
- private static HashMap<Context, NfcDta> sNfcDtas = new HashMap<Context, NfcDta>();
-
- private final Context mContext;
-
- private NfcDta(Context context, INfcDta service) {
- mContext = context.getApplicationContext();
- sService = service;
- }
-
- /**
- * Helper to get an instance of this class.
- *
- * @param adapter A reference to an NfcAdapter object.
- * @return
- */
- public static synchronized NfcDta getInstance(NfcAdapter adapter) {
- if (adapter == null) throw new NullPointerException("NfcAdapter is null");
- Context context = adapter.getContext();
- if (context == null) {
- Log.e(TAG, "NfcAdapter context is null.");
- throw new UnsupportedOperationException();
- }
-
- NfcDta manager = sNfcDtas.get(context);
- if (manager == null) {
- INfcDta service = adapter.getNfcDtaInterface();
- if (service == null) {
- Log.e(TAG, "This device does not implement the INfcDta interface.");
- throw new UnsupportedOperationException();
- }
- manager = new NfcDta(context, service);
- sNfcDtas.put(context, manager);
- }
- return manager;
- }
-
- /**
- * Enables DTA mode
- *
- * @return true/false if enabling was successful
- */
- public boolean enableDta() {
- try {
- sService.enableDta();
- } catch (RemoteException e) {
- return false;
- }
- return true;
- }
-
- /**
- * Disables DTA mode
- *
- * @return true/false if disabling was successful
- */
- public boolean disableDta() {
- try {
- sService.disableDta();
- } catch (RemoteException e) {
- return false;
- }
- return true;
- }
-
- /**
- * Enables Server
- *
- * @return true/false if enabling was successful
- */
- public boolean enableServer(String serviceName, int serviceSap, int miu,
- int rwSize, int testCaseId) {
- try {
- return sService.enableServer(serviceName, serviceSap, miu, rwSize, testCaseId);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Disables Server
- *
- * @return true/false if disabling was successful
- */
- public boolean disableServer() {
- try {
- sService.disableServer();
- } catch (RemoteException e) {
- return false;
- }
- return true;
- }
-
- /**
- * Enables Client
- *
- * @return true/false if enabling was successful
- */
- public boolean enableClient(String serviceName, int miu, int rwSize,
- int testCaseId) {
- try {
- return sService.enableClient(serviceName, miu, rwSize, testCaseId);
- } catch (RemoteException e) {
- return false;
- }
- }
-
- /**
- * Disables client
- *
- * @return true/false if disabling was successful
- */
- public boolean disableClient() {
- try {
- sService.disableClient();
- } catch (RemoteException e) {
- return false;
- }
- return true;
- }
-
- /**
- * Registers Message Service
- *
- * @return true/false if registration was successful
- */
- public boolean registerMessageService(String msgServiceName) {
- try {
- return sService.registerMessageService(msgServiceName);
- } catch (RemoteException e) {
- return false;
- }
- }
-}
diff --git a/nfc/java/android/nfc/package.html b/nfc/java/android/nfc/package.html
deleted file mode 100644
index 55c1d1650aa9..000000000000
--- a/nfc/java/android/nfc/package.html
+++ /dev/null
@@ -1,33 +0,0 @@
-<HTML>
-<BODY>
-<p>Provides access to Near Field Communication (NFC) functionality, allowing applications to read
-NDEF message in NFC tags. A "tag" may actually be another device that appears as a tag.</p>
-
-<p>For more information, see the
-<a href="{@docRoot}guide/topics/connectivity/nfc/index.html">Near Field Communication</a> guide.</p>
-{@more}
-
-<p>Here's a summary of the classes:</p>
-
-<dl>
- <dt>{@link android.nfc.NfcManager}</dt>
- <dd>This is the high level manager, used to obtain this device's {@link android.nfc.NfcAdapter}. You can
-acquire an instance using {@link android.content.Context#getSystemService}.</dd>
- <dt>{@link android.nfc.NfcAdapter}</dt>
- <dd>This represents the device's NFC adapter, which is your entry-point to performing NFC
-operations. You can acquire an instance with {@link android.nfc.NfcManager#getDefaultAdapter}, or
-{@link android.nfc.NfcAdapter#getDefaultAdapter(android.content.Context)}.</dd>
- <dt>{@link android.nfc.NdefMessage}</dt>
- <dd>Represents an NDEF data message, which is the standard format in which "records"
-carrying data are transmitted between devices and tags. Your application can receive these
-messages from an {@link android.nfc.NfcAdapter#ACTION_TAG_DISCOVERED} intent.</dd>
- <dt>{@link android.nfc.NdefRecord}</dt>
- <dd>Represents a record, which is delivered in a {@link android.nfc.NdefMessage} and describes the
-type of data being shared and carries the data itself.</dd>
-</dl>
-
-<p class="note"><strong>Note:</strong>
-Not all Android-powered devices provide NFC functionality.</p>
-
-</BODY>
-</HTML>
diff --git a/nfc/java/android/nfc/tech/BasicTagTechnology.java b/nfc/java/android/nfc/tech/BasicTagTechnology.java
deleted file mode 100644
index ae468fead7a2..000000000000
--- a/nfc/java/android/nfc/tech/BasicTagTechnology.java
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.Tag;
-import android.nfc.TransceiveResult;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * A base class for tag technologies that are built on top of transceive().
- */
-abstract class BasicTagTechnology implements TagTechnology {
- private static final String TAG = "NFC";
-
- final Tag mTag;
-
- boolean mIsConnected;
- int mSelectedTechnology;
-
- BasicTagTechnology(Tag tag, int tech) throws RemoteException {
- mTag = tag;
- mSelectedTechnology = tech;
- }
-
- @Override
- public Tag getTag() {
- return mTag;
- }
-
- /** Internal helper to throw IllegalStateException if the technology isn't connected */
- void checkConnected() {
- if ((mTag.getConnectedTechnology() != mSelectedTechnology) ||
- (mTag.getConnectedTechnology() == -1)) {
- throw new IllegalStateException("Call connect() first!");
- }
- }
-
- @Override
- public boolean isConnected() {
- if (!mIsConnected) {
- return false;
- }
-
- try {
- return mTag.getTagService().isPresent(mTag.getServiceHandle());
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return false;
- }
- }
-
- @Override
- public void connect() throws IOException {
- try {
- int errorCode = mTag.getTagService().connect(mTag.getServiceHandle(),
- mSelectedTechnology);
-
- if (errorCode == ErrorCodes.SUCCESS) {
- // Store this in the tag object
- if (!mTag.setConnectedTechnology(mSelectedTechnology)) {
- Log.e(TAG, "Close other technology first!");
- throw new IOException("Only one TagTechnology can be connected at a time.");
- }
- mIsConnected = true;
- } else if (errorCode == ErrorCodes.ERROR_NOT_SUPPORTED) {
- throw new UnsupportedOperationException("Connecting to " +
- "this technology is not supported by the NFC " +
- "adapter.");
- } else {
- throw new IOException();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- throw new IOException("NFC service died");
- }
- }
-
- /** @hide */
- @Override
- public void reconnect() throws IOException {
- if (!mIsConnected) {
- throw new IllegalStateException("Technology not connected yet");
- }
-
- try {
- int errorCode = mTag.getTagService().reconnect(mTag.getServiceHandle());
-
- if (errorCode != ErrorCodes.SUCCESS) {
- mIsConnected = false;
- mTag.setTechnologyDisconnected();
- throw new IOException();
- }
- } catch (RemoteException e) {
- mIsConnected = false;
- mTag.setTechnologyDisconnected();
- Log.e(TAG, "NFC service dead", e);
- throw new IOException("NFC service died");
- }
- }
-
- @Override
- public void close() throws IOException {
- try {
- /* Note that we don't want to physically disconnect the tag,
- * but just reconnect to it to reset its state
- */
- mTag.getTagService().resetTimeouts();
- mTag.getTagService().reconnect(mTag.getServiceHandle());
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- } finally {
- mIsConnected = false;
- mTag.setTechnologyDisconnected();
- }
- }
-
- /** Internal getMaxTransceiveLength() */
- int getMaxTransceiveLengthInternal() {
- try {
- return mTag.getTagService().getMaxTransceiveLength(mSelectedTechnology);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return 0;
- }
- }
- /** Internal transceive */
- byte[] transceive(byte[] data, boolean raw) throws IOException {
- checkConnected();
-
- try {
- TransceiveResult result = mTag.getTagService().transceive(mTag.getServiceHandle(),
- data, raw);
- if (result == null) {
- throw new IOException("transceive failed");
- } else {
- return result.getResponseOrThrow();
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- throw new IOException("NFC service died");
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/IsoDep.java b/nfc/java/android/nfc/tech/IsoDep.java
deleted file mode 100644
index 0ba0c5a8d13b..000000000000
--- a/nfc/java/android/nfc/tech/IsoDep.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Provides access to ISO-DEP (ISO 14443-4) properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire an {@link IsoDep} object using {@link #get}.
- * <p>The primary ISO-DEP I/O operation is {@link #transceive}. Applications must
- * implement their own protocol stack on top of {@link #transceive}.
- * <p>Tags that enumerate the {@link IsoDep} technology in {@link Tag#getTechList}
- * will also enumerate
- * {@link NfcA} or {@link NfcB} (since IsoDep builds on top of either of these).
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class IsoDep extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /** @hide */
- public static final String EXTRA_HI_LAYER_RESP = "hiresp";
- /** @hide */
- public static final String EXTRA_HIST_BYTES = "histbytes";
-
- private byte[] mHiLayerResponse = null;
- private byte[] mHistBytes = null;
-
- /**
- * Get an instance of {@link IsoDep} for the given tag.
- * <p>Does not cause any RF activity and does not block.
- * <p>Returns null if {@link IsoDep} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag does not support ISO-DEP.
- *
- * @param tag an ISO-DEP compatible tag
- * @return ISO-DEP object
- */
- public static IsoDep get(Tag tag) {
- if (!tag.hasTech(TagTechnology.ISO_DEP)) return null;
- try {
- return new IsoDep(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public IsoDep(Tag tag)
- throws RemoteException {
- super(tag, TagTechnology.ISO_DEP);
- Bundle extras = tag.getTechExtras(TagTechnology.ISO_DEP);
- if (extras != null) {
- mHiLayerResponse = extras.getByteArray(EXTRA_HI_LAYER_RESP);
- mHistBytes = extras.getByteArray(EXTRA_HIST_BYTES);
- }
- }
-
- /**
- * Set the timeout of {@link #transceive} in milliseconds.
- * <p>The timeout only applies to ISO-DEP {@link #transceive}, and is
- * reset to a default value when {@link #close} is called.
- * <p>Setting a longer timeout may be useful when performing
- * transactions that require a long processing time on the tag
- * such as key generation.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param timeout timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void setTimeout(int timeout) {
- try {
- int err = mTag.getTagService().setTimeout(TagTechnology.ISO_DEP, timeout);
- if (err != ErrorCodes.SUCCESS) {
- throw new IllegalArgumentException("The supplied timeout is not valid");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-
- /**
- * Get the current timeout for {@link #transceive} in milliseconds.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public int getTimeout() {
- try {
- return mTag.getTagService().getTimeout(TagTechnology.ISO_DEP);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return 0;
- }
- }
-
- /**
- * Return the ISO-DEP historical bytes for {@link NfcA} tags.
- * <p>Does not cause any RF activity and does not block.
- * <p>The historical bytes can be used to help identify a tag. They are present
- * only on {@link IsoDep} tags that are based on {@link NfcA} RF technology.
- * If this tag is not {@link NfcA} then null is returned.
- * <p>In ISO 14443-4 terminology, the historical bytes are a subset of the RATS
- * response.
- *
- * @return ISO-DEP historical bytes, or null if this is not a {@link NfcA} tag
- */
- public byte[] getHistoricalBytes() {
- return mHistBytes;
- }
-
- /**
- * Return the higher layer response bytes for {@link NfcB} tags.
- * <p>Does not cause any RF activity and does not block.
- * <p>The higher layer response bytes can be used to help identify a tag.
- * They are present only on {@link IsoDep} tags that are based on {@link NfcB}
- * RF technology. If this tag is not {@link NfcB} then null is returned.
- * <p>In ISO 14443-4 terminology, the higher layer bytes are a subset of the
- * ATTRIB response.
- *
- * @return ISO-DEP historical bytes, or null if this is not a {@link NfcB} tag
- */
- public byte[] getHiLayerResponse() {
- return mHiLayerResponse;
- }
-
- /**
- * Send raw ISO-DEP data to the tag and receive the response.
- *
- * <p>Applications must only send the INF payload, and not the start of frame and
- * end of frame indicators. Applications do not need to fragment the payload, it
- * will be automatically fragmented and defragmented by {@link #transceive} if
- * it exceeds FSD/FSC limits.
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param data command bytes to send, must not be null
- * @return response bytes received, will not be null
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or this operation is canceled
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-
- /**
- * <p>Standard APDUs have a 1-byte length field, allowing a maximum of
- * 255 payload bytes, which results in a maximum APDU length of 261 bytes.
- *
- * <p>Extended length APDUs have a 3-byte length field, allowing 65535
- * payload bytes.
- *
- * <p>Some NFC adapters, like the one used in the Nexus S and the Galaxy Nexus
- * do not support extended length APDUs. They are expected to be well-supported
- * in the future though. Use this method to check for extended length APDU
- * support.
- *
- * @return whether the NFC adapter on this device supports extended length APDUs.
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public boolean isExtendedLengthApduSupported() {
- try {
- return mTag.getTagService().getExtendedLengthApdusSupported();
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return false;
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/MifareClassic.java b/nfc/java/android/nfc/tech/MifareClassic.java
deleted file mode 100644
index 26f54e692289..000000000000
--- a/nfc/java/android/nfc/tech/MifareClassic.java
+++ /dev/null
@@ -1,655 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.Tag;
-import android.nfc.TagLostException;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-/**
- * Provides access to MIFARE Classic properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire a {@link MifareClassic} object using {@link #get}.
- *
- * <p>MIFARE Classic is also known as MIFARE Standard.
- * <p>MIFARE Classic tags are divided into sectors, and each sector is sub-divided into
- * blocks. Block size is always 16 bytes ({@link #BLOCK_SIZE}. Sector size varies.
- * <ul>
- * <li>MIFARE Classic Mini are 320 bytes ({@link #SIZE_MINI}), with 5 sectors each of 4 blocks.
- * <li>MIFARE Classic 1k are 1024 bytes ({@link #SIZE_1K}), with 16 sectors each of 4 blocks.
- * <li>MIFARE Classic 2k are 2048 bytes ({@link #SIZE_2K}), with 32 sectors each of 4 blocks.
- * <li>MIFARE Classic 4k are 4096 bytes ({@link #SIZE_4K}). The first 32 sectors contain 4 blocks
- * and the last 8 sectors contain 16 blocks.
- * </ul>
- *
- * <p>MIFARE Classic tags require authentication on a per-sector basis before any
- * other I/O operations on that sector can be performed. There are two keys per sector,
- * and ACL bits determine what I/O operations are allowed on that sector after
- * authenticating with a key. {@see #authenticateSectorWithKeyA} and
- * {@see #authenticateSectorWithKeyB}.
- *
- * <p>Three well-known authentication keys are defined in this class:
- * {@link #KEY_DEFAULT}, {@link #KEY_MIFARE_APPLICATION_DIRECTORY},
- * {@link #KEY_NFC_FORUM}.
- * <ul>
- * <li>{@link #KEY_DEFAULT} is the default factory key for MIFARE Classic.
- * <li>{@link #KEY_MIFARE_APPLICATION_DIRECTORY} is the well-known key for
- * MIFARE Classic cards that have been formatted according to the
- * MIFARE Application Directory (MAD) specification.
- * <li>{@link #KEY_NFC_FORUM} is the well-known key for MIFARE Classic cards that
- * have been formatted according to the NXP specification for NDEF on MIFARE Classic.
- *
- * <p>Implementation of this class on a Android NFC device is optional.
- * If it is not implemented, then
- * {@link MifareClassic} will never be enumerated in {@link Tag#getTechList}.
- * If it is enumerated, then all {@link MifareClassic} I/O operations will be supported,
- * and {@link Ndef#MIFARE_CLASSIC} NDEF tags will also be supported. In either case,
- * {@link NfcA} will also be enumerated on the tag, because all MIFARE Classic tags are also
- * {@link NfcA}.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class MifareClassic extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /**
- * The default factory key.
- */
- public static final byte[] KEY_DEFAULT =
- {(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF,(byte)0xFF};
- /**
- * The well-known key for tags formatted according to the
- * MIFARE Application Directory (MAD) specification.
- */
- public static final byte[] KEY_MIFARE_APPLICATION_DIRECTORY =
- {(byte)0xA0,(byte)0xA1,(byte)0xA2,(byte)0xA3,(byte)0xA4,(byte)0xA5};
- /**
- * The well-known key for tags formatted according to the
- * NDEF on MIFARE Classic specification.
- */
- public static final byte[] KEY_NFC_FORUM =
- {(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7,(byte)0xD3,(byte)0xF7};
-
- /** A MIFARE Classic compatible card of unknown type */
- public static final int TYPE_UNKNOWN = -1;
- /** A MIFARE Classic tag */
- public static final int TYPE_CLASSIC = 0;
- /** A MIFARE Plus tag */
- public static final int TYPE_PLUS = 1;
- /** A MIFARE Pro tag */
- public static final int TYPE_PRO = 2;
-
- /** Tag contains 16 sectors, each with 4 blocks. */
- public static final int SIZE_1K = 1024;
- /** Tag contains 32 sectors, each with 4 blocks. */
- public static final int SIZE_2K = 2048;
- /**
- * Tag contains 40 sectors. The first 32 sectors contain 4 blocks and the last 8 sectors
- * contain 16 blocks.
- */
- public static final int SIZE_4K = 4096;
- /** Tag contains 5 sectors, each with 4 blocks. */
- public static final int SIZE_MINI = 320;
-
- /** Size of a MIFARE Classic block (in bytes) */
- public static final int BLOCK_SIZE = 16;
-
- private static final int MAX_BLOCK_COUNT = 256;
- private static final int MAX_SECTOR_COUNT = 40;
-
- private boolean mIsEmulated;
- private int mType;
- private int mSize;
-
- /**
- * Get an instance of {@link MifareClassic} for the given tag.
- * <p>Does not cause any RF activity and does not block.
- * <p>Returns null if {@link MifareClassic} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag is not MIFARE Classic compatible, or this Android
- * device does not support MIFARE Classic.
- *
- * @param tag an MIFARE Classic compatible tag
- * @return MIFARE Classic object
- */
- public static MifareClassic get(Tag tag) {
- if (!tag.hasTech(TagTechnology.MIFARE_CLASSIC)) return null;
- try {
- return new MifareClassic(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public MifareClassic(Tag tag) throws RemoteException {
- super(tag, TagTechnology.MIFARE_CLASSIC);
-
- NfcA a = NfcA.get(tag); // MIFARE Classic is always based on NFC a
-
- mIsEmulated = false;
-
- switch (a.getSak()) {
- case 0x01:
- case 0x08:
- mType = TYPE_CLASSIC;
- mSize = SIZE_1K;
- break;
- case 0x09:
- mType = TYPE_CLASSIC;
- mSize = SIZE_MINI;
- break;
- case 0x10:
- mType = TYPE_PLUS;
- mSize = SIZE_2K;
- // SecLevel = SL2
- break;
- case 0x11:
- mType = TYPE_PLUS;
- mSize = SIZE_4K;
- // Seclevel = SL2
- break;
- case 0x18:
- mType = TYPE_CLASSIC;
- mSize = SIZE_4K;
- break;
- case 0x28:
- mType = TYPE_CLASSIC;
- mSize = SIZE_1K;
- mIsEmulated = true;
- break;
- case 0x38:
- mType = TYPE_CLASSIC;
- mSize = SIZE_4K;
- mIsEmulated = true;
- break;
- case 0x88:
- mType = TYPE_CLASSIC;
- mSize = SIZE_1K;
- // NXP-tag: false
- break;
- case 0x98:
- case 0xB8:
- mType = TYPE_PRO;
- mSize = SIZE_4K;
- break;
- default:
- // Stack incorrectly reported a MifareClassic. We cannot handle this
- // gracefully - we have no idea of the memory layout. Bail.
- throw new RuntimeException(
- "Tag incorrectly enumerated as MIFARE Classic, SAK = " + a.getSak());
- }
- }
-
- /**
- * Return the type of this MIFARE Classic compatible tag.
- * <p>One of {@link #TYPE_UNKNOWN}, {@link #TYPE_CLASSIC}, {@link #TYPE_PLUS} or
- * {@link #TYPE_PRO}.
- * <p>Does not cause any RF activity and does not block.
- *
- * @return type
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Return the size of the tag in bytes
- * <p>One of {@link #SIZE_MINI}, {@link #SIZE_1K}, {@link #SIZE_2K}, {@link #SIZE_4K}.
- * These constants are equal to their respective size in bytes.
- * <p>Does not cause any RF activity and does not block.
- * @return size in bytes
- */
- public int getSize() {
- return mSize;
- }
-
- /**
- * Return true if the tag is emulated, determined at discovery time.
- * These are actually smart-cards that emulate a MIFARE Classic interface.
- * They can be treated identically to a MIFARE Classic tag.
- * @hide
- */
- public boolean isEmulated() {
- return mIsEmulated;
- }
-
- /**
- * Return the number of MIFARE Classic sectors.
- * <p>Does not cause any RF activity and does not block.
- * @return number of sectors
- */
- public int getSectorCount() {
- switch (mSize) {
- case SIZE_1K:
- return 16;
- case SIZE_2K:
- return 32;
- case SIZE_4K:
- return 40;
- case SIZE_MINI:
- return 5;
- default:
- return 0;
- }
- }
-
- /**
- * Return the total number of MIFARE Classic blocks.
- * <p>Does not cause any RF activity and does not block.
- * @return total number of blocks
- */
- public int getBlockCount() {
- return mSize / BLOCK_SIZE;
- }
-
- /**
- * Return the number of blocks in the given sector.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param sectorIndex index of sector, starting from 0
- * @return number of blocks in the sector
- */
- public int getBlockCountInSector(int sectorIndex) {
- validateSector(sectorIndex);
-
- if (sectorIndex < 32) {
- return 4;
- } else {
- return 16;
- }
- }
-
- /**
- * Return the sector that contains a given block.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param blockIndex index of block to lookup, starting from 0
- * @return sector index that contains the block
- */
- public int blockToSector(int blockIndex) {
- validateBlock(blockIndex);
-
- if (blockIndex < 32 * 4) {
- return blockIndex / 4;
- } else {
- return 32 + (blockIndex - 32 * 4) / 16;
- }
- }
-
- /**
- * Return the first block of a given sector.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param sectorIndex index of sector to lookup, starting from 0
- * @return block index of first block in sector
- */
- public int sectorToBlock(int sectorIndex) {
- if (sectorIndex < 32) {
- return sectorIndex * 4;
- } else {
- return 32 * 4 + (sectorIndex - 32) * 16;
- }
- }
-
- /**
- * Authenticate a sector with key A.
- *
- * <p>Successful authentication of a sector with key A enables other
- * I/O operations on that sector. The set of operations granted by key A
- * key depends on the ACL bits set in that sector. For more information
- * see the MIFARE Classic specification on <a href="http://www.nxp.com">http://www.nxp.com</a>.
- *
- * <p>A failed authentication attempt causes an implicit reconnection to the
- * tag, so authentication to other sectors will be lost.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param sectorIndex index of sector to authenticate, starting from 0
- * @param key 6-byte authentication key
- * @return true on success, false on authentication failure
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public boolean authenticateSectorWithKeyA(int sectorIndex, byte[] key) throws IOException {
- return authenticate(sectorIndex, key, true);
- }
-
- /**
- * Authenticate a sector with key B.
- *
- * <p>Successful authentication of a sector with key B enables other
- * I/O operations on that sector. The set of operations granted by key B
- * depends on the ACL bits set in that sector. For more information
- * see the MIFARE Classic specification on <a href="http://www.nxp.com">http://www.nxp.com</a>.
- *
- * <p>A failed authentication attempt causes an implicit reconnection to the
- * tag, so authentication to other sectors will be lost.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param sectorIndex index of sector to authenticate, starting from 0
- * @param key 6-byte authentication key
- * @return true on success, false on authentication failure
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public boolean authenticateSectorWithKeyB(int sectorIndex, byte[] key) throws IOException {
- return authenticate(sectorIndex, key, false);
- }
-
- private boolean authenticate(int sector, byte[] key, boolean keyA) throws IOException {
- validateSector(sector);
- checkConnected();
-
- byte[] cmd = new byte[12];
-
- // First byte is the command
- if (keyA) {
- cmd[0] = 0x60; // phHal_eMifareAuthentA
- } else {
- cmd[0] = 0x61; // phHal_eMifareAuthentB
- }
-
- // Second byte is block address
- // Authenticate command takes a block address. Authenticating a block
- // of a sector will authenticate the entire sector.
- cmd[1] = (byte) sectorToBlock(sector);
-
- // Next 4 bytes are last 4 bytes of UID
- byte[] uid = getTag().getId();
- System.arraycopy(uid, uid.length - 4, cmd, 2, 4);
-
- // Next 6 bytes are key
- System.arraycopy(key, 0, cmd, 6, 6);
-
- try {
- if (transceive(cmd, false) != null) {
- return true;
- }
- } catch (TagLostException e) {
- throw e;
- } catch (IOException e) {
- // No need to deal with, will return false anyway
- }
- return false;
- }
-
- /**
- * Read 16-byte block.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param blockIndex index of block to read, starting from 0
- * @return 16 byte block
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public byte[] readBlock(int blockIndex) throws IOException {
- validateBlock(blockIndex);
- checkConnected();
-
- byte[] cmd = { 0x30, (byte) blockIndex };
- return transceive(cmd, false);
- }
-
- /**
- * Write 16-byte block.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param blockIndex index of block to write, starting from 0
- * @param data 16 bytes of data to write
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public void writeBlock(int blockIndex, byte[] data) throws IOException {
- validateBlock(blockIndex);
- checkConnected();
- if (data.length != 16) {
- throw new IllegalArgumentException("must write 16-bytes");
- }
-
- byte[] cmd = new byte[data.length + 2];
- cmd[0] = (byte) 0xA0; // MF write command
- cmd[1] = (byte) blockIndex;
- System.arraycopy(data, 0, cmd, 2, data.length);
-
- transceive(cmd, false);
- }
-
- /**
- * Increment a value block, storing the result in the temporary block on the tag.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param blockIndex index of block to increment, starting from 0
- * @param value non-negative to increment by
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public void increment(int blockIndex, int value) throws IOException {
- validateBlock(blockIndex);
- validateValueOperand(value);
- checkConnected();
-
- ByteBuffer cmd = ByteBuffer.allocate(6);
- cmd.order(ByteOrder.LITTLE_ENDIAN);
- cmd.put( (byte) 0xC1 );
- cmd.put( (byte) blockIndex );
- cmd.putInt(value);
-
- transceive(cmd.array(), false);
- }
-
- /**
- * Decrement a value block, storing the result in the temporary block on the tag.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param blockIndex index of block to decrement, starting from 0
- * @param value non-negative to decrement by
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public void decrement(int blockIndex, int value) throws IOException {
- validateBlock(blockIndex);
- validateValueOperand(value);
- checkConnected();
-
- ByteBuffer cmd = ByteBuffer.allocate(6);
- cmd.order(ByteOrder.LITTLE_ENDIAN);
- cmd.put( (byte) 0xC0 );
- cmd.put( (byte) blockIndex );
- cmd.putInt(value);
-
- transceive(cmd.array(), false);
- }
-
- /**
- * Copy from the temporary block to a value block.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param blockIndex index of block to copy to
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public void transfer(int blockIndex) throws IOException {
- validateBlock(blockIndex);
- checkConnected();
-
- byte[] cmd = { (byte) 0xB0, (byte) blockIndex };
-
- transceive(cmd, false);
- }
-
- /**
- * Copy from a value block to the temporary block.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param blockIndex index of block to copy from
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public void restore(int blockIndex) throws IOException {
- validateBlock(blockIndex);
- checkConnected();
-
- byte[] cmd = { (byte) 0xC2, (byte) blockIndex };
-
- transceive(cmd, false);
- }
-
- /**
- * Send raw NfcA data to a tag and receive the response.
- *
- * <p>This is equivalent to connecting to this tag via {@link NfcA}
- * and calling {@link NfcA#transceive}. Note that all MIFARE Classic
- * tags are based on {@link NfcA} technology.
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @see NfcA#transceive
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-
- /**
- * Set the {@link #transceive} timeout in milliseconds.
- *
- * <p>The timeout only applies to {@link #transceive} on this object,
- * and is reset to a default value when {@link #close} is called.
- *
- * <p>Setting a longer timeout may be useful when performing
- * transactions that require a long processing time on the tag
- * such as key generation.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param timeout timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void setTimeout(int timeout) {
- try {
- int err = mTag.getTagService().setTimeout(TagTechnology.MIFARE_CLASSIC, timeout);
- if (err != ErrorCodes.SUCCESS) {
- throw new IllegalArgumentException("The supplied timeout is not valid");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-
- /**
- * Get the current {@link #transceive} timeout in milliseconds.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public int getTimeout() {
- try {
- return mTag.getTagService().getTimeout(TagTechnology.MIFARE_CLASSIC);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return 0;
- }
- }
-
- private static void validateSector(int sector) {
- // Do not be too strict on upper bounds checking, since some cards
- // have more addressable memory than they report. For example,
- // MIFARE Plus 2k cards will appear as MIFARE Classic 1k cards when in
- // MIFARE Classic compatibility mode.
- // Note that issuing a command to an out-of-bounds block is safe - the
- // tag should report error causing IOException. This validation is a
- // helper to guard against obvious programming mistakes.
- if (sector < 0 || sector >= MAX_SECTOR_COUNT) {
- throw new IndexOutOfBoundsException("sector out of bounds: " + sector);
- }
- }
-
- private static void validateBlock(int block) {
- // Just looking for obvious out of bounds...
- if (block < 0 || block >= MAX_BLOCK_COUNT) {
- throw new IndexOutOfBoundsException("block out of bounds: " + block);
- }
- }
-
- private static void validateValueOperand(int value) {
- if (value < 0) {
- throw new IllegalArgumentException("value operand negative");
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/MifareUltralight.java b/nfc/java/android/nfc/tech/MifareUltralight.java
deleted file mode 100644
index c0416a39ba76..000000000000
--- a/nfc/java/android/nfc/tech/MifareUltralight.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.Tag;
-import android.nfc.TagLostException;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-//TOOD: Ultralight C 3-DES authentication, one-way counter
-
-/**
- * Provides access to MIFARE Ultralight properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire a {@link MifareUltralight} object using {@link #get}.
- *
- * <p>MIFARE Ultralight compatible tags have 4 byte pages {@link #PAGE_SIZE}.
- * The primary operations on an Ultralight tag are {@link #readPages} and
- * {@link #writePage}.
- *
- * <p>The original MIFARE Ultralight consists of a 64 byte EEPROM. The first
- * 4 pages are for the OTP area, manufacturer data, and locking bits. They are
- * readable and some bits are writable. The final 12 pages are the user
- * read/write area. For more information see the NXP data sheet MF0ICU1.
- *
- * <p>The MIFARE Ultralight C consists of a 192 byte EEPROM. The first 4 pages
- * are for OTP, manufacturer data, and locking bits. The next 36 pages are the
- * user read/write area. The next 4 pages are additional locking bits, counters
- * and authentication configuration and are readable. The final 4 pages are for
- * the authentication key and are not readable. For more information see the
- * NXP data sheet MF0ICU2.
- *
- * <p>Implementation of this class on a Android NFC device is optional.
- * If it is not implemented, then
- * {@link MifareUltralight} will never be enumerated in {@link Tag#getTechList}.
- * If it is enumerated, then all {@link MifareUltralight} I/O operations will be supported.
- * In either case, {@link NfcA} will also be enumerated on the tag,
- * because all MIFARE Ultralight tags are also {@link NfcA} tags.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class MifareUltralight extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /** A MIFARE Ultralight compatible tag of unknown type */
- public static final int TYPE_UNKNOWN = -1;
- /** A MIFARE Ultralight tag */
- public static final int TYPE_ULTRALIGHT = 1;
- /** A MIFARE Ultralight C tag */
- public static final int TYPE_ULTRALIGHT_C = 2;
-
- /** Size of a MIFARE Ultralight page in bytes */
- public static final int PAGE_SIZE = 4;
-
- private static final int NXP_MANUFACTURER_ID = 0x04;
- private static final int MAX_PAGE_COUNT = 256;
-
- /** @hide */
- public static final String EXTRA_IS_UL_C = "isulc";
-
- private int mType;
-
- /**
- * Get an instance of {@link MifareUltralight} for the given tag.
- * <p>Returns null if {@link MifareUltralight} was not enumerated in
- * {@link Tag#getTechList} - this indicates the tag is not MIFARE
- * Ultralight compatible, or that this Android
- * device does not implement MIFARE Ultralight.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an MIFARE Ultralight compatible tag
- * @return MIFARE Ultralight object
- */
- public static MifareUltralight get(Tag tag) {
- if (!tag.hasTech(TagTechnology.MIFARE_ULTRALIGHT)) return null;
- try {
- return new MifareUltralight(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public MifareUltralight(Tag tag) throws RemoteException {
- super(tag, TagTechnology.MIFARE_ULTRALIGHT);
-
- // Check if this could actually be a MIFARE
- NfcA a = NfcA.get(tag);
-
- mType = TYPE_UNKNOWN;
-
- if (a.getSak() == 0x00 && tag.getId()[0] == NXP_MANUFACTURER_ID) {
- Bundle extras = tag.getTechExtras(TagTechnology.MIFARE_ULTRALIGHT);
- if (extras.getBoolean(EXTRA_IS_UL_C)) {
- mType = TYPE_ULTRALIGHT_C;
- } else {
- mType = TYPE_ULTRALIGHT;
- }
- }
- }
-
- /**
- * Return the MIFARE Ultralight type of the tag.
- * <p>One of {@link #TYPE_ULTRALIGHT} or {@link #TYPE_ULTRALIGHT_C} or
- * {@link #TYPE_UNKNOWN}.
- * <p>Depending on how the tag has been formatted, it can be impossible
- * to accurately classify between original MIFARE Ultralight and
- * Ultralight C. So treat this method as a hint.
- * <p>Does not cause any RF activity and does not block.
- *
- * @return the type
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Read 4 pages (16 bytes).
- *
- * <p>The MIFARE Ultralight protocol always reads 4 pages at a time, to
- * reduce the number of commands required to read an entire tag.
- * <p>If a read spans past the last readable block, then the tag will
- * return pages that have been wrapped back to the first blocks. MIFARE
- * Ultralight tags have readable blocks 0x00 through 0x0F. So a read to
- * block offset 0x0E would return blocks 0x0E, 0x0F, 0x00, 0x01. MIFARE
- * Ultralight C tags have readable blocks 0x00 through 0x2B. So a read to
- * block 0x2A would return blocks 0x2A, 0x2B, 0x00, 0x01.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param pageOffset index of first page to read, starting from 0
- * @return 4 pages (16 bytes)
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public byte[] readPages(int pageOffset) throws IOException {
- validatePageIndex(pageOffset);
- checkConnected();
-
- byte[] cmd = { 0x30, (byte) pageOffset};
- return transceive(cmd, false);
- }
-
- /**
- * Write 1 page (4 bytes).
- *
- * <p>The MIFARE Ultralight protocol always writes 1 page at a time, to
- * minimize EEPROM write cycles.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param pageOffset index of page to write, starting from 0
- * @param data 4 bytes to write
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- */
- public void writePage(int pageOffset, byte[] data) throws IOException {
- validatePageIndex(pageOffset);
- checkConnected();
-
- byte[] cmd = new byte[data.length + 2];
- cmd[0] = (byte) 0xA2;
- cmd[1] = (byte) pageOffset;
- System.arraycopy(data, 0, cmd, 2, data.length);
-
- transceive(cmd, false);
- }
-
- /**
- * Send raw NfcA data to a tag and receive the response.
- *
- * <p>This is equivalent to connecting to this tag via {@link NfcA}
- * and calling {@link NfcA#transceive}. Note that all MIFARE Classic
- * tags are based on {@link NfcA} technology.
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @see NfcA#transceive
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-
- /**
- * Set the {@link #transceive} timeout in milliseconds.
- *
- * <p>The timeout only applies to {@link #transceive} on this object,
- * and is reset to a default value when {@link #close} is called.
- *
- * <p>Setting a longer timeout may be useful when performing
- * transactions that require a long processing time on the tag
- * such as key generation.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param timeout timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void setTimeout(int timeout) {
- try {
- int err = mTag.getTagService().setTimeout(
- TagTechnology.MIFARE_ULTRALIGHT, timeout);
- if (err != ErrorCodes.SUCCESS) {
- throw new IllegalArgumentException("The supplied timeout is not valid");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-
- /**
- * Get the current {@link #transceive} timeout in milliseconds.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public int getTimeout() {
- try {
- return mTag.getTagService().getTimeout(TagTechnology.MIFARE_ULTRALIGHT);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return 0;
- }
- }
-
- private static void validatePageIndex(int pageIndex) {
- // Do not be too strict on upper bounds checking, since some cards
- // may have more addressable memory than they report.
- // Note that issuing a command to an out-of-bounds block is safe - the
- // tag will wrap the read to an addressable area. This validation is a
- // helper to guard against obvious programming mistakes.
- if (pageIndex < 0 || pageIndex >= MAX_PAGE_COUNT) {
- throw new IndexOutOfBoundsException("page out of bounds: " + pageIndex);
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/Ndef.java b/nfc/java/android/nfc/tech/Ndef.java
deleted file mode 100644
index 7d83f157a314..000000000000
--- a/nfc/java/android/nfc/tech/Ndef.java
+++ /dev/null
@@ -1,408 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.FormatException;
-import android.nfc.INfcTag;
-import android.nfc.NdefMessage;
-import android.nfc.Tag;
-import android.nfc.TagLostException;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Provides access to NDEF content and operations on a {@link Tag}.
- *
- * <p>Acquire a {@link Ndef} object using {@link #get}.
- *
- * <p>NDEF is an NFC Forum data format. The data formats are implemented in
- * {@link android.nfc.NdefMessage} and
- * {@link android.nfc.NdefRecord}. This class provides methods to
- * retrieve and modify the {@link android.nfc.NdefMessage}
- * on a tag.
- *
- * <p>There are currently four NFC Forum standardized tag types that can be
- * formatted to contain NDEF data.
- * <ul>
- * <li>NFC Forum Type 1 Tag ({@link #NFC_FORUM_TYPE_1}), such as the Innovision Topaz
- * <li>NFC Forum Type 2 Tag ({@link #NFC_FORUM_TYPE_2}), such as the NXP MIFARE Ultralight
- * <li>NFC Forum Type 3 Tag ({@link #NFC_FORUM_TYPE_3}), such as Sony Felica
- * <li>NFC Forum Type 4 Tag ({@link #NFC_FORUM_TYPE_4}), such as NXP MIFARE Desfire
- * </ul>
- * It is mandatory for all Android devices with NFC to correctly enumerate
- * {@link Ndef} on NFC Forum Tag Types 1-4, and implement all NDEF operations
- * as defined in this class.
- *
- * <p>Some vendors have their own well defined specifications for storing NDEF data
- * on tags that do not fall into the above categories. Android devices with NFC
- * should enumerate and implement {@link Ndef} under these vendor specifications
- * where possible, but it is not mandatory. {@link #getType} returns a String
- * describing this specification, for example {@link #MIFARE_CLASSIC} is
- * <code>com.nxp.ndef.mifareclassic</code>.
- *
- * <p>Android devices that support MIFARE Classic must also correctly
- * implement {@link Ndef} on MIFARE Classic tags formatted to NDEF.
- *
- * <p>For guaranteed compatibility across all Android devices with NFC, it is
- * recommended to use NFC Forum Types 1-4 in new deployments of NFC tags
- * with NDEF payload. Vendor NDEF formats will not work on all Android devices.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class Ndef extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /** @hide */
- public static final int NDEF_MODE_READ_ONLY = 1;
- /** @hide */
- public static final int NDEF_MODE_READ_WRITE = 2;
- /** @hide */
- public static final int NDEF_MODE_UNKNOWN = 3;
-
- /** @hide */
- public static final String EXTRA_NDEF_MSG = "ndefmsg";
-
- /** @hide */
- public static final String EXTRA_NDEF_MAXLENGTH = "ndefmaxlength";
-
- /** @hide */
- public static final String EXTRA_NDEF_CARDSTATE = "ndefcardstate";
-
- /** @hide */
- public static final String EXTRA_NDEF_TYPE = "ndeftype";
-
- /** @hide */
- public static final int TYPE_OTHER = -1;
- /** @hide */
- public static final int TYPE_1 = 1;
- /** @hide */
- public static final int TYPE_2 = 2;
- /** @hide */
- public static final int TYPE_3 = 3;
- /** @hide */
- public static final int TYPE_4 = 4;
- /** @hide */
- public static final int TYPE_MIFARE_CLASSIC = 101;
- /** @hide */
- public static final int TYPE_ICODE_SLI = 102;
-
- /** @hide */
- public static final String UNKNOWN = "android.ndef.unknown";
-
- /** NFC Forum Tag Type 1 */
- public static final String NFC_FORUM_TYPE_1 = "org.nfcforum.ndef.type1";
- /** NFC Forum Tag Type 2 */
- public static final String NFC_FORUM_TYPE_2 = "org.nfcforum.ndef.type2";
- /** NFC Forum Tag Type 3 */
- public static final String NFC_FORUM_TYPE_3 = "org.nfcforum.ndef.type3";
- /** NFC Forum Tag Type 4 */
- public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
- /** NDEF on MIFARE Classic */
- public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
- /**
- * NDEF on iCODE SLI
- * @hide
- */
- public static final String ICODE_SLI = "com.nxp.ndef.icodesli";
-
- private final int mMaxNdefSize;
- private final int mCardState;
- private final NdefMessage mNdefMsg;
- private final int mNdefType;
-
- /**
- * Get an instance of {@link Ndef} for the given tag.
- *
- * <p>Returns null if {@link Ndef} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag is not NDEF formatted, or that this tag
- * is NDEF formatted but under a vendor specification that this Android
- * device does not implement.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an NDEF compatible tag
- * @return Ndef object
- */
- public static Ndef get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NDEF)) return null;
- try {
- return new Ndef(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
- * Internal constructor, to be used by NfcAdapter
- * @hide
- */
- public Ndef(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NDEF);
- Bundle extras = tag.getTechExtras(TagTechnology.NDEF);
- if (extras != null) {
- mMaxNdefSize = extras.getInt(EXTRA_NDEF_MAXLENGTH);
- mCardState = extras.getInt(EXTRA_NDEF_CARDSTATE);
- mNdefMsg = extras.getParcelable(EXTRA_NDEF_MSG, android.nfc.NdefMessage.class);
- mNdefType = extras.getInt(EXTRA_NDEF_TYPE);
- } else {
- throw new NullPointerException("NDEF tech extras are null.");
- }
-
- }
-
- /**
- * Get the {@link NdefMessage} that was read from the tag at discovery time.
- *
- * <p>If the NDEF Message is modified by an I/O operation then it
- * will not be updated here, this function only returns what was discovered
- * when the tag entered the field.
- * <p>Note that this method may return null if the tag was in the
- * INITIALIZED state as defined by NFC Forum, as in this state the
- * tag is formatted to support NDEF but does not contain a message yet.
- * <p>Does not cause any RF activity and does not block.
- * @return NDEF Message read from the tag at discovery time, can be null
- */
- public NdefMessage getCachedNdefMessage() {
- return mNdefMsg;
- }
-
- /**
- * Get the NDEF tag type.
- *
- * <p>Returns one of {@link #NFC_FORUM_TYPE_1}, {@link #NFC_FORUM_TYPE_2},
- * {@link #NFC_FORUM_TYPE_3}, {@link #NFC_FORUM_TYPE_4},
- * {@link #MIFARE_CLASSIC} or another NDEF tag type that has not yet been
- * formalized in this Android API.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return a string representing the NDEF tag type
- */
- public String getType() {
- switch (mNdefType) {
- case TYPE_1:
- return NFC_FORUM_TYPE_1;
- case TYPE_2:
- return NFC_FORUM_TYPE_2;
- case TYPE_3:
- return NFC_FORUM_TYPE_3;
- case TYPE_4:
- return NFC_FORUM_TYPE_4;
- case TYPE_MIFARE_CLASSIC:
- return MIFARE_CLASSIC;
- case TYPE_ICODE_SLI:
- return ICODE_SLI;
- default:
- return UNKNOWN;
- }
- }
-
- /**
- * Get the maximum NDEF message size in bytes.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return size in bytes
- */
- public int getMaxSize() {
- return mMaxNdefSize;
- }
-
- /**
- * Determine if the tag is writable.
- *
- * <p>NFC Forum tags can be in read-only or read-write states.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * <p>Requires {@link android.Manifest.permission#NFC} permission.
- *
- * @return true if the tag is writable
- */
- public boolean isWritable() {
- return (mCardState == NDEF_MODE_READ_WRITE);
- }
-
- /**
- * Read the current {@link android.nfc.NdefMessage} on this tag.
- *
- * <p>This always reads the current NDEF Message stored on the tag.
- *
- * <p>Note that this method may return null if the tag was in the
- * INITIALIZED state as defined by NFC Forum, as in that state the
- * tag is formatted to support NDEF but does not contain a message yet.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return the NDEF Message, can be null
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- * @throws FormatException if the NDEF Message on the tag is malformed
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public NdefMessage getNdefMessage() throws IOException, FormatException {
- checkConnected();
-
- try {
- INfcTag tagService = mTag.getTagService();
- if (tagService == null) {
- throw new IOException("Mock tags don't support this operation.");
- }
- int serviceHandle = mTag.getServiceHandle();
- if (tagService.isNdef(serviceHandle)) {
- NdefMessage msg = tagService.ndefRead(serviceHandle);
- if (msg == null && !tagService.isPresent(serviceHandle)) {
- throw new TagLostException();
- }
- return msg;
- } else if (!tagService.isPresent(serviceHandle)) {
- throw new TagLostException();
- } else {
- return null;
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return null;
- }
- }
-
- /**
- * Overwrite the {@link NdefMessage} on this tag.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param msg the NDEF Message to write, must not be null
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- * @throws FormatException if the NDEF Message to write is malformed
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void writeNdefMessage(NdefMessage msg) throws IOException, FormatException {
- checkConnected();
-
- try {
- INfcTag tagService = mTag.getTagService();
- if (tagService == null) {
- throw new IOException("Mock tags don't support this operation.");
- }
- int serviceHandle = mTag.getServiceHandle();
- if (tagService.isNdef(serviceHandle)) {
- int errorCode = tagService.ndefWrite(serviceHandle, msg);
- switch (errorCode) {
- case ErrorCodes.SUCCESS:
- break;
- case ErrorCodes.ERROR_IO:
- throw new IOException();
- case ErrorCodes.ERROR_INVALID_PARAM:
- throw new FormatException();
- default:
- // Should not happen
- throw new IOException();
- }
- }
- else {
- throw new IOException("Tag is not ndef");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-
- /**
- * Indicates whether a tag can be made read-only with {@link #makeReadOnly()}.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return true if it is possible to make this tag read-only
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public boolean canMakeReadOnly() {
- INfcTag tagService = mTag.getTagService();
- if (tagService == null) {
- return false;
- }
- try {
- return tagService.canMakeReadOnly(mNdefType);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return false;
- }
- }
-
- /**
- * Make a tag read-only.
- *
- * <p>This sets the CC field to indicate the tag is read-only,
- * and where possible permanently sets the lock bits to prevent
- * any further modification of the memory.
- * <p>This is a one-way process and cannot be reverted!
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return true on success, false if it is not possible to make this tag read-only
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public boolean makeReadOnly() throws IOException {
- checkConnected();
-
- try {
- INfcTag tagService = mTag.getTagService();
- if (tagService == null) {
- return false;
- }
- if (tagService.isNdef(mTag.getServiceHandle())) {
- int errorCode = tagService.ndefMakeReadOnly(mTag.getServiceHandle());
- switch (errorCode) {
- case ErrorCodes.SUCCESS:
- return true;
- case ErrorCodes.ERROR_IO:
- throw new IOException();
- case ErrorCodes.ERROR_INVALID_PARAM:
- return false;
- default:
- // Should not happen
- throw new IOException();
- }
- }
- else {
- throw new IOException("Tag is not ndef");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return false;
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/NdefFormatable.java b/nfc/java/android/nfc/tech/NdefFormatable.java
deleted file mode 100644
index 2240fe7f7d3b..000000000000
--- a/nfc/java/android/nfc/tech/NdefFormatable.java
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.FormatException;
-import android.nfc.INfcTag;
-import android.nfc.NdefMessage;
-import android.nfc.Tag;
-import android.nfc.TagLostException;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Provide access to NDEF format operations on a {@link Tag}.
- *
- * <p>Acquire a {@link NdefFormatable} object using {@link #get}.
- *
- * <p>Android devices with NFC must only enumerate and implement this
- * class for tags for which it can format to NDEF.
- *
- * <p>Unfortunately the procedures to convert unformated tags to NDEF formatted
- * tags are not specified by NFC Forum, and are not generally well-known. So
- * there is no mandatory set of tags for which all Android devices with NFC
- * must support {@link NdefFormatable}.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class NdefFormatable extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /**
- * Get an instance of {@link NdefFormatable} for the given tag.
- * <p>Does not cause any RF activity and does not block.
- * <p>Returns null if {@link NdefFormatable} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag is not NDEF formatable by this Android device.
- *
- * @param tag an NDEF formatable tag
- * @return NDEF formatable object
- */
- public static NdefFormatable get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NDEF_FORMATABLE)) return null;
- try {
- return new NdefFormatable(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
- * Internal constructor, to be used by NfcAdapter
- * @hide
- */
- public NdefFormatable(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NDEF_FORMATABLE);
- }
-
- /**
- * Format a tag as NDEF, and write a {@link NdefMessage}.
- *
- * <p>This is a multi-step process, an IOException is thrown
- * if any one step fails.
- * <p>The card is left in a read-write state after this operation.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param firstMessage the NDEF message to write after formatting, can be null
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- * @throws FormatException if the NDEF Message to write is malformed
- */
- public void format(NdefMessage firstMessage) throws IOException, FormatException {
- format(firstMessage, false);
- }
-
- /**
- * Formats a tag as NDEF, write a {@link NdefMessage}, and make read-only.
- *
- * <p>This is a multi-step process, an IOException is thrown
- * if any one step fails.
- * <p>The card is left in a read-only state if this method returns successfully.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param firstMessage the NDEF message to write after formatting
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or the operation is canceled
- * @throws FormatException if the NDEF Message to write is malformed
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void formatReadOnly(NdefMessage firstMessage) throws IOException, FormatException {
- format(firstMessage, true);
- }
-
- /*package*/ void format(NdefMessage firstMessage, boolean makeReadOnly) throws IOException,
- FormatException {
- checkConnected();
-
- try {
- int serviceHandle = mTag.getServiceHandle();
- INfcTag tagService = mTag.getTagService();
- if (tagService == null) {
- throw new IOException();
- }
- int errorCode = tagService.formatNdef(serviceHandle, MifareClassic.KEY_DEFAULT);
- switch (errorCode) {
- case ErrorCodes.SUCCESS:
- break;
- case ErrorCodes.ERROR_IO:
- throw new IOException();
- case ErrorCodes.ERROR_INVALID_PARAM:
- throw new FormatException();
- default:
- // Should not happen
- throw new IOException();
- }
- // Now check and see if the format worked
- if (!tagService.isNdef(serviceHandle)) {
- throw new IOException();
- }
-
- // Write a message, if one was provided
- if (firstMessage != null) {
- errorCode = tagService.ndefWrite(serviceHandle, firstMessage);
- switch (errorCode) {
- case ErrorCodes.SUCCESS:
- break;
- case ErrorCodes.ERROR_IO:
- throw new IOException();
- case ErrorCodes.ERROR_INVALID_PARAM:
- throw new FormatException();
- default:
- // Should not happen
- throw new IOException();
- }
- }
-
- // optionally make read-only
- if (makeReadOnly) {
- errorCode = tagService.ndefMakeReadOnly(serviceHandle);
- switch (errorCode) {
- case ErrorCodes.SUCCESS:
- break;
- case ErrorCodes.ERROR_IO:
- throw new IOException();
- case ErrorCodes.ERROR_INVALID_PARAM:
- throw new IOException();
- default:
- // Should not happen
- throw new IOException();
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/NfcA.java b/nfc/java/android/nfc/tech/NfcA.java
deleted file mode 100644
index 7e6648361670..000000000000
--- a/nfc/java/android/nfc/tech/NfcA.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Provides access to NFC-A (ISO 14443-3A) properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire a {@link NfcA} object using {@link #get}.
- * <p>The primary NFC-A I/O operation is {@link #transceive}. Applications must
- * implement their own protocol stack on top of {@link #transceive}.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class NfcA extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /** @hide */
- public static final String EXTRA_SAK = "sak";
- /** @hide */
- public static final String EXTRA_ATQA = "atqa";
-
- private short mSak;
- private byte[] mAtqa;
-
- /**
- * Get an instance of {@link NfcA} for the given tag.
- * <p>Returns null if {@link NfcA} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag does not support NFC-A.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an NFC-A compatible tag
- * @return NFC-A object
- */
- public static NfcA get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NFC_A)) return null;
- try {
- return new NfcA(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public NfcA(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NFC_A);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_A);
- mSak = extras.getShort(EXTRA_SAK);
- mAtqa = extras.getByteArray(EXTRA_ATQA);
- }
-
- /**
- * Return the ATQA/SENS_RES bytes from tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return ATQA/SENS_RES bytes
- */
- public byte[] getAtqa() {
- return mAtqa;
- }
-
- /**
- * Return the SAK/SEL_RES bytes from tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return SAK bytes
- */
- public short getSak() {
- return mSak;
- }
-
- /**
- * Send raw NFC-A commands to the tag and receive the response.
- *
- * <p>Applications must not append the EoD (CRC) to the payload,
- * it will be automatically calculated.
- * <p>Applications must only send commands that are complete bytes,
- * for example a SENS_REQ is not possible (these are used to
- * manage tag polling and initialization).
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param data bytes to send
- * @return bytes received in response
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or this operation is canceled
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-
- /**
- * Set the {@link #transceive} timeout in milliseconds.
- *
- * <p>The timeout only applies to {@link #transceive} on this object,
- * and is reset to a default value when {@link #close} is called.
- *
- * <p>Setting a longer timeout may be useful when performing
- * transactions that require a long processing time on the tag
- * such as key generation.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param timeout timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void setTimeout(int timeout) {
- try {
- int err = mTag.getTagService().setTimeout(TagTechnology.NFC_A, timeout);
- if (err != ErrorCodes.SUCCESS) {
- throw new IllegalArgumentException("The supplied timeout is not valid");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-
- /**
- * Get the current {@link #transceive} timeout in milliseconds.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public int getTimeout() {
- try {
- return mTag.getTagService().getTimeout(TagTechnology.NFC_A);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return 0;
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/NfcB.java b/nfc/java/android/nfc/tech/NfcB.java
deleted file mode 100644
index 3ebd47f610c0..000000000000
--- a/nfc/java/android/nfc/tech/NfcB.java
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import java.io.IOException;
-
-/**
- * Provides access to NFC-B (ISO 14443-3B) properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire a {@link NfcB} object using {@link #get}.
- * <p>The primary NFC-B I/O operation is {@link #transceive}. Applications must
- * implement their own protocol stack on top of {@link #transceive}.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class NfcB extends BasicTagTechnology {
- /** @hide */
- public static final String EXTRA_APPDATA = "appdata";
- /** @hide */
- public static final String EXTRA_PROTINFO = "protinfo";
-
- private byte[] mAppData;
- private byte[] mProtInfo;
-
- /**
- * Get an instance of {@link NfcB} for the given tag.
- * <p>Returns null if {@link NfcB} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag does not support NFC-B.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an NFC-B compatible tag
- * @return NFC-B object
- */
- public static NfcB get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NFC_B)) return null;
- try {
- return new NfcB(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public NfcB(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NFC_B);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_B);
- mAppData = extras.getByteArray(EXTRA_APPDATA);
- mProtInfo = extras.getByteArray(EXTRA_PROTINFO);
- }
-
- /**
- * Return the Application Data bytes from ATQB/SENSB_RES at tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return Application Data bytes from ATQB/SENSB_RES bytes
- */
- public byte[] getApplicationData() {
- return mAppData;
- }
-
- /**
- * Return the Protocol Info bytes from ATQB/SENSB_RES at tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return Protocol Info bytes from ATQB/SENSB_RES bytes
- */
- public byte[] getProtocolInfo() {
- return mProtInfo;
- }
-
- /**
- * Send raw NFC-B commands to the tag and receive the response.
- *
- * <p>Applications must not append the EoD (CRC) to the payload,
- * it will be automatically calculated.
- * <p>Applications must not send commands that manage the polling
- * loop and initialization (SENSB_REQ, SLOT_MARKER etc).
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum number of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param data bytes to send
- * @return bytes received in response
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or this operation is canceled
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-}
diff --git a/nfc/java/android/nfc/tech/NfcBarcode.java b/nfc/java/android/nfc/tech/NfcBarcode.java
deleted file mode 100644
index 421ba7827cb1..000000000000
--- a/nfc/java/android/nfc/tech/NfcBarcode.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (C) 2012 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.nfc.tech;
-
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-/**
- * Provides access to tags containing just a barcode.
- *
- * <p>Acquire an {@link NfcBarcode} object using {@link #get}.
- *
- */
-public final class NfcBarcode extends BasicTagTechnology {
-
- /** Kovio Tags */
- public static final int TYPE_KOVIO = 1;
- public static final int TYPE_UNKNOWN = -1;
-
- /** @hide */
- public static final String EXTRA_BARCODE_TYPE = "barcodetype";
-
- private int mType;
-
- /**
- * Get an instance of {@link NfcBarcode} for the given tag.
- *
- * <p>Returns null if {@link NfcBarcode} was not enumerated in {@link Tag#getTechList}.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an NfcBarcode compatible tag
- * @return NfcBarcode object
- */
- public static NfcBarcode get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NFC_BARCODE)) return null;
- try {
- return new NfcBarcode(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
- * Internal constructor, to be used by NfcAdapter
- * @hide
- */
- public NfcBarcode(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NFC_BARCODE);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_BARCODE);
- if (extras != null) {
- mType = extras.getInt(EXTRA_BARCODE_TYPE);
- } else {
- throw new NullPointerException("NfcBarcode tech extras are null.");
- }
- }
-
- /**
- * Returns the NFC Barcode tag type.
- *
- * <p>Currently only one of {@link #TYPE_KOVIO} or {@link #TYPE_UNKNOWN}.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return the NFC Barcode tag type
- */
- public int getType() {
- return mType;
- }
-
- /**
- * Returns the barcode of an NfcBarcode tag.
- *
- * <p> Tags of {@link #TYPE_KOVIO} return 16 bytes:
- * <ul>
- * <p> The first byte is 0x80 ORd with a manufacturer ID, corresponding
- * to ISO/IEC 7816-6.
- * <p> The second byte describes the payload data format. Defined data
- * format types include the following:<ul>
- * <li>0x00: Reserved for manufacturer assignment</li>
- * <li>0x01: 96-bit URL with "http://www." prefix</li>
- * <li>0x02: 96-bit URL with "https://www." prefix</li>
- * <li>0x03: 96-bit URL with "http://" prefix</li>
- * <li>0x04: 96-bit URL with "https://" prefix</li>
- * <li>0x05: 96-bit GS1 EPC</li>
- * <li>0x06-0xFF: reserved</li>
- * </ul>
- * <p>The following 12 bytes are payload:<ul>
- * <li> In case of a URL payload, the payload is encoded in US-ASCII,
- * following the limitations defined in RFC3987.
- * {@see <a href="http://www.ietf.org/rfc/rfc3987.txt">RFC 3987</a>}</li>
- * <li> In case of GS1 EPC data, see <a href="http://www.gs1.org/gsmp/kc/epcglobal/tds/">
- * GS1 Electronic Product Code (EPC) Tag Data Standard (TDS)</a> for more details.
- * </li>
- * </ul>
- * <p>The last 2 bytes comprise the CRC.
- * </ul>
- * <p>Does not cause any RF activity and does not block.
- *
- * @return a byte array containing the barcode
- * @see <a href="http://www.thinfilm.no/docs/thinfilm-nfc-barcode-datasheet.pdf">
- * Thinfilm NFC Barcode tag specification (previously Kovio NFC Barcode)</a>
- * @see <a href="http://www.thinfilm.no/docs/thinfilm-nfc-barcode-data-format.pdf">
- * Thinfilm NFC Barcode data format (previously Kovio NFC Barcode)</a>
- */
- public byte[] getBarcode() {
- switch (mType) {
- case TYPE_KOVIO:
- // For Kovio tags the barcode matches the ID
- return mTag.getId();
- default:
- return null;
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/NfcF.java b/nfc/java/android/nfc/tech/NfcF.java
deleted file mode 100644
index 2ccd38875f07..000000000000
--- a/nfc/java/android/nfc/tech/NfcF.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.ErrorCodes;
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-/**
- * Provides access to NFC-F (JIS 6319-4) properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire a {@link NfcF} object using {@link #get}.
- * <p>The primary NFC-F I/O operation is {@link #transceive}. Applications must
- * implement their own protocol stack on top of {@link #transceive}.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class NfcF extends BasicTagTechnology {
- private static final String TAG = "NFC";
-
- /** @hide */
- public static final String EXTRA_SC = "systemcode";
- /** @hide */
- public static final String EXTRA_PMM = "pmm";
-
- private byte[] mSystemCode = null;
- private byte[] mManufacturer = null;
-
- /**
- * Get an instance of {@link NfcF} for the given tag.
- * <p>Returns null if {@link NfcF} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag does not support NFC-F.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an NFC-F compatible tag
- * @return NFC-F object
- */
- public static NfcF get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NFC_F)) return null;
- try {
- return new NfcF(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public NfcF(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NFC_F);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_F);
- if (extras != null) {
- mSystemCode = extras.getByteArray(EXTRA_SC);
- mManufacturer = extras.getByteArray(EXTRA_PMM);
- }
- }
-
- /**
- * Return the System Code bytes from tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return System Code bytes
- */
- public byte[] getSystemCode() {
- return mSystemCode;
- }
-
- /**
- * Return the Manufacturer bytes from tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return Manufacturer bytes
- */
- public byte[] getManufacturer() {
- return mManufacturer;
- }
-
- /**
- * Send raw NFC-F commands to the tag and receive the response.
- *
- * <p>Applications must not prefix the SoD (preamble and sync code)
- * and/or append the EoD (CRC) to the payload, it will be automatically calculated.
- *
- * <p>A typical NFC-F frame for this method looks like:
- * <pre>
- * LENGTH (1 byte) --- CMD (1 byte) -- IDm (8 bytes) -- PARAMS (LENGTH - 10 bytes)
- * </pre>
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum amount of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param data bytes to send
- * @return bytes received in response
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or this operation is canceled
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-
- /**
- * Set the {@link #transceive} timeout in milliseconds.
- *
- * <p>The timeout only applies to {@link #transceive} on this object,
- * and is reset to a default value when {@link #close} is called.
- *
- * <p>Setting a longer timeout may be useful when performing
- * transactions that require a long processing time on the tag
- * such as key generation.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param timeout timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void setTimeout(int timeout) {
- try {
- int err = mTag.getTagService().setTimeout(TagTechnology.NFC_F, timeout);
- if (err != ErrorCodes.SUCCESS) {
- throw new IllegalArgumentException("The supplied timeout is not valid");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- }
- }
-
- /**
- * Get the current {@link #transceive} timeout in milliseconds.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @return timeout value in milliseconds
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public int getTimeout() {
- try {
- return mTag.getTagService().getTimeout(TagTechnology.NFC_F);
- } catch (RemoteException e) {
- Log.e(TAG, "NFC service dead", e);
- return 0;
- }
- }
-}
diff --git a/nfc/java/android/nfc/tech/NfcV.java b/nfc/java/android/nfc/tech/NfcV.java
deleted file mode 100644
index 186c63bf07fd..000000000000
--- a/nfc/java/android/nfc/tech/NfcV.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import java.io.IOException;
-
-/**
- * Provides access to NFC-V (ISO 15693) properties and I/O operations on a {@link Tag}.
- *
- * <p>Acquire a {@link NfcV} object using {@link #get}.
- * <p>The primary NFC-V I/O operation is {@link #transceive}. Applications must
- * implement their own protocol stack on top of {@link #transceive}.
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public final class NfcV extends BasicTagTechnology {
- /** @hide */
- public static final String EXTRA_RESP_FLAGS = "respflags";
-
- /** @hide */
- public static final String EXTRA_DSFID = "dsfid";
-
- private byte mRespFlags;
- private byte mDsfId;
-
- /**
- * Get an instance of {@link NfcV} for the given tag.
- * <p>Returns null if {@link NfcV} was not enumerated in {@link Tag#getTechList}.
- * This indicates the tag does not support NFC-V.
- * <p>Does not cause any RF activity and does not block.
- *
- * @param tag an NFC-V compatible tag
- * @return NFC-V object
- */
- public static NfcV get(Tag tag) {
- if (!tag.hasTech(TagTechnology.NFC_V)) return null;
- try {
- return new NfcV(tag);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /** @hide */
- public NfcV(Tag tag) throws RemoteException {
- super(tag, TagTechnology.NFC_V);
- Bundle extras = tag.getTechExtras(TagTechnology.NFC_V);
- mRespFlags = extras.getByte(EXTRA_RESP_FLAGS);
- mDsfId = extras.getByte(EXTRA_DSFID);
- }
-
- /**
- * Return the Response Flag bytes from tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return Response Flag bytes
- */
- public byte getResponseFlags() {
- return mRespFlags;
- }
-
- /**
- * Return the DSF ID bytes from tag discovery.
- *
- * <p>Does not cause any RF activity and does not block.
- *
- * @return DSF ID bytes
- */
- public byte getDsfId() {
- return mDsfId;
- }
-
- /**
- * Send raw NFC-V commands to the tag and receive the response.
- *
- * <p>Applications must not append the CRC to the payload,
- * it will be automatically calculated. The application does
- * provide FLAGS, CMD and PARAMETER bytes.
- *
- * <p>Use {@link #getMaxTransceiveLength} to retrieve the maximum amount of bytes
- * that can be sent with {@link #transceive}.
- *
- * <p>This is an I/O operation and will block until complete. It must
- * not be called from the main application thread. A blocked call will be canceled with
- * {@link IOException} if {@link #close} is called from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @param data bytes to send
- * @return bytes received in response
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or this operation is canceled
- */
- public byte[] transceive(byte[] data) throws IOException {
- return transceive(data, true);
- }
-
-
- /**
- * Return the maximum number of bytes that can be sent with {@link #transceive}.
- * @return the maximum number of bytes that can be sent with {@link #transceive}.
- */
- public int getMaxTransceiveLength() {
- return getMaxTransceiveLengthInternal();
- }
-}
diff --git a/nfc/java/android/nfc/tech/TagTechnology.java b/nfc/java/android/nfc/tech/TagTechnology.java
deleted file mode 100644
index 839fe429b338..000000000000
--- a/nfc/java/android/nfc/tech/TagTechnology.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import android.nfc.Tag;
-
-import java.io.Closeable;
-import java.io.IOException;
-
-/**
- * {@link TagTechnology} is an interface to a technology in a {@link Tag}.
- * <p>
- * Obtain a {@link TagTechnology} implementation by calling the static method <code>get()</code>
- * on the implementation class.
- * <p>
- * NFC tags are based on a number of independently developed technologies and offer a
- * wide range of capabilities. The
- * {@link TagTechnology} implementations provide access to these different
- * technologies and capabilities. Some sub-classes map to technology
- * specification (for example {@link NfcA}, {@link IsoDep}, others map to
- * pseudo-technologies or capabilities (for example {@link Ndef}, {@link NdefFormatable}).
- * <p>
- * It is mandatory for all Android NFC devices to provide the following
- * {@link TagTechnology} implementations.
- * <ul>
- * <li>{@link NfcA} (also known as ISO 14443-3A)
- * <li>{@link NfcB} (also known as ISO 14443-3B)
- * <li>{@link NfcF} (also known as JIS 6319-4)
- * <li>{@link NfcV} (also known as ISO 15693)
- * <li>{@link IsoDep}
- * <li>{@link Ndef} on NFC Forum Type 1, Type 2, Type 3 or Type 4 compliant tags
- * </ul>
- * It is optional for Android NFC devices to provide the following
- * {@link TagTechnology} implementations. If it is not provided, the
- * Android device will never enumerate that class via {@link Tag#getTechList}.
- * <ul>
- * <li>{@link MifareClassic}
- * <li>{@link MifareUltralight}
- * <li>{@link NfcBarcode}
- * <li>{@link NdefFormatable} must only be enumerated on tags for which this Android device
- * is capable of formatting. Proprietary knowledge is often required to format a tag
- * to make it NDEF compatible.
- * </ul>
- * <p>
- * {@link TagTechnology} implementations provide methods that fall into two classes:
- * <em>cached getters</em> and <em>I/O operations</em>.
- * <h4>Cached getters</h4>
- * These methods (usually prefixed by <code>get</code> or <code>is</code>) return
- * properties of the tag, as determined at discovery time. These methods will never
- * block or cause RF activity, and do not require {@link #connect} to have been called.
- * They also never update, for example if a property is changed by an I/O operation with a tag
- * then the cached getter will still return the result from tag discovery time.
- * <h4>I/O operations</h4>
- * I/O operations may require RF activity, and may block. They have the following semantics.
- * <ul>
- * <li>{@link #connect} must be called before using any other I/O operation.
- * <li>{@link #close} must be called after completing I/O operations with a
- * {@link TagTechnology}, and it will cancel all other blocked I/O operations on other threads
- * (including {@link #connect} with {@link IOException}.
- * <li>Only one {@link TagTechnology} can be connected at a time. Other calls to
- * {@link #connect} will return {@link IOException}.
- * <li>I/O operations may block, and should never be called on the main application
- * thread.
- * </ul>
- *
- * <p class="note"><strong>Note:</strong> Methods that perform I/O operations
- * require the {@link android.Manifest.permission#NFC} permission.
- */
-public interface TagTechnology extends Closeable {
- /**
- * This technology is an instance of {@link NfcA}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int NFC_A = 1;
-
- /**
- * This technology is an instance of {@link NfcB}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int NFC_B = 2;
-
- /**
- * This technology is an instance of {@link IsoDep}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int ISO_DEP = 3;
-
- /**
- * This technology is an instance of {@link NfcF}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int NFC_F = 4;
-
- /**
- * This technology is an instance of {@link NfcV}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int NFC_V = 5;
-
- /**
- * This technology is an instance of {@link Ndef}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int NDEF = 6;
-
- /**
- * This technology is an instance of {@link NdefFormatable}.
- * <p>Support for this technology type is mandatory.
- * @hide
- */
- public static final int NDEF_FORMATABLE = 7;
-
- /**
- * This technology is an instance of {@link MifareClassic}.
- * <p>Support for this technology type is optional. If a stack doesn't support this technology
- * type tags using it must still be discovered and present the lower level radio interface
- * technologies in use.
- * @hide
- */
- public static final int MIFARE_CLASSIC = 8;
-
- /**
- * This technology is an instance of {@link MifareUltralight}.
- * <p>Support for this technology type is optional. If a stack doesn't support this technology
- * type tags using it must still be discovered and present the lower level radio interface
- * technologies in use.
- * @hide
- */
- public static final int MIFARE_ULTRALIGHT = 9;
-
- /**
- * This technology is an instance of {@link NfcBarcode}.
- * <p>Support for this technology type is optional. If a stack doesn't support this technology
- * type tags using it must still be discovered and present the lower level radio interface
- * technologies in use.
- * @hide
- */
- public static final int NFC_BARCODE = 10;
-
- /**
- * Get the {@link Tag} object backing this {@link TagTechnology} object.
- * @return the {@link Tag} backing this {@link TagTechnology} object.
- */
- public Tag getTag();
-
- /**
- * Enable I/O operations to the tag from this {@link TagTechnology} object.
- * <p>May cause RF activity and may block. Must not be called
- * from the main application thread. A blocked call will be canceled with
- * {@link IOException} by calling {@link #close} from another thread.
- * <p>Only one {@link TagTechnology} object can be connected to a {@link Tag} at a time.
- * <p>Applications must call {@link #close} when I/O operations are complete.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @see #close()
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or connect is canceled
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void connect() throws IOException;
-
- /**
- * Re-connect to the {@link Tag} associated with this connection. Reconnecting to a tag can be
- * used to reset the state of the tag itself.
- *
- * <p>May cause RF activity and may block. Must not be called
- * from the main application thread. A blocked call will be canceled with
- * {@link IOException} by calling {@link #close} from another thread.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @see #connect()
- * @see #close()
- * @throws TagLostException if the tag leaves the field
- * @throws IOException if there is an I/O failure, or connect is canceled
- * @throws SecurityException if the tag object is reused after the tag has left the field
- * @hide
- */
- public void reconnect() throws IOException;
-
- /**
- * Disable I/O operations to the tag from this {@link TagTechnology} object, and release resources.
- * <p>Also causes all blocked I/O operations on other thread to be canceled and
- * return with {@link IOException}.
- *
- * <p class="note">Requires the {@link android.Manifest.permission#NFC} permission.
- *
- * @see #connect()
- * @throws SecurityException if the tag object is reused after the tag has left the field
- */
- public void close() throws IOException;
-
- /**
- * Helper to indicate if I/O operations should be possible.
- *
- * <p>Returns true if {@link #connect} has completed, and {@link #close} has not been
- * called, and the {@link Tag} is not known to be out of range.
- * <p>Does not cause RF activity, and does not block.
- *
- * @return true if I/O operations should be possible
- */
- public boolean isConnected();
-}
diff --git a/nfc/java/android/nfc/tech/package.html b/nfc/java/android/nfc/tech/package.html
deleted file mode 100644
index a99828f90c5b..000000000000
--- a/nfc/java/android/nfc/tech/package.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<HTML>
-<BODY>
-<p>
-These classes provide access to a tag technology's features, which vary by the type
-of tag that is scanned. A scanned tag can support multiple technologies, and you can find
-out what they are by calling {@link android.nfc.Tag#getTechList getTechList()}.</p>
-
-<p>For more information on dealing with tag technologies and handling the ones that you care about, see
-<a href="{@docRoot}guide/topics/nfc/index.html#dispatch">The Tag Dispatch System</a>.
-The {@link android.nfc.tech.TagTechnology} interface provides an overview of the
-supported technologies.</p>
-</BODY>
-</HTML>
diff --git a/nfc/lint-baseline.xml b/nfc/lint-baseline.xml
deleted file mode 100644
index 67b496e0baf3..000000000000
--- a/nfc/lint-baseline.xml
+++ /dev/null
@@ -1,81 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
-
- <issue
- id="FlaggedApi"
- message="Method `NfcOemExtension()` is a flagged API and should be inside an `if (Flags.nfcOemExtension())` check (or annotate the surrounding method `NfcAdapter` with `@FlaggedApi(Flags.FLAG_NFC_OEM_EXTENSION) to transfer requirement to caller`)"
- errorLine1=" mNfcOemExtension = new NfcOemExtension(mContext, this);"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
- line="909"
- column="28"/>
- </issue>
-
- <issue
- id="FlaggedApi"
- message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
- errorLine1=" &amp;&amp; ((pollTechnology &amp; FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
- line="1917"
- column="39"/>
- </issue>
-
- <issue
- id="FlaggedApi"
- message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
- errorLine1=" &amp;&amp; ((pollTechnology &amp; FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
- line="1917"
- column="65"/>
- </issue>
-
- <issue
- id="FlaggedApi"
- message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
- errorLine1=" || (listenTechnology &amp; FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
- line="1918"
- column="40"/>
- </issue>
-
- <issue
- id="FlaggedApi"
- message="Field `FLAG_SET_DEFAULT_TECH` is a flagged API and should be inside an `if (Flags.nfcSetDefaultDiscTech())` check (or annotate the surrounding method `setDiscoveryTechnology` with `@FlaggedApi(Flags.FLAG_NFC_SET_DEFAULT_DISC_TECH) to transfer requirement to caller`)"
- errorLine1=" || (listenTechnology &amp; FLAG_SET_DEFAULT_TECH) == FLAG_SET_DEFAULT_TECH)) {"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcAdapter.java"
- line="1918"
- column="66"/>
- </issue>
-
- <issue
- id="FlaggedApi"
- message="Method `onVendorNciResponse()` is a flagged API and should be inside an `if (Flags.nfcVendorCmd())` check (or annotate the surrounding method `onVendorResponseReceived` with `@FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD) to transfer requirement to caller`)"
- errorLine1=" executor.execute(() -> callback.onVendorNciResponse(gid, oid, payload));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcVendorNciCallbackListener.java"
- line="88"
- column="44"/>
- </issue>
-
- <issue
- id="FlaggedApi"
- message="Method `onVendorNciNotification()` is a flagged API and should be inside an `if (Flags.nfcVendorCmd())` check (or annotate the surrounding method `onVendorNotificationReceived` with `@FlaggedApi(Flags.FLAG_NFC_VENDOR_CMD) to transfer requirement to caller`)"
- errorLine1=" executor.execute(() -> callback.onVendorNciNotification(gid, oid, payload));"
- errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
- <location
- file="frameworks/base/nfc/java/android/nfc/NfcVendorNciCallbackListener.java"
- line="106"
- column="44"/>
- </issue>
-
-</issues>
diff --git a/nfc/tests/Android.bp b/nfc/tests/Android.bp
deleted file mode 100644
index 17fb810c626b..000000000000
--- a/nfc/tests/Android.bp
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright 2021 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package {
- default_team: "trendy_team_fwk_nfc",
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_base_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_base_license"],
-}
-
-android_test {
- name: "NfcManagerTests",
- static_libs: [
- "androidx.test.core",
- "androidx.test.rules",
- "androidx.test.runner",
- "androidx.test.ext.junit",
- "mockito-target-extended-minus-junit4",
- "frameworks-base-testutils",
- "truth",
- "androidx.annotation_annotation",
- "androidx.appcompat_appcompat",
- "flag-junit",
- "platform-test-annotations",
- "testables",
- ],
- libs: [
- "androidx.annotation_annotation",
- "unsupportedappusage", // for android.compat.annotation.UnsupportedAppUsage
- "framework-permission-s.stubs.module_lib",
- "framework-permission.stubs.module_lib",
- "android.test.base.stubs.system",
- "android.test.mock.stubs.system",
- "android.test.runner.stubs.system",
- "framework-nfc.impl",
- ],
- jni_libs: [
- // Required for ExtendedMockito
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
- srcs: [
- "src/**/*.java",
- ":framework-nfc-updatable-sources",
- ":framework-nfc-non-updatable-sources",
- ],
- platform_apis: true,
- certificate: "platform",
- test_suites: [
- "device-tests",
- "mts-nfc",
- ],
- min_sdk_version: "35", // Should be 36 later.
-}
diff --git a/nfc/tests/AndroidManifest.xml b/nfc/tests/AndroidManifest.xml
deleted file mode 100644
index 95646720d3d5..000000000000
--- a/nfc/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.nfc">
-
- <application android:debuggable="true">
- <uses-library android:name="android.test.runner" />
- </application>
-
- <!-- This is a self-instrumenting test package. -->
- <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.nfc"
- android:label="NFC Manager Tests">
- </instrumentation>
-
-</manifest>
-
diff --git a/nfc/tests/AndroidTest.xml b/nfc/tests/AndroidTest.xml
deleted file mode 100644
index 490d6f5df197..000000000000
--- a/nfc/tests/AndroidTest.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2021 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<configuration description="Config for NFC Manager test cases">
- <option name="test-suite-tag" value="apct"/>
- <option name="test-suite-tag" value="apct-instrumentation"/>
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="test-file-name" value="NfcManagerTests.apk" />
- </target_preparer>
-
- <option name="test-suite-tag" value="apct"/>
- <option name="test-tag" value="NfcManagerTests"/>
-
- <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
- <option name="package" value="android.nfc" />
- <option name="hidden-api-checks" value="false"/>
- <option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
- </test>
-</configuration>
diff --git a/nfc/tests/src/android/nfc/NdefMessageTest.java b/nfc/tests/src/android/nfc/NdefMessageTest.java
deleted file mode 100644
index 9ca295da75c3..000000000000
--- a/nfc/tests/src/android/nfc/NdefMessageTest.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class NdefMessageTest {
- private NdefMessage mNdefMessage;
- private NdefRecord mNdefRecord;
-
- @Before
- public void setUp() {
- mNdefRecord = NdefRecord.createUri("http://www.example.com");
- mNdefMessage = new NdefMessage(mNdefRecord);
- }
-
- @After
- public void tearDown() {
- }
-
- @Test
- public void testGetRecords() {
- NdefRecord[] records = mNdefMessage.getRecords();
- assertThat(records).isNotNull();
- assertThat(records).hasLength(1);
- assertThat(records[0]).isEqualTo(mNdefRecord);
- }
-
- @Test
- public void testToByteArray() throws FormatException {
- byte[] bytes = mNdefMessage.toByteArray();
- assertThat(bytes).isNotNull();
- assertThat(bytes.length).isGreaterThan(0);
- NdefMessage ndefMessage = new NdefMessage(bytes);
- assertThat(ndefMessage).isNotNull();
- }
-}
diff --git a/nfc/tests/src/android/nfc/NdefRecordTest.java b/nfc/tests/src/android/nfc/NdefRecordTest.java
deleted file mode 100644
index 044c67448329..000000000000
--- a/nfc/tests/src/android/nfc/NdefRecordTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Locale;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NdefRecordTest {
-
- @Test
- public void testNdefRecordConstructor() throws FormatException {
- NdefRecord applicationRecord = NdefRecord
- .createApplicationRecord("com.android.test");
- NdefRecord ndefRecord = new NdefRecord(applicationRecord.toByteArray());
- assertThat(ndefRecord).isNotNull();
- assertThat(ndefRecord.toByteArray().length).isGreaterThan(0);
- assertThat(ndefRecord.getType()).isEqualTo("android.com:pkg".getBytes());
- assertThat(ndefRecord.getPayload()).isEqualTo("com.android.test".getBytes());
- }
-
- @Test
- public void testCreateExternal() {
- NdefRecord ndefRecord = NdefRecord.createExternal("test",
- "android.com:pkg", "com.android.test".getBytes());
- assertThat(ndefRecord).isNotNull();
- assertThat(ndefRecord.getType()).isEqualTo("test:android.com:pkg".getBytes());
- assertThat(ndefRecord.getPayload()).isEqualTo("com.android.test".getBytes());
- }
-
- @Test
- public void testCreateUri() {
- NdefRecord ndefRecord = NdefRecord.createUri("http://www.example.com");
- assertThat(ndefRecord).isNotNull();
- assertThat(ndefRecord.getTnf()).isEqualTo(NdefRecord.TNF_WELL_KNOWN);
- assertThat(ndefRecord.getType()).isEqualTo(NdefRecord.RTD_URI);
- }
-
- @Test
- public void testCreateMime() {
- NdefRecord ndefRecord = NdefRecord.createMime("text/plain", "example".getBytes());
- assertThat(ndefRecord).isNotNull();
- assertThat(ndefRecord.getTnf()).isEqualTo(NdefRecord.TNF_MIME_MEDIA);
- }
-
- @Test
- public void testCreateTextRecord() {
- String languageCode = Locale.getDefault().getLanguage();
- NdefRecord ndefRecord = NdefRecord.createTextRecord(languageCode, "testdata");
- assertThat(ndefRecord).isNotNull();
- assertThat(ndefRecord.getTnf()).isEqualTo(NdefRecord.TNF_WELL_KNOWN);
- assertThat(ndefRecord.getType()).isEqualTo(NdefRecord.RTD_TEXT);
- }
-
-}
diff --git a/nfc/tests/src/android/nfc/NfcAntennaInfoTest.java b/nfc/tests/src/android/nfc/NfcAntennaInfoTest.java
deleted file mode 100644
index c24816d85517..000000000000
--- a/nfc/tests/src/android/nfc/NfcAntennaInfoTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.Mockito.mock;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NfcAntennaInfoTest {
- private NfcAntennaInfo mNfcAntennaInfo;
-
-
- @Before
- public void setUp() {
- AvailableNfcAntenna availableNfcAntenna = mock(AvailableNfcAntenna.class);
- List<AvailableNfcAntenna> antennas = new ArrayList<>();
- antennas.add(availableNfcAntenna);
- mNfcAntennaInfo = new NfcAntennaInfo(1, 1, false, antennas);
- }
-
- @After
- public void tearDown() {
- }
-
- @Test
- public void testGetDeviceHeight() {
- int height = mNfcAntennaInfo.getDeviceHeight();
- assertThat(height).isEqualTo(1);
- }
-
- @Test
- public void testGetDeviceWidth() {
- int width = mNfcAntennaInfo.getDeviceWidth();
- assertThat(width).isEqualTo(1);
- }
-
- @Test
- public void testIsDeviceFoldable() {
- boolean foldable = mNfcAntennaInfo.isDeviceFoldable();
- assertThat(foldable).isFalse();
- }
-
- @Test
- public void testGetAvailableNfcAntennas() {
- List<AvailableNfcAntenna> antennas = mNfcAntennaInfo.getAvailableNfcAntennas();
- assertThat(antennas).isNotNull();
- assertThat(antennas.size()).isEqualTo(1);
- }
-
-}
diff --git a/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java b/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
deleted file mode 100644
index 48f4288d401e..000000000000
--- a/nfc/tests/src/android/nfc/NfcControllerAlwaysOnListenerTest.java
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
-import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
-import android.os.RemoteException;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.Executor;
-
-/**
- * Test of {@link NfcControllerAlwaysOnListener}.
- */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class NfcControllerAlwaysOnListenerTest {
-
- private INfcAdapter mNfcAdapter = mock(INfcAdapter.class);
-
- private Throwable mThrowRemoteException = new RemoteException("RemoteException");
-
- private static Executor getExecutor() {
- return new Executor() {
- @Override
- public void execute(Runnable command) {
- command.run();
- }
- };
- }
-
- private static void verifyListenerInvoked(ControllerAlwaysOnListener listener) {
- verify(listener, times(1)).onControllerAlwaysOnChanged(anyBoolean());
- }
-
- @Test
- public void testRegister_RegisterUnregisterWhenNotSupported() throws RemoteException {
- // isControllerAlwaysOnSupported() returns false, not supported.
- doReturn(false).when(mNfcAdapter).isControllerAlwaysOnSupported();
- NfcControllerAlwaysOnListener mListener =
- new NfcControllerAlwaysOnListener(mNfcAdapter);
- ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class);
- ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class);
-
- // Verify that the state listener will not registered with the NFC Adapter
- mListener.register(getExecutor(), mockListener1);
- verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any());
-
- // Register a second client and no any call to NFC Adapter
- mListener.register(getExecutor(), mockListener2);
- verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any());
-
- // Unregister first listener, and no any call to NFC Adapter
- mListener.unregister(mockListener1);
- verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any());
- verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any());
-
- // Unregister second listener, and no any call to NFC Adapter
- mListener.unregister(mockListener2);
- verify(mNfcAdapter, times(0)).registerControllerAlwaysOnListener(any());
- verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any());
- }
-
- @Test
- public void testRegister_RegisterUnregister() throws RemoteException {
- doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported();
- NfcControllerAlwaysOnListener mListener =
- new NfcControllerAlwaysOnListener(mNfcAdapter);
- ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class);
- ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class);
-
- // Verify that the state listener registered with the NFC Adapter
- mListener.register(getExecutor(), mockListener1);
- verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
-
- // Register a second client and no new call to NFC Adapter
- mListener.register(getExecutor(), mockListener2);
- verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
-
- // Unregister first listener
- mListener.unregister(mockListener1);
- verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
- verify(mNfcAdapter, times(0)).unregisterControllerAlwaysOnListener(any());
-
- // Unregister second listener and the state listener registered with the NFC Adapter
- mListener.unregister(mockListener2);
- verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
- verify(mNfcAdapter, times(1)).unregisterControllerAlwaysOnListener(any());
- }
-
- @Test
- public void testRegister_FirstRegisterFails() throws RemoteException {
- doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported();
- NfcControllerAlwaysOnListener mListener =
- new NfcControllerAlwaysOnListener(mNfcAdapter);
- ControllerAlwaysOnListener mockListener1 = mock(ControllerAlwaysOnListener.class);
- ControllerAlwaysOnListener mockListener2 = mock(ControllerAlwaysOnListener.class);
-
- // Throw a remote exception whenever first registering
- doThrow(mThrowRemoteException).when(mNfcAdapter).registerControllerAlwaysOnListener(
- any());
-
- mListener.register(getExecutor(), mockListener1);
- verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
-
- // No longer throw an exception, instead succeed
- doNothing().when(mNfcAdapter).registerControllerAlwaysOnListener(any());
-
- // Register a different listener
- mListener.register(getExecutor(), mockListener2);
- verify(mNfcAdapter, times(2)).registerControllerAlwaysOnListener(any());
-
- // Ensure first and second listener were invoked
- mListener.onControllerAlwaysOnChanged(true);
- verifyListenerInvoked(mockListener1);
- verifyListenerInvoked(mockListener2);
- }
-
- @Test
- public void testRegister_RegisterSameListenerTwice() throws RemoteException {
- doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported();
- NfcControllerAlwaysOnListener mListener =
- new NfcControllerAlwaysOnListener(mNfcAdapter);
- ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class);
-
- // Register the same listener Twice
- mListener.register(getExecutor(), mockListener);
- mListener.register(getExecutor(), mockListener);
- verify(mNfcAdapter, times(1)).registerControllerAlwaysOnListener(any());
-
- // Invoke a state change and ensure the listener is only called once
- mListener.onControllerAlwaysOnChanged(true);
- verifyListenerInvoked(mockListener);
- }
-
- @Test
- public void testNotify_AllListenersNotified() throws RemoteException {
- doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported();
- NfcControllerAlwaysOnListener listener = new NfcControllerAlwaysOnListener(mNfcAdapter);
- List<ControllerAlwaysOnListener> mockListeners = new ArrayList<>();
- for (int i = 0; i < 10; i++) {
- ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class);
- listener.register(getExecutor(), mockListener);
- mockListeners.add(mockListener);
- }
-
- // Invoke a state change and ensure all listeners are invoked
- listener.onControllerAlwaysOnChanged(true);
- for (ControllerAlwaysOnListener mListener : mockListeners) {
- verifyListenerInvoked(mListener);
- }
- }
-
- @Test
- public void testStateChange_CorrectValue() throws RemoteException {
- doReturn(true).when(mNfcAdapter).isControllerAlwaysOnSupported();
- runStateChangeValue(true, true);
- runStateChangeValue(false, false);
-
- }
-
- private void runStateChangeValue(boolean isEnabledIn, boolean isEnabledOut) {
- NfcControllerAlwaysOnListener listener = new NfcControllerAlwaysOnListener(mNfcAdapter);
- ControllerAlwaysOnListener mockListener = mock(ControllerAlwaysOnListener.class);
- listener.register(getExecutor(), mockListener);
- listener.onControllerAlwaysOnChanged(isEnabledIn);
- verify(mockListener, times(1)).onControllerAlwaysOnChanged(isEnabledOut);
- verify(mockListener, times(0)).onControllerAlwaysOnChanged(!isEnabledOut);
- }
-}
diff --git a/nfc/tests/src/android/nfc/NfcManagerTest.java b/nfc/tests/src/android/nfc/NfcManagerTest.java
deleted file mode 100644
index 06314cc03d37..000000000000
--- a/nfc/tests/src/android/nfc/NfcManagerTest.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-
-@RunWith(AndroidJUnit4.class)
-public class NfcManagerTest {
-
- private MockitoSession mMockitoSession;
- private NfcManager mNfcManager;
- @Mock
- private Context mContext;
-
- @Before
- public void setUp() {
- mMockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(NfcAdapter.class)
- .strictness(Strictness.LENIENT)
- .startMocking();
- MockitoAnnotations.initMocks(this);
-
- when(NfcAdapter.getNfcAdapter(any())).thenReturn(mock(NfcAdapter.class));
- when(mContext.getApplicationContext()).thenReturn(mContext);
- mNfcManager = new NfcManager(mContext);
- }
-
- @After
- public void tearDown() {
- mMockitoSession.finishMocking();
- }
-
- @Test
- public void testGetDefaultAdapter() {
- NfcAdapter nfcAdapter = mNfcManager.getDefaultAdapter();
- assertThat(nfcAdapter).isNotNull();
- }
-}
diff --git a/nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java b/nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java
deleted file mode 100644
index a90a716b6081..000000000000
--- a/nfc/tests/src/android/nfc/NfcRoutingTableEntryTest.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-@RunWith(JUnit4.class)
-public final class NfcRoutingTableEntryTest {
-
- @Test
- public void testAidEntry_GetAid() {
- String expectedAid = "A00000061A02";
- RoutingTableAidEntry entry = new RoutingTableAidEntry(1, expectedAid, 0);
-
- assertEquals(expectedAid, entry.getAid());
- }
-
- @Test
- public void testProtocolEntry_GetProtocol() {
- RoutingTableProtocolEntry entry =
- new RoutingTableProtocolEntry(1, RoutingTableProtocolEntry.PROTOCOL_T1T, 0);
-
- assertEquals(RoutingTableProtocolEntry.PROTOCOL_T1T, entry.getProtocol());
- }
-
- @Test
- public void testSystemCodeEntry_GetSystemCode() {
- byte[] expectedSystemCode = {0x01, 0x02, 0x03};
- RoutingTableSystemCodeEntry entry =
- new RoutingTableSystemCodeEntry(1, expectedSystemCode, 0);
-
- assertArrayEquals(expectedSystemCode, entry.getSystemCode());
- }
-
- @Test
- public void testTechnologyEntry_GetTechnology_A() {
- RoutingTableTechnologyEntry entry =
- new RoutingTableTechnologyEntry(1, RoutingTableTechnologyEntry.TECHNOLOGY_A, 0);
-
- assertEquals(RoutingTableTechnologyEntry.TECHNOLOGY_A, entry.getTechnology());
- }
-}
diff --git a/nfc/tests/src/android/nfc/OemLogItemsTest.java b/nfc/tests/src/android/nfc/OemLogItemsTest.java
deleted file mode 100644
index 21ef80485cc4..000000000000
--- a/nfc/tests/src/android/nfc/OemLogItemsTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * 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.
- * 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.nfc;
-
-import static org.junit.Assert.assertArrayEquals;
-import static org.junit.Assert.assertEquals;
-import static org.mockito.Mockito.mock;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-import java.time.Instant;
-
-@RunWith(JUnit4.class)
-public final class OemLogItemsTest {
-
- @Test
- public void testGetAction() {
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_RF_FIELD_STATE_CHANGED)
- .build();
- assertEquals(OemLogItems.LOG_ACTION_RF_FIELD_STATE_CHANGED, item.getAction());
- }
-
- @Test
- public void testGetEvent() {
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_NFC_TOGGLE)
- .setCallingEvent(OemLogItems.EVENT_ENABLE)
- .build();
- assertEquals(OemLogItems.EVENT_ENABLE, item.getEvent());
- }
-
- @Test
- public void testGetCallingPid() {
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_NFC_TOGGLE)
- .setCallingPid(1234)
- .build();
- assertEquals(1234, item.getCallingPid());
- }
-
- @Test
- public void testGetCommandApdu() {
- byte[] commandApdu = {0x01, 0x02, 0x03};
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_HCE_DATA)
- .setApduCommand(commandApdu)
- .build();
- assertArrayEquals(commandApdu, item.getCommandApdu());
- }
-
- @Test
- public void testGetResponseApdu() {
- byte[] responseApdu = {0x04, 0x05, 0x06};
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_HCE_DATA)
- .setApduResponse(responseApdu)
- .build();
- assertArrayEquals(responseApdu, item.getResponseApdu());
- }
-
- @Test
- public void testGetRfFieldEventTimeMillis() {
- Instant expectedTime = Instant.ofEpochSecond(1688768000, 123456789);
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_RF_FIELD_STATE_CHANGED)
- .setRfFieldOnTime(expectedTime)
- .build();
- assertEquals(expectedTime, item.getRfFieldEventTimeMillis());
- }
-
- @Test
- public void testGetTag() {
- Tag mockTag = mock(Tag.class);
- OemLogItems item = new OemLogItems.Builder(OemLogItems.LOG_ACTION_TAG_DETECTED)
- .setTag(mockTag)
- .build();
- assertEquals(mockTag, item.getTag());
- }
-}
diff --git a/nfc/tests/src/android/nfc/TechListParcelTest.java b/nfc/tests/src/android/nfc/TechListParcelTest.java
deleted file mode 100644
index a12bbbc6884b..000000000000
--- a/nfc/tests/src/android/nfc/TechListParcelTest.java
+++ /dev/null
@@ -1,82 +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 android.nfc;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.util.Arrays;
-
-@RunWith(AndroidJUnit4.class)
-public class TechListParcelTest {
-
- private static final String[] TECH_LIST_1 = new String[] { "tech1.1", "tech1.2" };
- private static final String[] TECH_LIST_2 = new String[] { "tech2.1" };
- private static final String[] TECH_LIST_EMPTY = new String[] {};
-
- @Test
- public void testWriteParcel() {
- TechListParcel techListParcel = new TechListParcel(TECH_LIST_1, TECH_LIST_2);
-
- Parcel parcel = Parcel.obtain();
- techListParcel.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- TechListParcel actualTechList =
- TechListParcel.CREATOR.createFromParcel(parcel);
- parcel.recycle();
-
- assertThat(actualTechList.getTechLists().length).isEqualTo(2);
- assertThat(Arrays.equals(actualTechList.getTechLists()[0], TECH_LIST_1)).isTrue();
- assertThat(Arrays.equals(actualTechList.getTechLists()[1], TECH_LIST_2)).isTrue();
- }
-
- @Test
- public void testWriteParcelArrayEmpty() {
- TechListParcel techListParcel = new TechListParcel();
-
- Parcel parcel = Parcel.obtain();
- techListParcel.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- TechListParcel actualTechList =
- TechListParcel.CREATOR.createFromParcel(parcel);
- parcel.recycle();
-
- assertThat(actualTechList.getTechLists().length).isEqualTo(0);
- }
-
- @Test
- public void testWriteParcelElementEmpty() {
- TechListParcel techListParcel = new TechListParcel(TECH_LIST_EMPTY);
-
- Parcel parcel = Parcel.obtain();
- techListParcel.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- TechListParcel actualTechList =
- TechListParcel.CREATOR.createFromParcel(parcel);
- parcel.recycle();
-
- assertThat(actualTechList.getTechLists().length).isEqualTo(1);
- assertThat(Arrays.equals(actualTechList.getTechLists()[0], TECH_LIST_EMPTY)).isTrue();
- }
-
-}
diff --git a/nfc/tests/src/android/nfc/cardemulation/AidGroupTest.java b/nfc/tests/src/android/nfc/cardemulation/AidGroupTest.java
deleted file mode 100644
index 7e0010247ee7..000000000000
--- a/nfc/tests/src/android/nfc/cardemulation/AidGroupTest.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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.
- * 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.nfc.cardemulation;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.Mockito.atLeastOnce;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-
-import android.os.Parcel;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlSerializer;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class AidGroupTest {
- private AidGroup mAidGroup;
-
- @Before
- public void setUp() {
- List<String> aids = new ArrayList<>();
- aids.add("A0000000031010");
- aids.add("A0000000041010");
- aids.add("A0000000034710");
- aids.add("A000000300");
- mAidGroup = new AidGroup(aids, "payment");
- }
-
- @After
- public void tearDown() {
- }
-
- @Test
- public void testGetCategory() {
- String category = mAidGroup.getCategory();
- assertThat(category).isNotNull();
- assertThat(category).isEqualTo("payment");
- }
-
- @Test
- public void testGetAids() {
- List<String> aids = mAidGroup.getAids();
- assertThat(aids).isNotNull();
- assertThat(aids.size()).isGreaterThan(0);
- assertThat(aids.get(0)).isEqualTo("A0000000031010");
- }
-
- @Test
- public void testWriteAsXml() throws IOException {
- XmlSerializer out = mock(XmlSerializer.class);
- mAidGroup.writeAsXml(out);
- verify(out, atLeastOnce()).startTag(isNull(), anyString());
- verify(out, atLeastOnce()).attribute(isNull(), anyString(), anyString());
- verify(out, atLeastOnce()).endTag(isNull(), anyString());
- }
-
- @Test
- public void testRightToParcel() {
- Parcel parcel = mock(Parcel.class);
- mAidGroup.writeToParcel(parcel, 0);
- verify(parcel).writeString8(anyString());
- verify(parcel).writeInt(anyInt());
- verify(parcel).writeStringList(any());
- }
-}
diff --git a/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java b/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java
deleted file mode 100644
index 48632064621c..000000000000
--- a/nfc/tests/src/android/nfc/cardemulation/CardemulationTest.java
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- * 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.
- * 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.nfc.cardemulation;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.app.role.RoleManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.nfc.Constants;
-import android.nfc.INfcCardEmulation;
-import android.nfc.NfcAdapter;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.provider.Settings;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-
-import com.android.dx.mockito.inline.extended.ExtendedMockito;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.mockito.MockitoSession;
-import org.mockito.quality.Strictness;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@RunWith(AndroidJUnit4.class)
-public class CardemulationTest {
-
- private CardEmulation mCardEmulation;
- @Mock
- private Context mContext;
- @Mock
- private INfcCardEmulation mINfcCardEmulation;
- @Mock
- private NfcAdapter mNfcAdapter;
- @Mock
- private PackageManager mPackageManager;
- private MockitoSession mMockitoSession;
-
- @Before
- public void setUp() {
- mMockitoSession = ExtendedMockito.mockitoSession()
- .mockStatic(NfcAdapter.class)
- .mockStatic(Settings.Secure.class)
- .strictness(Strictness.LENIENT)
- .startMocking();
- MockitoAnnotations.initMocks(this);
-
- when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION))
- .thenReturn(true);
- when(mContext.getApplicationContext()).thenReturn(mContext);
- when(mContext.getPackageManager()).thenReturn(mPackageManager);
- assertThat(mNfcAdapter).isNotNull();
- when(mNfcAdapter.getCardEmulationService()).thenReturn(mINfcCardEmulation);
- when(mNfcAdapter.getContext()).thenReturn(mContext);
- mCardEmulation = CardEmulation.getInstance(mNfcAdapter);
- }
-
- @After
- public void tearDown() {
- mMockitoSession.finishMocking();
- }
-
- @Test
- public void testIsDefaultServiceForCategory() throws RemoteException {
- ComponentName componentName = mock(ComponentName.class);
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- when(mINfcCardEmulation.isDefaultServiceForCategory(1, componentName,
- "payment")).thenReturn(true);
- boolean result = mCardEmulation.isDefaultServiceForCategory(componentName,
- "payment");
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).isDefaultServiceForCategory(1, componentName,
- "payment");
-
- }
-
- @Test
- public void testIsDefaultServiceForAid() throws RemoteException {
- ComponentName componentName = mock(ComponentName.class);
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- when(mINfcCardEmulation.isDefaultServiceForAid(1, componentName,
- "payment")).thenReturn(true);
- boolean result = mCardEmulation.isDefaultServiceForAid(componentName,
- "payment");
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).isDefaultServiceForAid(1, componentName,
- "payment");
- }
-
- @Test
- public void testCategoryAllowsForegroundPreference() throws Settings.SettingNotFoundException {
- when(mContext.createContextAsUser(any(), anyInt())).thenReturn(mContext);
- RoleManager roleManager = mock(RoleManager.class);
- when(roleManager.isRoleAvailable(RoleManager.ROLE_WALLET)).thenReturn(false);
- when(mContext.getSystemService(RoleManager.class)).thenReturn(roleManager);
- ContentResolver contentResolver = mock(ContentResolver.class);
- when(mContext.getContentResolver()).thenReturn(contentResolver);
- when(Settings.Secure.getInt(contentResolver, Constants
- .SETTINGS_SECURE_NFC_PAYMENT_FOREGROUND)).thenReturn(1);
- boolean result = mCardEmulation.categoryAllowsForegroundPreference("payment");
- assertThat(result).isTrue();
- }
-
- @Test
- public void testGetSelectionModeForCategory() throws RemoteException {
- when(mINfcCardEmulation.isDefaultPaymentRegistered()).thenReturn(true);
- int result = mCardEmulation.getSelectionModeForCategory("payment");
- assertThat(result).isEqualTo(0);
- }
-
- @Test
- public void testSetShouldDefaultToObserveModeForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.setShouldDefaultToObserveModeForService(1, componentName, true))
- .thenReturn(true);
- boolean result = mCardEmulation
- .setShouldDefaultToObserveModeForService(componentName, true);
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).setShouldDefaultToObserveModeForService(1, componentName, true);
- }
-
- @Test
- public void testRegisterPollingLoopFilterForService()throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.registerPollingLoopFilterForService(anyInt(),
- any(), anyString(), anyBoolean())).thenReturn(true);
- boolean result = mCardEmulation.registerPollingLoopFilterForService(componentName,
- "A0000000041010", true);
- assertThat(result).isTrue();
- verify(mINfcCardEmulation)
- .registerPollingLoopFilterForService(anyInt(), any(), anyString(), anyBoolean());
- }
-
- @Test
- public void testRemovePollingLoopFilterForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.removePollingLoopFilterForService(anyInt(), any(), anyString()))
- .thenReturn(true);
- boolean result = mCardEmulation
- .removePollingLoopFilterForService(componentName, "A0000000041010");
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).removePollingLoopFilterForService(anyInt(), any(), anyString());
- }
-
- @Test
- public void testRegisterPollingLoopPatternFilterForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.registerPollingLoopPatternFilterForService(anyInt(), any(),
- anyString(), anyBoolean())).thenReturn(true);
- boolean result = mCardEmulation.registerPollingLoopPatternFilterForService(componentName,
- "A0000000041010", true);
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).registerPollingLoopPatternFilterForService(anyInt(), any(),
- anyString(), anyBoolean());
- }
-
- @Test
- public void testRemovePollingLoopPatternFilterForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.removePollingLoopPatternFilterForService(anyInt(), any(),
- anyString())).thenReturn(true);
- boolean result = mCardEmulation.removePollingLoopPatternFilterForService(componentName,
- "A0000000041010");
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).removePollingLoopPatternFilterForService(anyInt(), any(),
- anyString());
- }
-
- @Test
- public void testRegisterAidsForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.registerAidGroupForService(anyInt(), any(),
- any())).thenReturn(true);
- List<String> aids = new ArrayList<>();
- aids.add("A0000000041010");
- boolean result = mCardEmulation.registerAidsForService(componentName, "payment",
- aids);
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).registerAidGroupForService(anyInt(), any(),
- any());
- }
-
- @Test
- public void testUnsetOffHostForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.unsetOffHostForService(1, componentName)).thenReturn(true);
- boolean result = mCardEmulation.unsetOffHostForService(componentName);
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).unsetOffHostForService(1, componentName);
- }
-
- @Test
- public void testSetOffHostForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- when(NfcAdapter.getDefaultAdapter(any())).thenReturn(mNfcAdapter);
- List<String> elements = new ArrayList<>();
- elements.add("eSE");
- when(mNfcAdapter.getSupportedOffHostSecureElements()).thenReturn(elements);
- ComponentName componentName = mock(ComponentName.class);
- when(mINfcCardEmulation.setOffHostForService(anyInt(), any(), anyString()))
- .thenReturn(true);
- boolean result = mCardEmulation.setOffHostForService(componentName,
- "eSE");
- assertThat(result).isTrue();
- verify(mINfcCardEmulation).setOffHostForService(anyInt(), any(), anyString());
- }
-
- @Test
- public void testGetAidsForService() throws RemoteException {
- UserHandle userHandle = mock(UserHandle.class);
- when(userHandle.getIdentifier()).thenReturn(1);
- when(mContext.getUser()).thenReturn(userHandle);
- ComponentName componentName = mock(ComponentName.class);
- List<String> elements = new ArrayList<>();
- elements.add("eSE");
- AidGroup aidGroup = mock(AidGroup.class);
- when(aidGroup.getAids()).thenReturn(elements);
- when(mINfcCardEmulation.getAidGroupForService(1, componentName, "payment"))
- .thenReturn(aidGroup);
- List<String> result = mCardEmulation.getAidsForService(componentName, "payment");
- assertThat(result).isNotNull();
- assertThat(result.size()).isGreaterThan(0);
- verify(mINfcCardEmulation).getAidGroupForService(1, componentName, "payment");
- }
-}
diff --git a/nfc/tests/src/android/nfc/dta/NfcDtaTest.java b/nfc/tests/src/android/nfc/dta/NfcDtaTest.java
deleted file mode 100644
index 38fb7ef311b5..000000000000
--- a/nfc/tests/src/android/nfc/dta/NfcDtaTest.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc.dta;
-
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doThrow;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.nfc.INfcDta;
-import android.nfc.NfcAdapter;
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class NfcDtaTest {
- private final String mServiceName = "serviceName";
- private final int mServiceSap = 1;
- private final int mMiu = 1;
- private final int mRwSize = 1;
- private final int mTestCaseId = 1;
- @Mock
- private NfcAdapter mMockNfcAdapter;
- @Mock
- private INfcDta mMockService;
- @Mock
- private Context mMockContext;
-
- private NfcDta mNfcDta;
-
- @Before
- public void setup() {
- MockitoAnnotations.initMocks(this);
- when(mMockNfcAdapter.getContext()).thenReturn(mMockContext);
- when(mMockNfcAdapter.getNfcDtaInterface()).thenReturn(mMockService);
-
- mNfcDta = NfcDta.getInstance(mMockNfcAdapter);
- }
-
- @Test
- public void testEnableData() throws RemoteException {
- assertTrue(mNfcDta.enableDta());
- verify(mMockService).enableDta();
- }
-
- @Test
- public void testEnableDataWithRemoteException() throws RemoteException {
- doThrow(new RemoteException()).when(mMockService).enableDta();
-
- assertFalse(mNfcDta.enableDta());
- verify(mMockService).enableDta();
- }
-
- @Test
- public void testDisableData() throws RemoteException {
- assertTrue(mNfcDta.disableDta());
- verify(mMockService).disableDta();
- }
-
- @Test
- public void testDisableDataWithRemoteException() throws RemoteException {
- doThrow(new RemoteException()).when(mMockService).disableDta();
-
- assertFalse(mNfcDta.disableDta());
- verify(mMockService).disableDta();
- }
-
- @Test
- public void testEnableServer() throws RemoteException {
- when(mMockService.enableServer(mServiceName, mServiceSap, mMiu, mRwSize,
- mTestCaseId)).thenReturn(true);
-
- mNfcDta.enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId);
- verify(mMockService).enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId);
- }
-
- @Test
- public void testEnableServerWithRemoteException() throws RemoteException {
- doThrow(new RemoteException()).when(mMockService).enableServer(mServiceName, mServiceSap,
- mMiu,
- mRwSize, mTestCaseId);
-
- mNfcDta.enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId);
- verify(mMockService).enableServer(mServiceName, mServiceSap, mMiu, mRwSize, mTestCaseId);
- }
-
- @Test
- public void testDisableServer() throws RemoteException {
- assertTrue(mNfcDta.disableServer());
- verify(mMockService).disableServer();
- }
-
- @Test
- public void testDisableServerWithRemoteException() throws RemoteException {
- doThrow(new RemoteException()).when(mMockService).disableServer();
-
- assertFalse(mNfcDta.disableServer());
- verify(mMockService).disableServer();
- }
-
- @Test
- public void testEnableClient() throws RemoteException {
- when(mMockService.enableClient(mServiceName, mMiu, mRwSize, mTestCaseId)).thenReturn(true);
-
- mNfcDta.enableClient(mServiceName, mMiu, mRwSize, mTestCaseId);
- verify(mMockService).enableClient(mServiceName, mMiu, mRwSize, mTestCaseId);
- }
-
- @Test
- public void testEnableClientWithRemoteException() throws RemoteException {
- doThrow(new RemoteException()).when(mMockService).enableClient(mServiceName, mMiu, mRwSize,
- mTestCaseId);
-
- mNfcDta.enableClient(mServiceName, mMiu, mRwSize, mTestCaseId);
- verify(mMockService).enableClient(mServiceName, mMiu, mRwSize, mTestCaseId);
- }
-
- @Test
- public void testDisableClient() throws RemoteException {
- assertTrue(mNfcDta.disableClient());
- verify(mMockService).disableClient();
- }
-
- @Test
- public void testDisableClientWithRemoteException() throws RemoteException {
- doThrow(new RemoteException()).when(mMockService).disableClient();
-
- assertFalse(mNfcDta.disableClient());
- verify(mMockService).disableClient();
- }
-
- @Test
- public void testRegisterMessageService() throws RemoteException {
- String msgServiceName = "sampleServiceName";
- when(mMockService.registerMessageService(msgServiceName)).thenReturn(true);
-
- mNfcDta.registerMessageService(msgServiceName);
- verify(mMockService).registerMessageService(msgServiceName);
- }
-
- @Test
- public void testRegisterMessageServiceWithRemoteException() throws RemoteException {
- String msgServiceName = "sampleServiceName";
- doThrow(new RemoteException()).when(mMockService).registerMessageService(msgServiceName);
-
- assertFalse(mNfcDta.registerMessageService(msgServiceName));
- }
-
- @Test(expected = NullPointerException.class)
- public void testGetInstanceWithNullPointerException() {
- NfcDta.getInstance(null);
- }
-
- @Test(expected = UnsupportedOperationException.class)
- public void testGetInstanceWithUnsupportedOperationExceptionForNfcAdapterContext() {
- when(mMockNfcAdapter.getContext()).thenReturn(null);
-
- NfcDta.getInstance(mMockNfcAdapter);
- }
-}
diff --git a/nfc/tests/src/android/nfc/tech/NfcATest.java b/nfc/tests/src/android/nfc/tech/NfcATest.java
deleted file mode 100644
index 40076ebd0a0a..000000000000
--- a/nfc/tests/src/android/nfc/tech/NfcATest.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.
- * 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.nfc.tech;
-
-import static android.nfc.tech.NfcA.EXTRA_ATQA;
-import static android.nfc.tech.NfcA.EXTRA_SAK;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.fail;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import android.nfc.ErrorCodes;
-import android.nfc.INfcTag;
-import android.nfc.Tag;
-import android.nfc.TransceiveResult;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-
-public class NfcATest {
- @Mock
- private Tag mMockTag;
- @Mock
- private INfcTag mMockTagService;
- @Mock
- private Bundle mMockBundle;
- private NfcA mNfcA;
- private final byte[] mSampleArray = new byte[] {1, 2, 3};
-
- @Before
- public void setUp() throws RemoteException {
- MockitoAnnotations.initMocks(this);
- when(mMockBundle.getShort(EXTRA_SAK)).thenReturn((short) 1);
- when(mMockBundle.getByteArray(EXTRA_ATQA)).thenReturn(mSampleArray);
- when(mMockTag.getTechExtras(TagTechnology.NFC_A)).thenReturn(mMockBundle);
-
- mNfcA = new NfcA(mMockTag);
- }
-
- @Test
- public void testGetNfcAWithTech() {
- Tag mockTag = mock(Tag.class);
- when(mockTag.getTechExtras(TagTechnology.NFC_A)).thenReturn(mMockBundle);
- when(mockTag.hasTech(TagTechnology.NFC_A)).thenReturn(true);
-
- assertNotNull(NfcA.get(mockTag));
- verify(mockTag).getTechExtras(TagTechnology.NFC_A);
- verify(mockTag).hasTech(TagTechnology.NFC_A);
- }
-
- @Test
- public void testGetNfcAWithoutTech() {
- when(mMockTag.hasTech(TagTechnology.NFC_A)).thenReturn(false);
- assertNull(NfcA.get(mMockTag));
- }
-
- @Test
- public void testGetAtga() {
- assertNotNull(mNfcA.getAtqa());
- }
-
- @Test
- public void testGetSak() {
- assertEquals((short) 1, mNfcA.getSak());
- }
-
- @Test
- public void testTransceive() throws IOException, RemoteException {
- TransceiveResult mockTransceiveResult = mock(TransceiveResult.class);
- when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_A);
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTag.getServiceHandle()).thenReturn(1);
- when(mMockTagService.transceive(1, mSampleArray, true))
- .thenReturn(mockTransceiveResult);
- when(mockTransceiveResult.getResponseOrThrow()).thenReturn(mSampleArray);
-
- mNfcA.transceive(mSampleArray);
- verify(mMockTag).getTagService();
- verify(mMockTag).getServiceHandle();
- }
-
- @Test
- public void testGetMaxTransceiveLength() throws RemoteException {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_A)).thenReturn(1);
-
- mNfcA.getMaxTransceiveLength();
- verify(mMockTag).getTagService();
- }
-
- @Test
- public void testSetTimeout() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.setTimeout(TagTechnology.NFC_A, 1000)).thenReturn(
- ErrorCodes.SUCCESS);
-
- mNfcA.setTimeout(1000);
- verify(mMockTag).getTagService();
- verify(mMockTagService).setTimeout(TagTechnology.NFC_A, 1000);
- } catch (Exception e) {
- fail("Unexpected exception during valid setTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testSetTimeoutInvalidTimeout() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.setTimeout(TagTechnology.NFC_A, -1)).thenReturn(
- ErrorCodes.ERROR_TIMEOUT);
-
- assertThrows(IllegalArgumentException.class, () -> mNfcA.setTimeout(-1));
- } catch (Exception e) {
- fail("Unexpected exception during invalid setTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testSetTimeoutRemoteException() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.setTimeout(TagTechnology.NFC_A, 1000)).thenThrow(
- new RemoteException());
-
- mNfcA.setTimeout(1000); // Should not throw an exception but log it
- verify(mMockTag).getTagService();
- verify(mMockTagService).setTimeout(TagTechnology.NFC_A, 1000);
- } catch (Exception e) {
- fail("Unexpected exception during RemoteException in setTimeout: " + e.getMessage());
- }
-
- }
-
- @Test
- public void testGetTimeout() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.getTimeout(TagTechnology.NFC_A)).thenReturn(2000);
-
- assertEquals(2000, mNfcA.getTimeout());
- verify(mMockTag).getTagService();
- verify(mMockTagService).getTimeout(TagTechnology.NFC_A);
- } catch (Exception e) {
- fail("Unexpected exception during valid getTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testGetTimeoutRemoteException() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.getTimeout(TagTechnology.NFC_A)).thenThrow(new RemoteException());
-
- assertEquals(0, mNfcA.getTimeout());
- } catch (Exception e) {
- fail("Unexpected exception during RemoteException in getTimeout: " + e.getMessage());
- }
- }
-}
diff --git a/nfc/tests/src/android/nfc/tech/NfcBTest.java b/nfc/tests/src/android/nfc/tech/NfcBTest.java
deleted file mode 100644
index 98d6070e760c..000000000000
--- a/nfc/tests/src/android/nfc/tech/NfcBTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.
- * 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.nfc.tech;
-
-import static android.nfc.tech.NfcB.EXTRA_APPDATA;
-import static android.nfc.tech.NfcB.EXTRA_PROTINFO;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-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.nfc.INfcTag;
-import android.nfc.Tag;
-import android.nfc.TransceiveResult;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-
-public class NfcBTest {
- private final byte[] mSampleAppDate = new byte[] {1, 2, 3};
- private final byte[] mSampleProtInfo = new byte[] {3, 2, 1};
- @Mock
- private Tag mMockTag;
- @Mock
- private Bundle mMockBundle;
- @Mock
- private INfcTag mMockTagService;
- private NfcB mNfcB;
-
- @Before
- public void setUp() throws RemoteException {
- MockitoAnnotations.initMocks(this);
- when(mMockBundle.getByteArray(EXTRA_APPDATA)).thenReturn(mSampleAppDate);
- when(mMockBundle.getByteArray(EXTRA_PROTINFO)).thenReturn(mSampleProtInfo);
- when(mMockTag.getTechExtras(TagTechnology.NFC_B)).thenReturn(mMockBundle);
-
- mNfcB = new NfcB(mMockTag);
- }
-
- @Test
- public void testGetApplicationData() {
- assertNotNull(mNfcB.getApplicationData());
- }
-
- @Test
- public void testGetProtocolInfo() {
- assertNotNull(mNfcB.getProtocolInfo());
- }
-
- @Test
- public void testGetNfcBInstance() {
- Tag tag = mock(Tag.class);
- when(tag.hasTech(TagTechnology.NFC_B)).thenReturn(true);
- when(tag.getTechExtras(TagTechnology.NFC_B)).thenReturn(mMockBundle);
-
- assertNotNull(NfcB.get(tag));
- verify(tag).hasTech(TagTechnology.NFC_B);
- verify(tag).getTechExtras(TagTechnology.NFC_B);
- }
-
- @Test
- public void testGetNfcBNullInstance() {
- Tag tag = mock(Tag.class);
- when(tag.hasTech(TagTechnology.NFC_B)).thenReturn(false);
-
- assertNull(NfcB.get(tag));
- verify(tag).hasTech(TagTechnology.NFC_B);
- verify(tag, never()).getTechExtras(TagTechnology.NFC_B);
- }
-
-
- @Test
- public void testTransceive() throws IOException, RemoteException {
- byte[] sampleData = new byte[] {1, 2, 3, 4, 5};
- TransceiveResult mockTransceiveResult = mock(TransceiveResult.class);
- when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_B);
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTag.getServiceHandle()).thenReturn(1);
- when(mMockTagService.transceive(1, sampleData, true))
- .thenReturn(mockTransceiveResult);
- when(mockTransceiveResult.getResponseOrThrow()).thenReturn(sampleData);
-
- mNfcB.transceive(sampleData);
- verify(mMockTag).getTagService();
- verify(mMockTag).getServiceHandle();
- }
-
- @Test
- public void testGetMaxTransceiveLength() throws RemoteException {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_B)).thenReturn(1);
-
- mNfcB.getMaxTransceiveLength();
- verify(mMockTag).getTagService();
- }
-}
diff --git a/nfc/tests/src/android/nfc/tech/NfcBarcodeTest.java b/nfc/tests/src/android/nfc/tech/NfcBarcodeTest.java
deleted file mode 100644
index 3aa4e2c13895..000000000000
--- a/nfc/tests/src/android/nfc/tech/NfcBarcodeTest.java
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright (C) 2012 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.nfc.tech;
-
-import static android.nfc.tech.NfcBarcode.EXTRA_BARCODE_TYPE;
-import static android.nfc.tech.NfcBarcode.TYPE_KOVIO;
-import static android.nfc.tech.NfcBarcode.TYPE_UNKNOWN;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-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.nfc.Tag;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-public class NfcBarcodeTest {
- @Mock
- private Tag mMockTag;
- @Mock
- private Bundle mMockBundle;
- private NfcBarcode mNfcBarcode;
-
- @Before
- public void setUp() throws RemoteException {
- MockitoAnnotations.initMocks(this);
- when(mMockBundle.getInt(EXTRA_BARCODE_TYPE)).thenReturn(TYPE_KOVIO);
- when(mMockTag.getTechExtras(TagTechnology.NFC_BARCODE)).thenReturn(mMockBundle);
-
- mNfcBarcode = new NfcBarcode(mMockTag);
- }
-
- @Test
- public void testGetNfcBarcodeInstance() {
- Tag mockTag = mock(Tag.class);
- when(mockTag.hasTech(TagTechnology.NFC_BARCODE)).thenReturn(true);
- when(mockTag.getTechExtras(TagTechnology.NFC_BARCODE)).thenReturn(mMockBundle);
-
- assertNotNull(NfcBarcode.get(mockTag));
- verify(mockTag).hasTech(TagTechnology.NFC_BARCODE);
- verify(mockTag).getTechExtras(TagTechnology.NFC_BARCODE);
- }
-
- @Test(expected = NullPointerException.class)
- public void testGetNfcBarcodeInstanceWithException() {
- Tag mockTag = mock(Tag.class);
- when(mockTag.hasTech(TagTechnology.NFC_BARCODE)).thenReturn(true);
- when(mockTag.getTechExtras(TagTechnology.NFC_BARCODE)).thenReturn(null);
-
- assertNull(NfcBarcode.get(mockTag));
- verify(mockTag).hasTech(TagTechnology.NFC_BARCODE);
- verify(mockTag).getTechExtras(TagTechnology.NFC_BARCODE);
- }
-
- @Test
- public void testGetNfcBarcodeWithoutTech() {
- when(mMockTag.hasTech(TagTechnology.NFC_BARCODE)).thenReturn(false);
-
- assertNull(NfcBarcode.get(mMockTag));
- }
-
- @Test
- public void testGetType() {
- int result = mNfcBarcode.getType();
- assertEquals(TYPE_KOVIO, result);
- }
-
- @Test
- public void testGetBarcodeWithTypeKovio() {
- byte[] sampleId = "sampleId".getBytes();
- when(mMockTag.getId()).thenReturn(sampleId);
-
- assertEquals(sampleId, mNfcBarcode.getBarcode());
- verify(mMockTag).getId();
- }
-
- @Test
- public void testGetBarCodeTypeUnknown() throws RemoteException {
- when(mMockBundle.getInt(EXTRA_BARCODE_TYPE)).thenReturn(TYPE_UNKNOWN);
- when(mMockTag.getTechExtras(TagTechnology.NFC_BARCODE)).thenReturn(mMockBundle);
- mNfcBarcode = new NfcBarcode(mMockTag);
-
- assertNull(mNfcBarcode.getBarcode());
- verify(mMockTag, never()).getId();
- }
-}
diff --git a/nfc/tests/src/android/nfc/tech/NfcFTest.java b/nfc/tests/src/android/nfc/tech/NfcFTest.java
deleted file mode 100644
index 31a6943566e0..000000000000
--- a/nfc/tests/src/android/nfc/tech/NfcFTest.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import static android.nfc.tech.NfcF.EXTRA_PMM;
-import static android.nfc.tech.NfcF.EXTRA_SC;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertThrows;
-import static org.junit.Assert.fail;
-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.nfc.ErrorCodes;
-import android.nfc.INfcTag;
-import android.nfc.Tag;
-import android.nfc.TransceiveResult;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-
-public class NfcFTest {
- private final byte[] mSampleSystemCode = new byte[] {1, 2, 3};
- private final byte[] mSampleManufacturer = new byte[] {3, 2, 1};
- @Mock
- private Tag mMockTag;
- @Mock
- private INfcTag mMockTagService;
- @Mock
- private Bundle mMockBundle;
- private NfcF mNfcF;
-
- @Before
- public void setUp() throws RemoteException {
- MockitoAnnotations.initMocks(this);
- when(mMockBundle.getByteArray(EXTRA_SC)).thenReturn(mSampleSystemCode);
- when(mMockBundle.getByteArray(EXTRA_PMM)).thenReturn(mSampleManufacturer);
- when(mMockTag.getTechExtras(TagTechnology.NFC_F)).thenReturn(mMockBundle);
-
- mNfcF = new NfcF(mMockTag);
- }
-
- @Test
- public void testGetSystemCode() {
- assertNotNull(mNfcF.getSystemCode());
- }
-
- @Test
- public void testGetManufacturer() {
- assertNotNull(mNfcF.getManufacturer());
- }
-
- @Test
- public void testGetNfcFInstanceWithTech() {
- Tag tag = mock(Tag.class);
- when(tag.getTechExtras(TagTechnology.NFC_F)).thenReturn(mMockBundle);
- when(tag.hasTech(TagTechnology.NFC_F)).thenReturn(true);
-
- assertNotNull(NfcF.get(tag));
- verify(tag).getTechExtras(TagTechnology.NFC_F);
- verify(tag).hasTech(TagTechnology.NFC_F);
- }
-
- @Test
- public void testGetNfcFInstanceWithoutTech() {
- Tag tag = mock(Tag.class);
- when(tag.hasTech(TagTechnology.NFC_F)).thenReturn(false);
-
- assertNull(NfcF.get(tag));
- verify(tag).hasTech(TagTechnology.NFC_F);
- verify(tag, never()).getTechExtras(TagTechnology.NFC_F);
- }
-
- @Test
- public void testTransceive() throws IOException, RemoteException {
- byte[] sampleData = new byte[]{1, 2, 3, 4, 5};
- TransceiveResult mockTransceiveResult = mock(TransceiveResult.class);
- when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_F);
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTag.getServiceHandle()).thenReturn(1);
- when(mMockTagService.transceive(1, sampleData, true))
- .thenReturn(mockTransceiveResult);
- when(mockTransceiveResult.getResponseOrThrow()).thenReturn(sampleData);
-
- mNfcF.transceive(sampleData);
- verify(mMockTag).getTagService();
- verify(mMockTag).getServiceHandle();
- }
-
- @Test
- public void testGetMaxTransceiveLength() throws RemoteException {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_F)).thenReturn(1);
-
- mNfcF.getMaxTransceiveLength();
- verify(mMockTag).getTagService();
- }
-
- @Test
- public void testGetTimeout() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.getTimeout(TagTechnology.NFC_F)).thenReturn(2000);
-
- assertEquals(2000, mNfcF.getTimeout());
- verify(mMockTag).getTagService();
- verify(mMockTagService).getTimeout(TagTechnology.NFC_F);
- } catch (Exception e) {
- fail("Unexpected exception during valid getTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testGetTimeoutRemoteException() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.getTimeout(TagTechnology.NFC_F)).thenThrow(new RemoteException());
-
- assertEquals(0, mNfcF.getTimeout());
- } catch (Exception e) {
- fail("Unexpected exception during RemoteException in getTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testSetTimeout() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.setTimeout(TagTechnology.NFC_F, 1000)).thenReturn(
- ErrorCodes.SUCCESS);
-
- mNfcF.setTimeout(1000);
- verify(mMockTag).getTagService();
- verify(mMockTagService).setTimeout(TagTechnology.NFC_F, 1000);
- } catch (Exception e) {
- fail("Unexpected exception during valid setTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testSetTimeoutInvalidTimeout() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.setTimeout(TagTechnology.NFC_F, -1)).thenReturn(
- ErrorCodes.ERROR_TIMEOUT);
-
- assertThrows(IllegalArgumentException.class, () -> mNfcF.setTimeout(-1));
- } catch (Exception e) {
- fail("Unexpected exception during invalid setTimeout: " + e.getMessage());
- }
- }
-
- @Test
- public void testSetTimeoutRemoteException() {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- try {
- when(mMockTagService.setTimeout(TagTechnology.NFC_F, 1000)).thenThrow(
- new RemoteException());
-
- mNfcF.setTimeout(1000);
- verify(mMockTag).getTagService();
- verify(mMockTagService).setTimeout(TagTechnology.NFC_F, 1000);
- } catch (Exception e) {
- fail("Unexpected exception during RemoteException in setTimeout: " + e.getMessage());
- }
- }
-}
diff --git a/nfc/tests/src/android/nfc/tech/NfcVTest.java b/nfc/tests/src/android/nfc/tech/NfcVTest.java
deleted file mode 100644
index 6a99921b9287..000000000000
--- a/nfc/tests/src/android/nfc/tech/NfcVTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2010 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.nfc.tech;
-
-import static android.nfc.tech.NfcV.EXTRA_DSFID;
-import static android.nfc.tech.NfcV.EXTRA_RESP_FLAGS;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-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.nfc.INfcTag;
-import android.nfc.Tag;
-import android.nfc.TransceiveResult;
-import android.os.Bundle;
-import android.os.RemoteException;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.IOException;
-
-public class NfcVTest {
- private final byte mSampleRespFlags = (byte) 1;
- private final byte mSampleDsfId = (byte) 2;
- @Mock
- private Tag mMockTag;
- @Mock
- private INfcTag mMockTagService;
- @Mock
- private Bundle mMockBundle;
- private NfcV mNfcV;
-
- @Before
- public void setUp() throws RemoteException {
- MockitoAnnotations.initMocks(this);
- when(mMockBundle.getByte(EXTRA_RESP_FLAGS)).thenReturn(mSampleRespFlags);
- when(mMockBundle.getByte(EXTRA_DSFID)).thenReturn(mSampleDsfId);
- when(mMockTag.getTechExtras(TagTechnology.NFC_V)).thenReturn(mMockBundle);
-
- mNfcV = new NfcV(mMockTag);
- }
-
- @Test
- public void testGetResponseFlag() {
- assertEquals(mSampleRespFlags, mNfcV.getResponseFlags());
- }
-
- @Test
- public void testGetDsfId() {
- assertEquals(mSampleDsfId, mNfcV.getDsfId());
- }
-
- @Test
- public void testGetNfcVInstance() {
- Tag tag = mock(Tag.class);
- when(tag.hasTech(TagTechnology.NFC_V)).thenReturn(true);
- when(tag.getTechExtras(TagTechnology.NFC_V)).thenReturn(mMockBundle);
-
- assertNotNull(NfcV.get(tag));
- verify(tag).getTechExtras(TagTechnology.NFC_V);
- verify(tag).hasTech(TagTechnology.NFC_V);
- }
-
- @Test
- public void testGetNfcVNullInstance() {
- Tag tag = mock(Tag.class);
- when(tag.hasTech(TagTechnology.NFC_V)).thenReturn(false);
-
- assertNull(NfcV.get(tag));
- verify(tag, never()).getTechExtras(TagTechnology.NFC_V);
- verify(tag).hasTech(TagTechnology.NFC_V);
- }
-
- @Test
- public void testTransceive() throws IOException, RemoteException {
- byte[] sampleData = new byte[] {1, 2, 3, 4, 5};
- TransceiveResult mockTransceiveResult = mock(TransceiveResult.class);
- when(mMockTag.getConnectedTechnology()).thenReturn(TagTechnology.NFC_V);
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTag.getServiceHandle()).thenReturn(1);
- when(mMockTagService.transceive(1, sampleData, true))
- .thenReturn(mockTransceiveResult);
- when(mockTransceiveResult.getResponseOrThrow()).thenReturn(sampleData);
-
- mNfcV.transceive(sampleData);
- verify(mMockTag).getTagService();
- verify(mMockTag).getServiceHandle();
- }
-
- @Test
- public void testGetMaxTransceiveLength() throws RemoteException {
- when(mMockTag.getTagService()).thenReturn(mMockTagService);
- when(mMockTagService.getMaxTransceiveLength(TagTechnology.NFC_V)).thenReturn(1);
-
- mNfcV.getMaxTransceiveLength();
- verify(mMockTag).getTagService();
- }
-}
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ActionButton.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ActionButton.kt
index 04a2c07da388..b88fda77144f 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ActionButton.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/ActionButton.kt
@@ -65,8 +65,8 @@ fun ToggleVisibilityButton(modifier: Modifier = Modifier, onToggle: (Boolean) ->
imageVector = if (toggleState.value)
Icons.Outlined.Visibility else Icons.Outlined.VisibilityOff,
contentDescription = if (toggleState.value)
- stringResource(R.string.content_description_show_password) else
- stringResource(R.string.content_description_hide_password),
+ stringResource(R.string.content_description_hide_password) else
+ stringResource(R.string.content_description_show_password),
tint = MaterialTheme.colorScheme.onSurfaceVariant,
)
}
diff --git a/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/PreferenceBindingTestUtils.kt b/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/PreferenceBindingTestUtils.kt
index 00bad5203f07..220614bf064f 100644
--- a/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/PreferenceBindingTestUtils.kt
+++ b/packages/SettingsLib/Preference/testutils/com/android/settingslib/preference/PreferenceBindingTestUtils.kt
@@ -19,18 +19,27 @@ package com.android.settingslib.preference
import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.preference.Preference
+import androidx.preference.PreferenceScreen
import com.android.settingslib.metadata.PersistentPreference
import com.android.settingslib.metadata.PreferenceMetadata
/** Creates [Preference] widget and binds with metadata. */
+@Suppress("UNCHECKED_CAST")
@VisibleForTesting
-fun <P : Preference> PreferenceMetadata.createAndBindWidget(context: Context): P {
+fun <P : Preference> PreferenceMetadata.createAndBindWidget(
+ context: Context,
+ preferenceScreen: PreferenceScreen? = null,
+): P {
val binding = PreferenceBindingFactory.defaultFactory.getPreferenceBinding(this)!!
return (binding.createWidget(context) as P).also {
if (this is PersistentPreference<*>) {
- storage(context)?.let { keyValueStore ->
+ storage(context).let { keyValueStore ->
it.preferenceDataStore = PreferenceDataStoreAdapter(keyValueStore)
}
+ // Attach preference to preference screen, otherwise `Preference.performClick` does not
+ // interact with underlying datastore
+ (preferenceScreen ?: PreferenceScreenFactory(context).getOrCreatePreferenceScreen())
+ .addPreference(it)
}
binding.bind(it, this)
}
diff --git a/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outline_color_selector.xml b/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outline_color_selector.xml
new file mode 100644
index 000000000000..5084f11afa51
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outline_color_selector.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_checked="true" android:color="@android:color/transparent"/>
+ <item android:color="?attr/colorOutlineVariant"/>
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outlined_background_color_selector.xml b/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outlined_background_color_selector.xml
new file mode 100644
index 000000000000..ed05cdd1c96d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_button_outlined_background_color_selector.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false" android:state_checked="true"
+ android:alpha="0.12"
+ android:color="?attr/colorOnSurface"/>
+ <item android:state_checked="true" android:color="?attr/colorContainerChecked"/>
+ <item android:state_checkable="true" android:color="?attr/colorContainerUnchecked"/>
+ <item android:color="?attr/colorContainer" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_filled_button_color.xml b/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_filled_button_color.xml
new file mode 100644
index 000000000000..678bec4f3cba
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/color/settingslib_expressive_filled_button_color.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_enabled="false"
+ android:alpha="0.12" android:color="@color/settingslib_materialColorOnSurface"/>
+ <item android:state_checked="true" android:color="@color/settingslib_materialColorPrimary"/>
+ <item android:state_checkable="true" android:color="@color/settingslib_materialColorSurfaceContainer"/>
+ <item android:color="@color/settingslib_materialColorPrimary" />
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml
index 2261e58a961e..2776544e2948 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v35/settingslib_expressive_collapsable_textview.xml
@@ -57,6 +57,7 @@
android:id="@+id/collapse_button"
app:layout_constraintTop_toBottomOf="@id/settingslib_expressive_learn_more"
app:layout_constraintStart_toStartOf="parent"
+ android:textColor="@color/settingslib_materialColorOnSurface"
android:text="@string/settingslib_expressive_text_expand"
app:icon="@drawable/settingslib_expressive_icon_expand"
style="@style/SettingslibTextButtonStyle.Expressive"/>
diff --git a/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml
index 9d3d70b366aa..b5f22b73cecd 100644
--- a/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml
+++ b/packages/SettingsLib/SettingsTheme/res/values-v31/styles_expressive.xml
@@ -17,27 +17,16 @@
<resources>
<style name="SettingsLibButtonStyle.Expressive.Filled"
- parent="@style/Widget.Material3.Button">
+ parent="@style/Widget.Material3Expressive.Button.Icon">
<item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center</item>
- <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item>
- <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item>
- <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item>
- <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item>
- <item name="android:backgroundTint">@color/settingslib_materialColorPrimary</item>
<item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item>
- <item name="android:textColor">@color/settingslib_materialColorOnPrimary</item>
- <item name="iconGravity">textStart</item>
- <item name="iconTint">@color/settingslib_materialColorOnPrimary</item>
- <item name="iconSize">@dimen/settingslib_expressive_space_small4</item>
</style>
<style name="SettingsLibButtonStyle.Expressive.Filled.Large">
- <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item>
- <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item>
- <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item>
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium</item>
</style>
<style name="SettingsLibButtonStyle.Expressive.Filled.Extra"
@@ -45,28 +34,34 @@
<item name="android:layout_width">match_parent</item>
</style>
+ <style name="SettingsLibButtonStyle.Expressive.Icon.Filled"
+ parent="@style/Widget.Material3Expressive.Button.IconButton.Filled">
+ <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="SettingsLibButtonStyle.Expressive.Icon.Filled.Large">
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium</item>
+ </style>
+
+ <style name="SettingsLibButtonStyle.Expressive.Icon.Filled.Extra"
+ parent="@style/SettingsLibButtonStyle.Expressive.Icon.Filled.Large">
+ <item name="android:layout_width">match_parent</item>
+ </style>
+
<style name="SettingsLibButtonStyle.Expressive.Tonal"
- parent="@style/Widget.Material3.Button.TonalButton">
+ parent="@style/Widget.Material3Expressive.Button.TonalButton.Icon">
<item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center</item>
- <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item>
- <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item>
- <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item>
- <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item>
- <item name="android:backgroundTint">@color/settingslib_materialColorSecondaryContainer</item>
<item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item>
- <item name="android:textColor">@color/settingslib_materialColorOnSecondaryContainer</item>
- <item name="iconGravity">textStart</item>
- <item name="iconTint">@color/settingslib_materialColorOnSecondaryContainer</item>
- <item name="iconSize">@dimen/settingslib_expressive_space_small4</item>
</style>
<style name="SettingsLibButtonStyle.Expressive.Tonal.Large">
- <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item>
- <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item>
- <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item>
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium</item>
</style>
<style name="SettingsLibButtonStyle.Expressive.Tonal.Extra"
@@ -74,29 +69,34 @@
<item name="android:layout_width">match_parent</item>
</style>
+ <style name="SettingsLibButtonStyle.Expressive.Icon.Tonal"
+ parent="@style/Widget.Material3Expressive.Button.IconButton.Tonal">
+ <item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item>
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:gravity">center</item>
+ </style>
+
+ <style name="SettingsLibButtonStyle.Expressive.Icon.Tonal.Large">
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium</item>
+ </style>
+
+ <style name="SettingsLibButtonStyle.Expressive.Icon.Tonal.Extra"
+ parent="@style/SettingsLibButtonStyle.Expressive.Tonal.Large">
+ <item name="android:layout_width">match_parent</item>
+ </style>
+
<style name="SettingsLibButtonStyle.Expressive.Outline"
- parent="@style/Widget.Material3.Button.OutlinedButton.Icon">
+ parent="@style/Widget.Material3Expressive.Button.OutlinedButton.Icon">
<item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:gravity">center</item>
- <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item>
- <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item>
- <item name="android:paddingVertical">@dimen/settingslib_expressive_space_extrasmall5</item>
- <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small1</item>
<item name="android:textAppearance">@style/TextAppearance.SettingsLib.LabelLarge</item>
- <item name="android:textColor">@color/settingslib_materialColorPrimary</item>
- <item name="iconTint">@color/settingslib_materialColorPrimary</item>
- <item name="iconGravity">textStart</item>
- <item name="iconSize">@dimen/settingslib_expressive_space_small4</item>
- <item name="iconPadding">@dimen/settingslib_expressive_space_extrasmall4</item>
- <item name="strokeColor">@color/settingslib_materialColorOutlineVariant</item>
</style>
<style name="SettingsLibButtonStyle.Expressive.Outline.Large">
- <item name="android:paddingVertical">@dimen/settingslib_expressive_space_small1</item>
- <item name="android:paddingHorizontal">@dimen/settingslib_expressive_space_small4</item>
- <item name="android:textAppearance">@style/TextAppearance.SettingsLib.TitleMedium</item>
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Medium</item>
</style>
<style name="SettingsLibButtonStyle.Expressive.Outline.Extra"
@@ -105,15 +105,10 @@
</style>
<style name="SettingslibTextButtonStyle.Expressive"
- parent="@style/Widget.Material3.Button.TextButton.Icon">
+ parent="@style/Widget.Material3Expressive.Button.TextButton.Icon">
<item name="android:theme">@style/Theme.Material3.DynamicColors.DayNight</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
- <item name="android:textAppearance">@style/TextAppearance.SettingsLib.BodyLarge.Emphasized</item>
- <item name="android:textColor">@color/settingslib_materialColorOnSurface</item>
- <item name="iconTint">@null</item>
- <item name="iconPadding">@dimen/settingslib_expressive_space_extrasmall4</item>
- <item name="rippleColor">?android:attr/colorControlHighlight</item>
</style>
<style name="SettingsLibCardStyle" parent="">
diff --git a/packages/SettingsLib/SettingsTheme/res/values/styles_m3_expressive.xml b/packages/SettingsLib/SettingsTheme/res/values/styles_m3_expressive.xml
new file mode 100644
index 000000000000..826fe31d121d
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/values/styles_m3_expressive.xml
@@ -0,0 +1,475 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ 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.
+ -->
+
+<resources xmlns:tools="http://schemas.android.com/tools">
+ <!-- M3 Expressive filled button style. -->
+ <style name="Widget.Material3Expressive.Button" parent="Widget.Material3.Button">
+ <item name="android:paddingStart">?attr/containerPaddingStart</item>
+ <item name="android:paddingEnd">?attr/containerPaddingEnd</item>
+ <item name="android:paddingTop">?attr/containerPaddingTop</item>
+ <item name="android:paddingBottom">?attr/containerPaddingBottom</item>
+ <item name="android:insetTop">?attr/containerInsetTop</item>
+ <item name="android:insetBottom">?attr/containerInsetBottom</item>
+ <item name="iconPadding">?attr/containerIconPadding</item>
+ <item name="iconSize">?attr/containerIconSize</item>
+ <item name="android:textAppearance">?attr/labelTextAppearance</item>
+ <item name="shapeAppearance">@xml/settingslib_button_shape_state_list</item>
+ <item name="shapeAppearanceOverlay">@null</item>
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Filled</item>
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.Small</item>
+ </style>
+ <style name="Widget.Material3Expressive.Button.Icon"/>
+
+ <!-- M3 Expressive tonal button style. -->
+ <style name="Widget.Material3Expressive.Button.TonalButton">
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Tonal</item>
+ </style>
+ <style name="Widget.Material3Expressive.Button.TonalButton.Icon"/>
+
+ <!-- M3 Expressive outlined button style. -->
+ <style name="Widget.Material3Expressive.Button.OutlinedButton">
+ <item name="android:stateListAnimator" tools:ignore="NewApi">@animator/mtrl_btn_unelevated_state_list_anim</item>
+ <item name="elevation">0dp</item>
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Outlined</item>
+ <item name="strokeColor">@color/settingslib_expressive_button_outline_color_selector</item>
+ <item name="strokeWidth">?attr/containerStrokeWidth</item>
+ <item name="backgroundTint">@color/settingslib_expressive_button_outlined_background_color_selector</item>
+ </style>
+ <style name="Widget.Material3Expressive.Button.OutlinedButton.Icon"/>
+
+ <!-- M3 Expressive text button style. -->
+ <style name="Widget.Material3Expressive.Button.TextButton">
+ <item name="android:stateListAnimator" tools:ignore="NewApi">@animator/mtrl_btn_unelevated_state_list_anim</item>
+ <item name="elevation">0dp</item>
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.TextButton</item>
+ </style>
+ <style name="Widget.Material3Expressive.Button.TextButton.Icon"/>
+
+ <!-- Styles for M3 Expressive Icon Buttons. -->
+
+ <!-- M3 Expressive icon only button without a container or outline style. -->
+ <style name="Widget.Material3Expressive.Button.IconButton">
+ <item name="android:stateListAnimator" tools:ignore="NewApi">@animator/mtrl_btn_unelevated_state_list_anim</item>
+ <item name="elevation">0dp</item>
+ <item name="android:minWidth">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="android:minHeight">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="android:insetLeft">?attr/containerInsetLeft</item>
+ <item name="android:insetRight">?attr/containerInsetRight</item>
+ <item name="iconPadding">@dimen/m3_btn_icon_only_icon_padding</item>
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.IconButton.Standard</item>
+ <item name="materialSizeOverlay">@style/SizeOverlay.Material3Expressive.Button.IconButton.Small</item>
+ </style>
+
+ <!-- M3 Expressive icon only button filled container style. -->
+ <style name="Widget.Material3Expressive.Button.IconButton.Filled">
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Filled</item>
+ </style>
+
+ <!-- M3 Expressive icon only button in tonal container style. -->
+ <style name="Widget.Material3Expressive.Button.IconButton.Tonal">
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Tonal</item>
+ </style>
+
+ <!-- M3 Expressive icon only button with an outline style. -->
+ <style name="Widget.Material3Expressive.Button.IconButton.Outlined">
+ <item name="materialThemeOverlay">@style/ThemeOverlay.Material3Expressive.Button.Outlined</item>
+ <item name="strokeColor">@color/settingslib_expressive_button_outline_color_selector</item>
+ <item name="strokeWidth">?attr/containerStrokeWidth</item>
+ <item name="backgroundTint">@color/settingslib_expressive_button_outlined_background_color_selector</item>
+ </style>
+
+ <!-- Styles for M3 Expressive Button Groups. -->
+
+ <!-- M3 Expressive Button Group. -->
+ <style name="Widget.Material3Expressive.MaterialButtonGroup" parent="Widget.Material3.MaterialButtonGroup"/>
+
+ <!-- M3 Expressive Connected Button Group. -->
+ <style name="Widget.Material3Expressive.MaterialButtonGroup.Connected" parent="Widget.Material3.MaterialButtonGroup.Connected">
+ <item name="innerCornerSize">@xml/settingslib_inner_corner_size_state_list</item>
+ </style>
+
+ <!-- M3 Expressive Button Toggle Group (Segmented Button). -->
+ <style name="Widget.Material3Expressive.MaterialButtonToggleGroup" parent="Widget.Material3.MaterialButtonToggleGroup">
+ <item name="innerCornerSize">@xml/settingslib_inner_corner_size_state_list</item>
+ <item name="shapeAppearance">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="android:spacing">@dimen/settingslib_expressive_space_extrasmall1</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlays for different color variants. -->
+
+ <!-- M3 Expressive Button Theme Overlay for the filled color variant. -->
+ <style name="ThemeOverlay.Material3Expressive.Button.Filled" parent="">
+ <item name="colorContainer">?attr/colorPrimary</item>
+ <item name="colorContainerChecked">?attr/colorPrimary</item>
+ <item name="colorContainerUnchecked">?attr/colorSurfaceContainer</item>
+ <item name="colorOnContainer">?attr/colorOnPrimary</item>
+ <item name="colorOnContainerChecked">?attr/colorOnPrimary</item>
+ <item name="colorOnContainerUnchecked">?attr/colorOnSurfaceVariant</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the tonal color variant. -->
+ <style name="ThemeOverlay.Material3Expressive.Button.Tonal" parent="">
+ <item name="colorContainer">?attr/colorSecondaryContainer</item>
+ <item name="colorContainerChecked">?attr/colorSecondary</item>
+ <item name="colorContainerUnchecked">?attr/colorSecondaryContainer</item>
+ <item name="colorOnContainer">?attr/colorOnSecondaryContainer</item>
+ <item name="colorOnContainerChecked">?attr/colorOnSecondary</item>
+ <item name="colorOnContainerUnchecked">?attr/colorOnSecondaryContainer</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the outlined variant. -->
+ <style name="ThemeOverlay.Material3Expressive.Button.Outlined" parent="">
+ <item name="colorContainer">@android:color/transparent</item>
+ <item name="colorContainerChecked">?attr/colorSurfaceInverse</item>
+ <item name="colorContainerUnchecked">@android:color/transparent</item>
+ <item name="colorOnContainer">?attr/colorOnSurfaceVariant</item>
+ <item name="colorOnContainerChecked">?attr/colorOnSurfaceInverse</item>
+ <item name="colorOnContainerUnchecked">?attr/colorOnSurfaceVariant</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the text only variant. -->
+ <style name="ThemeOverlay.Material3Expressive.Button.TextButton" parent="ThemeOverlay.Material3.Button.TextButton">
+ <item name="colorContainerChecked">?attr/colorContainer</item>
+ <item name="colorContainerUnchecked">?attr/colorContainer</item>
+ <item name="colorOnContainerChecked">?attr/colorOnContainer</item>
+ <item name="colorOnContainerUnchecked">?attr/colorOnSurfaceVariant</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the icon only variant. -->
+ <style name="ThemeOverlay.Material3Expressive.Button.IconButton.Standard" parent="">
+ <item name="colorContainer">@android:color/transparent</item>
+ <item name="colorContainerChecked">@android:color/transparent</item>
+ <item name="colorContainerUnchecked">@android:color/transparent</item>
+ <item name="colorOnContainer">?attr/colorOnSurfaceVariant</item>
+ <item name="colorOnContainerChecked">?attr/colorPrimary</item>
+ <item name="colorOnContainerUnchecked">?attr/colorOnSurfaceVariant</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the extra small variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.Xsmall" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall6</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall6</item>
+ <item name="containerPaddingTop">6dp</item>
+ <item name="containerPaddingBottom">6dp</item>
+ <item name="containerInsetTop">8dp</item>
+ <item name="containerInsetBottom">8dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_small3</item>
+ <item name="containerIconPadding">@dimen/settingslib_expressive_space_extrasmall4</item>
+ <item name="containerStrokeWidth">1dp</item>
+ <item name="labelTextAppearance">?attr/textAppearanceLabelLarge</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerSmall</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerMedium</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.Xsmall.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the small variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.Small" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_small1</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_small1</item>
+ <item name="containerPaddingTop">10dp</item>
+ <item name="containerPaddingBottom">10dp</item>
+ <item name="containerInsetTop">4dp</item>
+ <item name="containerInsetBottom">4dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_small3</item>
+ <item name="containerIconPadding">@dimen/settingslib_expressive_space_extrasmall4</item>
+ <item name="containerStrokeWidth">1dp</item>
+ <item name="labelTextAppearance">?attr/textAppearanceLabelLarge</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerSmall</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerMedium</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.Small.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the medium variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.Medium" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_small4</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_small4</item>
+ <item name="containerPaddingTop">16dp</item>
+ <item name="containerPaddingBottom">16dp</item>
+ <item name="containerInsetTop">0dp</item>
+ <item name="containerInsetBottom">0dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_small4</item>
+ <item name="containerIconPadding">@dimen/settingslib_expressive_space_extrasmall4</item>
+ <item name="containerStrokeWidth">1dp</item>
+ <item name="labelTextAppearance">?attr/textAppearanceTitleMedium</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerMedium</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerLarge</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.Medium.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerLarge</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the large variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.Large" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="containerPaddingTop">32dp</item>
+ <item name="containerPaddingBottom">32dp</item>
+ <item name="containerInsetTop">0dp</item>
+ <item name="containerInsetBottom">0dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_medium1</item>
+ <item name="containerIconPadding">@dimen/settingslib_expressive_space_extrasmall6</item>
+ <item name="containerStrokeWidth">@dimen/settingslib_expressive_space_extrasmall1</item>
+ <item name="labelTextAppearance">?attr/textAppearanceHeadlineSmall</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerLarge</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerExtraLarge</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.Large.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <!-- M3 Expressive Button Theme Overlay for the extra large variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.Xlarge" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_large2</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_large2</item>
+ <item name="containerPaddingTop">48dp</item>
+ <item name="containerPaddingBottom">48dp</item>
+ <item name="containerInsetTop">0dp</item>
+ <item name="containerInsetBottom">0dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_medium3</item>
+ <item name="containerIconPadding">@dimen/settingslib_expressive_space_small1</item>
+ <item name="containerStrokeWidth">3dp</item>
+ <item name="labelTextAppearance">?attr/textAppearanceHeadlineLarge</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerLarge</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerExtraLarge</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.Xlarge.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <!-- M3 Expressive Icon Button Theme Overlay for the extra small variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xsmall" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall3</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall3</item>
+ <item name="containerPaddingTop">6dp</item>
+ <item name="containerPaddingBottom">6dp</item>
+ <item name="containerInsetTop">8dp</item>
+ <item name="containerInsetBottom">8dp</item>
+ <item name="containerInsetLeft">8dp</item>
+ <item name="containerInsetRight">8dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_small3</item>
+ <item name="containerStrokeWidth">1dp</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerSmall</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerMedium</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xsmall.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xsmall.Narrow">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall2</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall2</item>
+ <item name="containerInsetLeft">10dp</item>
+ <item name="containerInsetRight">10dp</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xsmall.Narrow.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xsmall.Wide">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall5</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall5</item>
+ <item name="containerInsetLeft">4dp</item>
+ <item name="containerInsetRight">4dp</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xsmall.Wide.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <!-- M3 Expressive Icon Button Theme Overlay for the small variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Small" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall4</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall4</item>
+ <item name="containerPaddingTop">8dp</item>
+ <item name="containerPaddingBottom">8dp</item>
+ <item name="containerInsetTop">4dp</item>
+ <item name="containerInsetBottom">4dp</item>
+ <item name="containerInsetLeft">4dp</item>
+ <item name="containerInsetRight">4dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_small4</item>
+ <item name="containerStrokeWidth">1dp</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerSmall</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerMedium</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Small.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Small.Narrow">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall2</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall2</item>
+ <item name="containerInsetLeft">8dp</item>
+ <item name="containerInsetRight">8dp</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Small.Narrow.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Small.Wide">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall7</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall7</item>
+ <item name="containerInsetLeft">0dp</item>
+ <item name="containerInsetRight">0dp</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Small.Wide.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerMedium</item>
+ </style>
+
+ <!-- M3 Expressive Icon Button Theme Overlay for the medium variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Medium" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_small1</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_small1</item>
+ <item name="containerPaddingTop">16dp</item>
+ <item name="containerPaddingBottom">16dp</item>
+ <item name="containerInsetTop">0dp</item>
+ <item name="containerInsetBottom">0dp</item>
+ <item name="containerInsetLeft">0dp</item>
+ <item name="containerInsetRight">0dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_small4</item>
+ <item name="containerStrokeWidth">1dp</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerMedium</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerLarge</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Medium.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerLarge</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Medium.Narrow">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_extrasmall6</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_extrasmall6</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Medium.Narrow.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerLarge</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Medium.Wide">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_small4</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_small4</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Medium.Wide.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerLarge</item>
+ </style>
+
+ <!-- M3 Expressive Icon Button Theme Overlay for the large variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Large" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_medium1</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_medium1</item>
+ <item name="containerPaddingTop">32dp</item>
+ <item name="containerPaddingBottom">32dp</item>
+ <item name="containerInsetTop">0dp</item>
+ <item name="containerInsetBottom">0dp</item>
+ <item name="containerInsetLeft">0dp</item>
+ <item name="containerInsetRight">0dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_medium1</item>
+ <item name="containerStrokeWidth">@dimen/settingslib_expressive_space_extrasmall1</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerLarge</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerExtraLarge</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Large.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Large.Narrow">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_small1</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_small1</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Large.Narrow.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Large.Wide">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_medium4</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Large.Wide.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <!-- M3 Expressive Icon Button Theme Overlay for the extra large variant. -->
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xlarge" parent="">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_medium4</item>
+ <item name="containerPaddingTop">48dp</item>
+ <item name="containerPaddingBottom">48dp</item>
+ <item name="containerInsetTop">0dp</item>
+ <item name="containerInsetBottom">0dp</item>
+ <item name="containerInsetLeft">0dp</item>
+ <item name="containerInsetRight">0dp</item>
+ <item name="containerIconSize">@dimen/settingslib_expressive_space_medium3</item>
+ <item name="containerStrokeWidth">3dp</item>
+ <item name="containerShapePressed">?attr/shapeAppearanceCornerLarge</item>
+ <item name="containerShapeChecked">?attr/shapeAppearanceCornerExtraLarge</item>
+ <item name="containerShapeDefault">@style/ShapeAppearance.Material3.Corner.Full</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xlarge.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xlarge.Narrow">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_medium1</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_medium1</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xlarge.Narrow.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xlarge.Wide">
+ <item name="containerPaddingStart">@dimen/settingslib_expressive_space_large3</item>
+ <item name="containerPaddingEnd">@dimen/settingslib_expressive_space_large3</item>
+ </style>
+ <style name="SizeOverlay.Material3Expressive.Button.IconButton.Xlarge.Wide.Square">
+ <item name="containerShapeChecked">@style/ShapeAppearance.Material3.Corner.Full</item>
+ <item name="containerShapeDefault">?attr/shapeAppearanceCornerExtraLarge</item>
+ </style>
+
+ <!-- M3 shape -->
+ <style name="ShapeAppearance.Material3.Corner.Full" parent="">
+ <item name="cornerFamily">?attr/shapeCornerFamily</item>
+ <item name="cornerSize">50%</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/xml/settingslib_button_shape_state_list.xml b/packages/SettingsLib/SettingsTheme/res/xml/settingslib_button_shape_state_list.xml
new file mode 100644
index 000000000000..defedb3ee477
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/xml/settingslib_button_shape_state_list.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:state_checkable="true" android:state_pressed="true"
+ app:shapeAppearance="?attr/containerShapePressed"/>
+ <item android:state_checked="true"
+ app:shapeAppearance="?attr/containerShapeChecked"/>
+ <item app:shapeAppearance="?attr/containerShapeDefault"/>
+</selector> \ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/xml/settingslib_inner_corner_size_state_list.xml b/packages/SettingsLib/SettingsTheme/res/xml/settingslib_inner_corner_size_state_list.xml
new file mode 100644
index 000000000000..6e49c7c69931
--- /dev/null
+++ b/packages/SettingsLib/SettingsTheme/res/xml/settingslib_inner_corner_size_state_list.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:state_checkable="true" android:state_pressed="true"
+ app:cornerSize="4dp"/>
+ <item android:state_checked="true"
+ app:cornerSize="50%"/>
+ <item app:cornerSize="8dp"/>
+</selector> \ No newline at end of file
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
index 9bc334391ef9..068df8e31ed0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/communal/ui/compose/CommunalHub.kt
@@ -112,6 +112,7 @@ import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
@@ -759,10 +760,12 @@ fun calculateWidgetSize(
private fun HorizontalGridWrapper(
minContentPadding: PaddingValues,
gridState: LazyGridState,
+ dragDropState: GridDragDropState?,
setContentOffset: (offset: Offset) -> Unit,
modifier: Modifier = Modifier,
content: LazyGridScope.(sizeInfo: SizeInfo?) -> Unit,
) {
+ val isDragging = dragDropState?.draggingItemKey != null
if (communalResponsiveGrid()) {
val flingBehavior =
rememberSnapFlingBehavior(lazyGridState = gridState, snapPosition = SnapPosition.Start)
@@ -775,6 +778,10 @@ private fun HorizontalGridWrapper(
minHorizontalArrangement = Dimensions.ItemSpacing,
minVerticalArrangement = Dimensions.ItemSpacing,
setContentOffset = setContentOffset,
+ // Temporarily disable user gesture scrolling while dragging a widget to prevent
+ // conflicts between the drag and scroll gestures. Programmatic scrolling remains
+ // enabled to allow dragging a widget beyond the visible boundaries.
+ userScrollEnabled = !isDragging,
content = content,
)
} else {
@@ -793,6 +800,10 @@ private fun HorizontalGridWrapper(
contentPadding = minContentPadding,
horizontalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
verticalArrangement = Arrangement.spacedBy(Dimensions.ItemSpacing),
+ // Temporarily disable user gesture scrolling while dragging a widget to prevent
+ // conflicts between the drag and scroll gestures. Programmatic scrolling remains
+ // enabled to allow dragging a widget beyond the visible boundaries.
+ userScrollEnabled = !isDragging,
) {
content(null)
}
@@ -862,6 +873,7 @@ private fun BoxScope.CommunalHubLazyGrid(
HorizontalGridWrapper(
modifier = gridModifier,
gridState = gridState,
+ dragDropState = dragDropState,
minContentPadding = minContentPadding,
setContentOffset = setContentOffset,
) { sizeInfo ->
@@ -1708,23 +1720,29 @@ private fun Umo(
private fun UmoLegacy(viewModel: BaseCommunalViewModel, modifier: Modifier = Modifier) {
AndroidView(
modifier =
- modifier.pointerInput(Unit) {
- detectHorizontalDragGestures { change, _ ->
- change.consume()
- val upTime = SystemClock.uptimeMillis()
- val event =
- MotionEvent.obtain(
- upTime,
- upTime,
- MotionEvent.ACTION_MOVE,
- change.position.x,
- change.position.y,
- 0,
- )
- viewModel.mediaHost.hostView.dispatchTouchEvent(event)
- event.recycle()
- }
- },
+ modifier
+ .clip(
+ shape =
+ RoundedCornerShape(dimensionResource(system_app_widget_background_radius))
+ )
+ .background(MaterialTheme.colorScheme.primary)
+ .pointerInput(Unit) {
+ detectHorizontalDragGestures { change, _ ->
+ change.consume()
+ val upTime = SystemClock.uptimeMillis()
+ val event =
+ MotionEvent.obtain(
+ upTime,
+ upTime,
+ MotionEvent.ACTION_MOVE,
+ change.position.x,
+ change.position.y,
+ 0,
+ )
+ viewModel.mediaHost.hostView.dispatchTouchEvent(event)
+ event.recycle()
+ }
+ },
factory = { _ ->
viewModel.mediaHost.hostView.apply {
layoutParams =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index 957fdf7bcd8f..58bfd08dfdbc 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -340,11 +340,12 @@ fun ContentScope.NotificationScrollingStack(
// set the bounds to null when the scrim disappears
DisposableEffect(Unit) { onDispose { viewModel.onScrimBoundsChanged(null) } }
- val minScrimTop = with(density) { ShadeHeader.Dimensions.CollapsedHeight.toPx() }
+ // Top position if the scrim, when it is fully expanded.
+ val minScrimTop = ShadeHeader.Dimensions.CollapsedHeight
// The minimum offset for the scrim. The scrim is considered fully expanded when it
// is at this offset.
- val minScrimOffset: () -> Float = { minScrimTop - maxScrimTop() }
+ val minScrimOffset: () -> Float = { with(density) { minScrimTop.toPx() } - maxScrimTop() }
// The height of the scrim visible on screen when it is in its resting (collapsed) state.
val minVisibleScrimHeight: () -> Float = {
@@ -563,6 +564,7 @@ fun ContentScope.NotificationScrollingStack(
}
.thenIf(shouldShowScrim) { Modifier.background(scrimBackgroundColor) }
.thenIf(shouldFillMaxSize) { Modifier.fillMaxSize() }
+ .thenIf(supportNestedScrolling) { Modifier.padding(bottom = minScrimTop) }
.debugBackground(viewModel, DEBUG_BOX_COLOR)
) {
Column(
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index a53c6b29338f..aefe83b781e0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -239,7 +239,7 @@ private fun SceneScope.ShadeScene(
modifier = modifier,
shadeSession = shadeSession,
)
- is ShadeMode.Dual -> error("Dual shade is not yet implemented!")
+ is ShadeMode.Dual -> error("Dual shade is implemented separately as an overlay.")
}
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
index 8777ff924bc1..495fdafad26d 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/AnimateSharedAsState.kt
@@ -434,7 +434,8 @@ private class AnimatedStateImpl<T, Delta>(
if (element != null) {
layoutImpl.elements[element]?.let { element ->
elementState(
- layoutImpl.state.transitionStates,
+ listOf(layoutImpl.state.transitionStates),
+ elementKey = element.key,
isInContent = { it in element.stateByContent },
)
as? TransitionState.Transition
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
index 16b4322411ac..b0d9fcd4344b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/Element.kt
@@ -45,7 +45,11 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.Constraints
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.round
+import androidx.compose.ui.util.fastAll
+import androidx.compose.ui.util.fastAny
import androidx.compose.ui.util.fastCoerceIn
+import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastForEachIndexed
import androidx.compose.ui.util.fastForEachReversed
import androidx.compose.ui.util.lerp
import com.android.compose.animation.scene.content.Content
@@ -92,7 +96,17 @@ internal class Element(val key: ElementKey) {
/** The last and target state of this element in a given content. */
@Stable
- class State(val content: ContentKey) {
+ class State(
+ /**
+ * A list of contents where this element state finds itself in. The last content is the
+ * content of the STL which is actually responsible to compose and place this element. The
+ * other contents (if any) are the ancestors. The ancestors do not actually place this
+ * element but the element is part of the ancestors scene as part of a NestedSTL. The state
+ * can be accessed by ancestor transitions to read the properties of this element to compute
+ * transformations.
+ */
+ val contents: List<ContentKey>
+ ) {
/**
* The *target* state of this element in this content, i.e. the state of this element when
* we are idle on this content.
@@ -158,7 +172,8 @@ internal fun Modifier.element(
// layout/drawing.
// TODO(b/341072461): Revert this and read the current transitions in ElementNode directly once
// we can ensure that SceneTransitionLayoutImpl will compose new contents first.
- val currentTransitionStates = layoutImpl.state.transitionStates
+ val currentTransitionStates = getAllNestedTransitionStates(layoutImpl)
+
return thenIf(layoutImpl.state.isElevationPossible(content.key, key)) {
Modifier.maybeElevateInContent(layoutImpl, content, key, currentTransitionStates)
}
@@ -166,11 +181,26 @@ internal fun Modifier.element(
.testTag(key.testTag)
}
+/**
+ * Returns the transition states of all ancestors + the transition state of the current STL. The
+ * last element is the transition state of the local STL (the one with the highest nestingDepth).
+ *
+ * @return Each transition state of a STL is a List and this is a list of all the states.
+ */
+internal fun getAllNestedTransitionStates(
+ layoutImpl: SceneTransitionLayoutImpl
+): List<List<TransitionState>> {
+ return buildList {
+ layoutImpl.ancestors.fastForEach { add(it.layoutImpl.state.transitionStates) }
+ add(layoutImpl.state.transitionStates)
+ }
+}
+
private fun Modifier.maybeElevateInContent(
layoutImpl: SceneTransitionLayoutImpl,
content: Content,
key: ElementKey,
- transitionStates: List<TransitionState>,
+ transitionStates: List<List<TransitionState>>,
): Modifier {
fun isSharedElement(
stateByContent: Map<ContentKey, Element.State>,
@@ -192,12 +222,12 @@ private fun Modifier.maybeElevateInContent(
content.containerState,
enabled = {
val stateByContent = layoutImpl.elements.getValue(key).stateByContent
- val state = elementState(transitionStates, isInContent = { it in stateByContent })
+ val state = elementState(transitionStates, key, isInContent = { it in stateByContent })
state is TransitionState.Transition &&
state.transformationSpec
.transformations(key, content.key)
- .shared
+ ?.shared
?.transformation
?.elevateInContent == content.key &&
isSharedElement(stateByContent, state) &&
@@ -218,7 +248,7 @@ private fun Modifier.maybeElevateInContent(
*/
internal data class ElementModifier(
internal val layoutImpl: SceneTransitionLayoutImpl,
- private val currentTransitionStates: List<TransitionState>,
+ private val currentTransitionStates: List<List<TransitionState>>,
internal val content: Content,
internal val key: ElementKey,
) : ModifierNodeElement<ElementNode>() {
@@ -232,7 +262,7 @@ internal data class ElementModifier(
internal class ElementNode(
private var layoutImpl: SceneTransitionLayoutImpl,
- private var currentTransitionStates: List<TransitionState>,
+ private var currentTransitionStates: List<List<TransitionState>>,
private var content: Content,
private var key: ElementKey,
) : Modifier.Node(), DrawModifierNode, ApproachLayoutModifierNode, TraversableNode {
@@ -257,10 +287,15 @@ internal class ElementNode(
_element = element
addToRenderAuthority(element)
if (!element.stateByContent.contains(content.key)) {
- val elementState = Element.State(content.key)
+ val contents = buildList {
+ layoutImpl.ancestors.fastForEach { add(it.inContent) }
+ add(content.key)
+ }
+
+ val elementState = Element.State(contents)
element.stateByContent[content.key] = elementState
- layoutImpl.ancestorContentKeys.forEach { element.stateByContent[it] = elementState }
+ layoutImpl.ancestors.fastForEach { element.stateByContent[it.inContent] = elementState }
}
}
@@ -273,7 +308,7 @@ internal class ElementNode(
// this element was composed multiple times in the same content.
val nCodeLocations = stateInContent.nodes.size
if (nCodeLocations != 1 || !stateInContent.nodes.contains(this@ElementNode)) {
- error("$key was composed $nCodeLocations times in ${stateInContent.content}")
+ error("$key was composed $nCodeLocations times in ${stateInContent.contents}")
}
}
}
@@ -288,12 +323,12 @@ internal class ElementNode(
}
private fun addToRenderAuthority(element: Element) {
- val nestingDepth = layoutImpl.ancestorContentKeys.size
+ val nestingDepth = layoutImpl.ancestors.size
element.renderAuthority[nestingDepth] = content.key
}
private fun removeFromRenderAuthority() {
- val nestingDepth = layoutImpl.ancestorContentKeys.size
+ val nestingDepth = layoutImpl.ancestors.size
if (element.renderAuthority[nestingDepth] == content.key) {
element.renderAuthority.remove(nestingDepth)
}
@@ -305,7 +340,7 @@ internal class ElementNode(
fun update(
layoutImpl: SceneTransitionLayoutImpl,
- currentTransitionStates: List<TransitionState>,
+ currentTransitionStates: List<List<TransitionState>>,
content: Content,
key: ElementKey,
) {
@@ -326,7 +361,7 @@ internal class ElementNode(
override fun isMeasurementApproachInProgress(lookaheadSize: IntSize): Boolean {
// TODO(b/324191441): Investigate whether making this check more complex (checking if this
// element is shared or transformed) would lead to better performance.
- return layoutImpl.state.isTransitioning()
+ return isAnyStateTransitioning()
}
override fun Placeable.PlacementScope.isPlacementApproachInProgress(
@@ -334,7 +369,12 @@ internal class ElementNode(
): Boolean {
// TODO(b/324191441): Investigate whether making this check more complex (checking if this
// element is shared or transformed) would lead to better performance.
- return layoutImpl.state.isTransitioning()
+ return isAnyStateTransitioning()
+ }
+
+ private fun isAnyStateTransitioning(): Boolean {
+ return layoutImpl.state.isTransitioning() ||
+ layoutImpl.ancestors.fastAny { it.layoutImpl.state.isTransitioning() }
}
@ExperimentalComposeUiApi
@@ -372,7 +412,7 @@ internal class ElementNode(
// This is the case if for example a transition between two overlays is ongoing where
// sharedElement isn't part of either but the element is still rendered as part of
// the underlying scene that is currently not being transitioned.
- val currentState = currentTransitionStates.last()
+ val currentState = currentTransitionStates.last().last()
val shouldPlaceInThisContent =
elementContentWhenIdle(
layoutImpl,
@@ -448,7 +488,7 @@ internal class ElementNode(
element,
transition,
contentValue = { it.targetOffset },
- transformation = { it.offset },
+ transformation = { it?.offset },
currentValue = { currentOffset },
isSpecified = { it != Offset.Unspecified },
::lerp,
@@ -592,8 +632,7 @@ internal class ElementNode(
}
}
- pruneForContent(stateInContent.content)
- layoutImpl.ancestorContentKeys.forEach { content -> pruneForContent(content) }
+ stateInContent.contents.fastForEach { pruneForContent(it) }
}
}
}
@@ -602,9 +641,10 @@ internal class ElementNode(
private fun elementState(
layoutImpl: SceneTransitionLayoutImpl,
element: Element,
- transitionStates: List<TransitionState>,
+ transitionStates: List<List<TransitionState>>,
): TransitionState? {
- val state = elementState(transitionStates, isInContent = { it in element.stateByContent })
+ val state =
+ elementState(transitionStates, element.key, isInContent = { it in element.stateByContent })
val transition = state as? TransitionState.Transition
val previousTransition = element.lastTransition
@@ -625,23 +665,48 @@ private fun elementState(
}
internal inline fun elementState(
- transitionStates: List<TransitionState>,
+ transitionStates: List<List<TransitionState>>,
+ elementKey: ElementKey,
isInContent: (ContentKey) -> Boolean,
): TransitionState? {
- val lastState = transitionStates.last()
- if (lastState is TransitionState.Idle) {
- check(transitionStates.size == 1)
- return lastState
- }
+ // transitionStates is a list of all ancestor transition states + transitionState of the local
+ // STL. By traversing the list in normal order we by default prioritize the transitionState of
+ // the highest ancestor if it is running and has a transformation for this element.
+ transitionStates.fastForEachIndexed { index, states ->
+ if (index < transitionStates.size - 1) {
+ // Check if any ancestor runs a transition that has a transformation for the element
+ states.fastForEachReversed { state ->
+ if (
+ state is TransitionState.Transition &&
+ (state.transformationSpec.hasTransformation(
+ elementKey,
+ state.fromContent,
+ ) ||
+ state.transformationSpec.hasTransformation(elementKey, state.toContent))
+ ) {
+ return state
+ }
+ }
+ } else {
+ // the last state of the list, is the state of the local STL
+ val lastState = states.last()
+ if (lastState is TransitionState.Idle) {
+ check(states.size == 1)
+ return lastState
+ }
- // Find the last transition with a content that contains the element.
- transitionStates.fastForEachReversed { state ->
- val transition = state as TransitionState.Transition
- if (isInContent(transition.fromContent) || isInContent(transition.toContent)) {
- return transition
+ // Find the last transition with a content that contains the element.
+ states.fastForEachReversed { state ->
+ val transition = state as TransitionState.Transition
+ if (isInContent(transition.fromContent) || isInContent(transition.toContent)) {
+ return transition
+ }
+ }
}
}
-
+ // We are running a transition where both from and to don't contain the element. The element
+ // may still be rendered as e.g. it can be part of a idle scene where two overlays are currently
+ // transitioning above it.
return null
}
@@ -706,7 +771,7 @@ private fun prepareInterruption(
stateInContent.alphaInterruptionDelta = 0f
stateInContent.scaleInterruptionDelta = Scale.Zero
- if (!shouldPlaceElement(layoutImpl, stateInContent.content, element, transition)) {
+ if (!shouldPlaceElement(layoutImpl, stateInContent.contents.last(), element, transition)) {
stateInContent.offsetBeforeInterruption = Offset.Unspecified
stateInContent.alphaBeforeInterruption = Element.AlphaUnspecified
stateInContent.scaleBeforeInterruption = Scale.Unspecified
@@ -720,7 +785,7 @@ private fun prepareInterruption(
}
/**
- * Reconcile the state of [element] in the formContent and toContent of [transition] so that the
+ * Reconcile the state of [element] in the fromContent and toContent of [transition] so that the
* values before interruption have their expected values, taking shared transitions into account.
*
* @return the unique state this element had during [transition], `null` if it had multiple
@@ -878,7 +943,7 @@ private inline fun <T> setPlacementInterruptionDelta(
// If the element is shared, also set the delta on the other content so that it is used by that
// content if we start overscrolling it and change the content where the element is placed.
val otherContent =
- if (stateInContent.content == transition.fromContent) transition.toContent
+ if (stateInContent.contents.last() == transition.fromContent) transition.toContent
else transition.fromContent
val otherContentState = element.stateByContent[otherContent] ?: return
if (isSharedElementEnabled(element.key, transition)) {
@@ -916,7 +981,8 @@ private fun shouldPlaceElement(
if (
content != transition.fromContent &&
content != transition.toContent &&
- (!isReplacingOverlay || content != transition.currentScene)
+ (!isReplacingOverlay || content != transition.currentScene) &&
+ transitionDoesNotInvolveAncestorContent(layoutImpl, transition)
) {
return false
}
@@ -938,6 +1004,15 @@ private fun shouldPlaceElement(
return shouldPlaceSharedElement(layoutImpl, content, element.key, transition)
}
+private fun transitionDoesNotInvolveAncestorContent(
+ layoutImpl: SceneTransitionLayoutImpl,
+ transition: TransitionState.Transition,
+): Boolean {
+ return layoutImpl.ancestors.fastAll {
+ it.inContent != transition.fromContent && it.inContent != transition.toContent
+ }
+}
+
/**
* Whether the element is opaque or not.
*
@@ -968,7 +1043,7 @@ private fun isElementOpaque(
return true
}
- return transition.transformationSpec.transformations(element.key, content.key).alpha == null
+ return transition.transformationSpec.transformations(element.key, content.key)?.alpha == null
}
/**
@@ -992,7 +1067,7 @@ private fun elementAlpha(
element,
transition,
contentValue = { 1f },
- transformation = { it.alpha },
+ transformation = { it?.alpha },
currentValue = { 1f },
isSpecified = { true },
::lerp,
@@ -1060,7 +1135,7 @@ private fun measure(
element,
transition,
contentValue = { it.targetSize },
- transformation = { it.size },
+ transformation = { it?.size },
currentValue = { measurable.measure(constraints).also { maybePlaceable = it }.size() },
isSpecified = { it != Element.SizeUnspecified },
::lerp,
@@ -1093,7 +1168,6 @@ private fun measure(
)
},
)
-
return measurable.measure(
Constraints.fixed(
interruptedSize.width.coerceAtLeast(0),
@@ -1117,7 +1191,7 @@ private fun ContentDrawScope.getDrawScale(
element,
transition,
contentValue = { Scale.Default },
- transformation = { it.drawScale },
+ transformation = { it?.drawScale },
currentValue = { Scale.Default },
isSpecified = { true },
::lerp,
@@ -1205,7 +1279,8 @@ private inline fun <T> computeValue(
element: Element,
transition: TransitionState.Transition?,
contentValue: (Element.State) -> T,
- transformation: (ElementTransformations) -> TransformationWithRange<PropertyTransformation<T>>?,
+ transformation:
+ (ElementTransformations?) -> TransformationWithRange<PropertyTransformation<T>>?,
currentValue: () -> T,
isSpecified: (T) -> Boolean,
lerp: (T, T, Float) -> T,
@@ -1230,7 +1305,7 @@ private inline fun <T> computeValue(
return contentValue(currentContentState)
}
- val currentContent = currentContentState.content
+ val currentContent = currentContentState.contents.last()
// The element is shared: interpolate between the value in fromContent and the value in
// toContent.
@@ -1265,23 +1340,52 @@ private inline fun <T> computeValue(
}
}
+ // The content for which we compute the transformation. Note that this is not necessarily
+ // [currentContent] because [currentContent] could be a different content than the transition
+ // fromContent or toContent during interruptions or when a ancestor transition is running.
+ val content: ContentKey
// Get the transformed value, i.e. the target value at the beginning (for entering elements) or
// end (for leaving elements) of the transition.
- val contentState =
- checkNotNull(
- when {
- isSharedElement && currentContent == fromContent -> fromState
- isSharedElement -> toState
- currentSceneState != null && currentContent == transition.currentScene ->
- currentSceneState
- else -> fromState ?: toState
+ val contentState: Element.State
+ when {
+ isSharedElement -> {
+ content = currentContent
+ contentState = currentContentState
+ }
+ isAncestorTransition(layoutImpl, transition) -> {
+ if (
+ fromState != null &&
+ transition.transformationSpec.hasTransformation(element.key, fromContent)
+ ) {
+ content = fromContent
+ contentState = fromState
+ } else if (
+ toState != null &&
+ transition.transformationSpec.hasTransformation(element.key, toContent)
+ ) {
+ content = toContent
+ contentState = toState
+ } else {
+ throw IllegalStateException(
+ "Ancestor transition is active but no transformation " +
+ "spec was found. The ancestor transition should have only been selected " +
+ "when a transformation for that element and content was defined."
+ )
}
- )
-
- // The content for which we compute the transformation. Note that this is not necessarily
- // [currentContent] because [currentContent] could be a different content than the transition
- // fromContent or toContent during interruptions.
- val content = contentState.content
+ }
+ currentSceneState != null && currentContent == transition.currentScene -> {
+ content = currentContent
+ contentState = currentSceneState
+ }
+ fromState != null -> {
+ content = fromContent
+ contentState = fromState
+ }
+ else -> {
+ content = toContent
+ contentState = toState!!
+ }
+ }
val transformationWithRange =
transformation(transition.transformationSpec.transformations(element.key, content))
@@ -1437,6 +1541,8 @@ private inline fun <T> computeValue(
when {
content == toContent -> true
content == fromContent -> false
+ isAncestorTransition(layoutImpl, transition) ->
+ isEnteringAncestorTransition(layoutImpl, transition)
content == transition.currentScene -> toState == null
else -> content == toContent
}
@@ -1447,6 +1553,22 @@ private inline fun <T> computeValue(
}
}
+private fun isAncestorTransition(
+ layoutImpl: SceneTransitionLayoutImpl,
+ transition: TransitionState.Transition,
+): Boolean {
+ return layoutImpl.ancestors.fastAny {
+ it.inContent == transition.fromContent || it.inContent == transition.toContent
+ }
+}
+
+private fun isEnteringAncestorTransition(
+ layoutImpl: SceneTransitionLayoutImpl,
+ transition: TransitionState.Transition
+): Boolean {
+ return layoutImpl.ancestors.fastAny { it.inContent == transition.toContent }
+}
+
private inline fun <T> PropertyTransformation<T>.requireInterpolatedTransformation(
element: Element,
transition: TransitionState.Transition,
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
index 388456e8893a..c10a48567b22 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/MovableElement.kt
@@ -163,7 +163,7 @@ private class MovableElementScopeImpl(
// Important: Like in Modifier.element(), we read the transition states during
// composition then pass them to Layout to make sure that composition sees new states
// before layout and drawing.
- val transitionStates = layoutImpl.state.transitionStates
+ val transitionStates = getAllNestedTransitionStates(layoutImpl)
Layout { _, _ ->
// No need to measure or place anything.
val size =
@@ -186,7 +186,7 @@ private fun shouldComposeMovableElement(
element: MovableElementKey,
): Boolean {
return when (
- val elementState = movableElementState(element, layoutImpl.state.transitionStates)
+ val elementState = movableElementState(element, getAllNestedTransitionStates(layoutImpl))
) {
null ->
movableElementContentWhenIdle(layoutImpl, element, layoutImpl.state.transitionState) ==
@@ -221,10 +221,14 @@ private fun shouldComposeMoveableElement(
private fun movableElementState(
element: MovableElementKey,
- transitionStates: List<TransitionState>,
+ transitionStates: List<List<TransitionState>>,
): TransitionState? {
val contents = element.contentPicker.contents
- return elementState(transitionStates, isInContent = { contents.contains(it) })
+ return elementState(
+ transitionStates,
+ elementKey = element,
+ isInContent = { contents.contains(it) },
+ )
}
private fun movableElementContentWhenIdle(
@@ -245,7 +249,7 @@ private fun placeholderContentSize(
content: ContentKey,
element: Element,
elementKey: MovableElementKey,
- transitionStates: List<TransitionState>,
+ transitionStates: List<List<TransitionState>>,
): IntSize {
// If the content of the movable element was already composed in this scene before, use that
// target size.
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index ce385abea627..7b30a2a475e3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -698,7 +698,7 @@ internal fun SceneTransitionLayoutForTesting(
transitionInterceptionThreshold: Float = 0f,
onLayoutImpl: ((SceneTransitionLayoutImpl) -> Unit)? = null,
sharedElementMap: MutableMap<ElementKey, Element> = remember { mutableMapOf() },
- ancestorContentKeys: List<ContentKey> = emptyList(),
+ ancestors: List<Ancestor> = remember { emptyList() },
lookaheadScope: LookaheadScope? = null,
builder: SceneTransitionLayoutScope.() -> Unit,
) {
@@ -715,7 +715,7 @@ internal fun SceneTransitionLayoutForTesting(
builder = builder,
animationScope = animationScope,
elements = sharedElementMap,
- ancestorContentKeys = ancestorContentKeys,
+ ancestors = ancestors,
lookaheadScope = lookaheadScope,
)
.also { onLayoutImpl?.invoke(it) }
@@ -738,9 +738,9 @@ internal fun SceneTransitionLayoutForTesting(
"when creating it, which is not supported"
)
}
- if (layoutImpl.ancestorContentKeys != ancestorContentKeys) {
+ if (layoutImpl.ancestors != ancestors) {
error(
- "This SceneTransitionLayout was bound to a different ancestorContents that was " +
+ "This SceneTransitionLayout was bound to a different ancestors that was " +
"used when creating it, which is not supported"
)
}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index e1cecc750d3d..e5bdc92b5762 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -57,6 +57,18 @@ import kotlinx.coroutines.launch
/** The type for the content of movable elements. */
internal typealias MovableElementContent = @Composable (@Composable () -> Unit) -> Unit
+internal data class Ancestor(
+ val layoutImpl: SceneTransitionLayoutImpl,
+
+ /**
+ * This is the content in which the corresponding descendant of this ancestor appears in.
+ *
+ * Example: When A is the root and has two scenes SA and SB and SB contains a NestedSTL called
+ * B. Then A is the ancestor of B and inContent is SB.
+ */
+ val inContent: ContentKey,
+)
+
@Stable
internal class SceneTransitionLayoutImpl(
internal val state: MutableSceneTransitionLayoutStateImpl,
@@ -83,16 +95,17 @@ internal class SceneTransitionLayoutImpl(
internal val elements: MutableMap<ElementKey, Element> = mutableMapOf(),
/**
- * When this STL is a [NestedSceneTransitionLayout], this is a list of [ContentKey]s of where
- * this STL is composed in within its ancestors.
+ * When this STL is a [NestedSceneTransitionLayout], this is a list of [Ancestor]s which
+ * provides a reference to the ancestor STLs and indicates where this STL is composed in within
+ * its ancestors.
*
* The root STL holds an emptyList. With each nesting level the parent is supposed to add
* exactly one scene to the list, therefore the size of this list is equal to the nesting depth
* of this STL.
*
- * This is used to know in which content of the ancestors a sharedElement appears in.
+ * This is used to enable transformations and shared elements across NestedSTLs.
*/
- internal val ancestorContentKeys: List<ContentKey> = emptyList(),
+ internal val ancestors: List<Ancestor> = emptyList(),
lookaheadScope: LookaheadScope? = null,
) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
index 6479e69a2aac..756d71c1b5cf 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitions.kt
@@ -266,19 +266,26 @@ internal class TransformationSpecImpl(
override val distance: UserActionDistance?,
override val transformationMatchers: List<TransformationMatcher>,
) : TransformationSpec {
- private val cache = mutableMapOf<ElementKey, MutableMap<ContentKey, ElementTransformations>>()
+ private val cache = mutableMapOf<ElementKey, MutableMap<ContentKey, ElementTransformations?>>()
- internal fun transformations(element: ElementKey, content: ContentKey): ElementTransformations {
+ internal fun transformations(
+ element: ElementKey,
+ content: ContentKey,
+ ): ElementTransformations? {
return cache
.getOrPut(element) { mutableMapOf() }
.getOrPut(content) { computeTransformations(element, content) }
}
+ internal fun hasTransformation(element: ElementKey, content: ContentKey): Boolean {
+ return transformations(element, content) != null
+ }
+
/** Filter [transformationMatchers] to compute the [ElementTransformations] of [element]. */
private fun computeTransformations(
element: ElementKey,
content: ContentKey,
- ): ElementTransformations {
+ ): ElementTransformations? {
var shared: TransformationWithRange<SharedElementTransformation>? = null
var offset: TransformationWithRange<PropertyTransformation<Offset>>? = null
var size: TransformationWithRange<PropertyTransformation<IntSize>>? = null
@@ -338,7 +345,13 @@ internal class TransformationSpecImpl(
}
}
- return ElementTransformations(shared, offset, size, drawScale, alpha)
+ return if (
+ shared == null && offset == null && size == null && drawScale == null && alpha == null
+ ) {
+ null
+ } else {
+ ElementTransformations(shared, offset, size, drawScale, alpha)
+ }
}
private fun throwIfNotNull(
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt
index 9de297f3ad5a..ed3a5cac8184 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SharedElement.kt
@@ -81,8 +81,9 @@ internal fun sharedElementTransformation(
): TransformationWithRange<SharedElementTransformation>? {
val transformationSpec = transition.transformationSpec
val sharedInFromContent =
- transformationSpec.transformations(element, transition.fromContent).shared
- val sharedInToContent = transformationSpec.transformations(element, transition.toContent).shared
+ transformationSpec.transformations(element, transition.fromContent)?.shared
+ val sharedInToContent =
+ transformationSpec.transformations(element, transition.toContent)?.shared
// The sharedElement() transformation must either be null or be the same in both contents.
if (sharedInFromContent != sharedInToContent) {
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 3716df5b5a35..8c5a72738a41 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -31,6 +31,7 @@ import androidx.compose.ui.layout.approachLayout
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.zIndex
+import com.android.compose.animation.scene.Ancestor
import com.android.compose.animation.scene.AnimatedState
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.ContentScope
@@ -181,16 +182,17 @@ internal class ContentScopeImpl(
modifier: Modifier,
builder: SceneTransitionLayoutScope.() -> Unit,
) {
+ val ancestors =
+ remember(layoutImpl, contentKey, layoutImpl.ancestors) {
+ layoutImpl.ancestors + Ancestor(layoutImpl, contentKey)
+ }
SceneTransitionLayoutForTesting(
state,
modifier,
onLayoutImpl = null,
builder = builder,
sharedElementMap = layoutImpl.elements,
- ancestorContentKeys =
- remember(layoutImpl.ancestorContentKeys, contentKey) {
- layoutImpl.ancestorContentKeys + contentKey
- },
+ ancestors = ancestors,
lookaheadScope = layoutImpl.lookaheadScope,
)
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
index c69129b38bdd..676903274b38 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/ElementTest.kt
@@ -2208,6 +2208,7 @@ class ElementTest {
}
@Test
+ @Ignore("b/363964445")
fun interruption_considerPreviousUniqueState() {
@Composable
fun SceneScope.Foo(modifier: Modifier = Modifier) {
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt
new file mode 100644
index 000000000000..0da422bcb696
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedElementTransformationTest.kt
@@ -0,0 +1,410 @@
+/*
+ * 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.compose.animation.scene.transformation
+
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.offset
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.test.SemanticsNodeInteraction
+import androidx.compose.ui.test.assertPositionInRootIsEqualTo
+import androidx.compose.ui.test.isNotDisplayed
+import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.Scale
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.SceneTransitions
+import com.android.compose.animation.scene.TestScenes
+import com.android.compose.animation.scene.testNestedTransition
+import com.android.compose.animation.scene.testing.lastAlphaForTesting
+import com.android.compose.animation.scene.testing.lastScaleForTesting
+import com.android.compose.animation.scene.transitions
+import com.android.compose.test.assertSizeIsEqualTo
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class NestedElementTransformationTest {
+ @get:Rule val rule = createComposeRule()
+
+ private object Scenes {
+ val NestedSceneA = SceneKey("NestedSceneA")
+ val NestedSceneB = SceneKey("NestedSceneB")
+ val NestedNestedSceneA = SceneKey("NestedNestedSceneA")
+ val NestedNestedSceneB = SceneKey("NestedNestedSceneB")
+ }
+
+ // Variants are named: nestingDepth + sceneNameSuffix
+ private val elementVariant0A =
+ TestElement(ElementKey("0A"), 0.dp, 0.dp, 100.dp, 100.dp, Color.Red)
+ private val elementVariant0B =
+ TestElement(ElementKey("0B"), 100.dp, 100.dp, 20.dp, 20.dp, Color.Cyan)
+ private val elementVariant1A =
+ TestElement(ElementKey("1A"), 40.dp, 80.dp, 60.dp, 20.dp, Color.Blue)
+ private val elementVariant1B =
+ TestElement(ElementKey("1B"), 80.dp, 40.dp, 140.dp, 180.dp, Color.Yellow)
+ private val elementVariant2A =
+ TestElement(ElementKey("2A"), 120.dp, 240.dp, 20.dp, 140.dp, Color.Green)
+ private val elementVariant2B =
+ TestElement(ElementKey("2B"), 200.dp, 320.dp, 40.dp, 70.dp, Color.Magenta)
+
+ private class TestElement(
+ val key: ElementKey,
+ val x: Dp,
+ val y: Dp,
+ val width: Dp,
+ val height: Dp,
+ val color: Color = Color.Black,
+ val alpha: Float = 0.8f,
+ )
+
+ @Composable
+ private fun ContentScope.TestElement(element: TestElement) {
+ Box(Modifier.fillMaxSize()) {
+ Box(
+ Modifier.offset(element.x, element.y)
+ .element(element.key)
+ .size(element.width, element.height)
+ .background(element.color)
+ .alpha(element.alpha)
+ )
+ }
+ }
+
+ private fun createState(
+ startScene: SceneKey,
+ transitions: SceneTransitions = SceneTransitions.Empty,
+ ): MutableSceneTransitionLayoutState {
+ return rule.runOnUiThread { MutableSceneTransitionLayoutState(startScene, transitions) }
+ }
+
+ private val threeNestedStls:
+ @Composable
+ (states: List<MutableSceneTransitionLayoutState>) -> Unit =
+ { states ->
+ SceneTransitionLayout(states[0]) {
+ scene(TestScenes.SceneA, content = { TestElement(elementVariant0A) })
+ scene(
+ TestScenes.SceneB,
+ content = {
+ Box(Modifier.fillMaxSize()) {
+ TestElement(elementVariant0B)
+ NestedSceneTransitionLayout(states[1], modifier = Modifier) {
+ scene(Scenes.NestedSceneA) {
+ Box(Modifier.fillMaxSize()) {
+ TestElement(elementVariant1A)
+ NestedSceneTransitionLayout(
+ state = states[2],
+ modifier = Modifier,
+ ) {
+ scene(Scenes.NestedNestedSceneA) {
+ TestElement(elementVariant2A)
+ }
+ scene(Scenes.NestedNestedSceneB) {
+ TestElement(elementVariant2B)
+ }
+ }
+ }
+ }
+ scene(Scenes.NestedSceneB) { TestElement(elementVariant1B) }
+ }
+ }
+ },
+ )
+ }
+ }
+
+ @Test
+ fun transitionInNestedNestedStl_transitionsOut() {
+ rule.testNestedTransition(
+ states =
+ listOf(
+ createState(TestScenes.SceneB),
+ createState(Scenes.NestedSceneA),
+ createState(
+ Scenes.NestedNestedSceneA,
+ transitions {
+ from(from = Scenes.NestedNestedSceneA, to = Scenes.NestedNestedSceneB) {
+ spec = tween(16 * 4, easing = LinearEasing)
+ translate(elementVariant2A.key, x = 100.dp, y = 50.dp)
+ scaleSize(elementVariant2A.key, width = 2f, height = 0.5f)
+ scaleDraw(elementVariant2A.key, scaleX = 4f, scaleY = 0.25f)
+ fade(elementVariant2A.key)
+ }
+ },
+ ),
+ ),
+ transitionLayout = threeNestedStls,
+ changeState = { it[2].setTargetScene(Scenes.NestedNestedSceneB, this) },
+ ) {
+ before { onElement(elementVariant2A.key).assertElementVariant(elementVariant2A) }
+ atAllFrames(4) {
+ onElement(elementVariant2A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant2A.x, elementVariant2A.x + 100.dp),
+ interpolate(elementVariant2A.y, elementVariant2A.y + 50.dp),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant2A.width, elementVariant2A.width * 2f),
+ interpolate(elementVariant2A.height, elementVariant2A.height * 0.5f),
+ )
+ val semanticNode = onElement(elementVariant2A.key).fetchSemanticsNode()
+ assertThat(semanticNode.lastAlphaForTesting).isEqualTo(interpolate(1f, 0f))
+ assertThat(semanticNode.lastScaleForTesting)
+ .isEqualTo(interpolate(Scale(1f, 1f), Scale(4f, 0.25f)))
+ }
+ after { onElement(elementVariant2A.key).isNotDisplayed() }
+ }
+ }
+
+ @Test
+ fun transitionInNestedNestedStl_transitionsIn() {
+ rule.testNestedTransition(
+ states =
+ listOf(
+ createState(TestScenes.SceneB),
+ createState(Scenes.NestedSceneA),
+ createState(
+ Scenes.NestedNestedSceneB,
+ transitions {
+ from(from = Scenes.NestedNestedSceneB) {
+ spec = tween(16 * 4, easing = LinearEasing)
+ translate(elementVariant2A.key, x = 100.dp, y = 50.dp)
+ scaleSize(elementVariant2A.key, width = 2f, height = 0.5f)
+ }
+ },
+ ),
+ ),
+ transitionLayout = threeNestedStls,
+ changeState = { it[2].setTargetScene(Scenes.NestedNestedSceneA, this) },
+ ) {
+ before { onElement(elementVariant2A.key).isNotDisplayed() }
+ atAllFrames(4) {
+ onElement(elementVariant2A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant2A.x + 100.dp, elementVariant2A.x),
+ interpolate(elementVariant2A.y + 50.dp, elementVariant2A.y),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant2A.width * 2f, elementVariant2A.width),
+ interpolate(elementVariant2A.height * 0.5f, elementVariant2A.height),
+ )
+ }
+ after { onElement(elementVariant2A.key).assertElementVariant(elementVariant2A) }
+ }
+ }
+
+ @Test
+ fun transitionInNestedStl_elementInNestedNestedStl_transitionsIn() {
+ rule.testNestedTransition(
+ states =
+ listOf(
+ createState(TestScenes.SceneB),
+ createState(
+ Scenes.NestedSceneB,
+ transitions {
+ from(from = Scenes.NestedSceneB, to = Scenes.NestedSceneA) {
+ spec = tween(16 * 4, easing = LinearEasing)
+ translate(elementVariant2A.key, x = 100.dp, y = 50.dp)
+ scaleSize(elementVariant2A.key, width = 2f, height = 0.5f)
+ }
+ },
+ ),
+ createState(Scenes.NestedNestedSceneA),
+ ),
+ transitionLayout = threeNestedStls,
+ changeState = { it[1].setTargetScene(Scenes.NestedSceneA, this) },
+ ) {
+ before { onElement(elementVariant2A.key).isNotDisplayed() }
+ atAllFrames(4) {
+ onElement(elementVariant2A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant2A.x + 100.dp, elementVariant2A.x),
+ interpolate(elementVariant2A.y + 50.dp, elementVariant2A.y),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant2A.width * 2f, elementVariant2A.width),
+ interpolate(elementVariant2A.height * 0.5f, elementVariant2A.height),
+ )
+ }
+ after { onElement(elementVariant2A.key).assertElementVariant(elementVariant2A) }
+ }
+ }
+
+ @Test
+ fun transitionInRootStl_elementsInAllLayers_transitionInAndOut() {
+ rule.testNestedTransition(
+ states =
+ listOf(
+ createState(
+ TestScenes.SceneB,
+ transitions {
+ to(to = TestScenes.SceneA) {
+ spec = tween(16 * 4, easing = LinearEasing)
+
+ // transitions out
+ translate(elementVariant2A.key, x = 100.dp, y = 50.dp)
+ scaleSize(elementVariant2A.key, width = 2f, height = 0.5f)
+
+ // transitions out
+ translate(elementVariant0B.key, x = 200.dp, y = 20.dp)
+ scaleSize(elementVariant0B.key, width = 3f, height = 0.2f)
+
+ // transitions out
+ translate(elementVariant1A.key, x = 300.dp, y = 10.dp)
+ scaleSize(elementVariant1A.key, width = 4f, height = 0.1f)
+
+ // transitions in
+ translate(elementVariant0A.key, x = 400.dp, y = 40.dp)
+ scaleSize(elementVariant0A.key, width = 0.5f, height = 2f)
+ }
+ },
+ ),
+ createState(Scenes.NestedSceneA),
+ createState(Scenes.NestedNestedSceneA),
+ ),
+ transitionLayout = threeNestedStls,
+ changeState = { it[0].setTargetScene(TestScenes.SceneA, this) },
+ ) {
+ before {
+ onElement(elementVariant2A.key).assertElementVariant(elementVariant2A)
+ onElement(elementVariant0B.key).assertElementVariant(elementVariant0B)
+ onElement(elementVariant1A.key).assertElementVariant(elementVariant1A)
+ onElement(elementVariant0A.key).isNotDisplayed()
+ }
+ atAllFrames(4) {
+ onElement(elementVariant2A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant2A.x, elementVariant2A.x + 100.dp),
+ interpolate(elementVariant2A.y, elementVariant2A.y + 50.dp),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant2A.width, elementVariant2A.width * 2f),
+ interpolate(elementVariant2A.height, elementVariant2A.height * 0.5f),
+ )
+
+ onElement(elementVariant0B.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant0B.x, elementVariant0B.x + 200.dp),
+ interpolate(elementVariant0B.y, elementVariant0B.y + 20.dp),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant0B.width, elementVariant0B.width * 3f),
+ interpolate(elementVariant0B.height, elementVariant0B.height * 0.2f),
+ )
+
+ onElement(elementVariant1A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant1A.x, elementVariant1A.x + 300.dp),
+ interpolate(elementVariant1A.y, elementVariant1A.y + 10.dp),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant1A.width, elementVariant1A.width * 4f),
+ interpolate(elementVariant1A.height, elementVariant1A.height * 0.1f),
+ )
+
+ onElement(elementVariant0A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant0A.x + 400.dp, elementVariant0A.x),
+ interpolate(elementVariant0A.y + 40.dp, elementVariant0A.y),
+ )
+ .assertSizeIsEqualTo(
+ interpolate(elementVariant0A.width * 0.5f, elementVariant0A.width),
+ interpolate(elementVariant0A.height * 2f, elementVariant0A.height),
+ )
+ }
+ after {
+ onElement(elementVariant2A.key).isNotDisplayed()
+ onElement(elementVariant0B.key).isNotDisplayed()
+ onElement(elementVariant1A.key).isNotDisplayed()
+ onElement(elementVariant0A.key).assertElementVariant(elementVariant0A)
+ }
+ }
+ }
+
+ @Test
+ fun transitionInMultipleStls_rootIsTakingControl() {
+ rule.testNestedTransition(
+ states =
+ listOf(
+ createState(
+ TestScenes.SceneB,
+ transitions {
+ to(to = TestScenes.SceneA) {
+ spec = tween(16 * 4, easing = LinearEasing)
+ translate(elementVariant2A.key, x = 100.dp, y = 50.dp)
+ }
+ },
+ ),
+ createState(
+ Scenes.NestedSceneA,
+ transitions {
+ to(to = Scenes.NestedSceneB) {
+ spec = tween(16 * 4, easing = LinearEasing)
+ translate(elementVariant2A.key, x = 200.dp, y = 150.dp)
+ }
+ },
+ ),
+ createState(
+ Scenes.NestedNestedSceneA,
+ transitions {
+ to(to = Scenes.NestedNestedSceneB) {
+ spec = tween(16 * 4, easing = LinearEasing)
+ translate(elementVariant2A.key, x = 300.dp, y = 250.dp)
+ }
+ },
+ ),
+ ),
+ transitionLayout = threeNestedStls,
+ changeState = {
+ it[2].setTargetScene(Scenes.NestedNestedSceneB, this)
+ it[1].setTargetScene(Scenes.NestedSceneB, this)
+ it[0].setTargetScene(TestScenes.SceneA, this)
+ },
+ ) {
+ before { onElement(elementVariant2A.key).assertElementVariant(elementVariant2A) }
+ atAllFrames(4) {
+ onElement(elementVariant2A.key)
+ .assertPositionInRootIsEqualTo(
+ interpolate(elementVariant2A.x, elementVariant2A.x + 100.dp),
+ interpolate(elementVariant2A.y, elementVariant2A.y + 50.dp),
+ )
+ }
+ after { onElement(elementVariant2A.key).isNotDisplayed() }
+ }
+ }
+
+ private fun SemanticsNodeInteraction.assertElementVariant(variant: TestElement) {
+ assertPositionInRootIsEqualTo(variant.x, variant.y)
+ assertSizeIsEqualTo(variant.width, variant.height)
+ }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt
index c6ef8cff1a66..d8b713625681 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/NestedSharedElementTest.kt
@@ -61,7 +61,7 @@ class NestedSharedElementTest {
val NestedNestedSceneB = SceneKey("NestedNestedSceneB")
}
- private val elementVariant1 = SharedElement(0.dp, 0.dp, 100.dp, 100.dp, Color.Red)
+ private val elementVariant1 = SharedElement(100.dp, 100.dp, 100.dp, 100.dp, Color.Red)
private val elementVariant2 = SharedElement(40.dp, 80.dp, 60.dp, 20.dp, Color.Blue)
private val elementVariant3 = SharedElement(80.dp, 40.dp, 140.dp, 180.dp, Color.Yellow)
private val elementVariant4 = SharedElement(120.dp, 240.dp, 20.dp, 140.dp, Color.Green)
@@ -223,7 +223,8 @@ class NestedSharedElementTest {
// In SceneA, Foo leaves to the left edge.
translate(TestElements.Foo.inScene(TestScenes.SceneA), Edge.Left, false)
- // We can't reference the element inside the NestedSTL as of today
+ // In NestedSceneA, Foo comes in from the top edge.
+ translate(TestElements.Foo.inScene(Scenes.NestedSceneA), Edge.Top, false)
},
) {
before { onElement(TestElements.Foo).assertElementVariant(elementVariant1) }
@@ -234,6 +235,11 @@ class NestedSharedElementTest {
elementVariant1.y,
)
.assertSizeIsEqualTo(elementVariant1.width, elementVariant1.height)
+ onElement(TestElements.Foo, scene = Scenes.NestedSceneA)
+ .assertPositionInRootIsEqualTo(
+ elementVariant2.x,
+ interpolate(0.dp, elementVariant2.y),
+ )
}
after { onElement(TestElements.Foo).assertElementVariant(elementVariant2) }
}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
index 47c10f5ab3a3..0dd08d92eb41 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/SharedElementTest.kt
@@ -18,11 +18,13 @@ package com.android.compose.animation.scene.transformation
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.size
import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.test.assertIsNotDisplayed
import androidx.compose.ui.test.assertPositionInRootIsEqualTo
import androidx.compose.ui.test.junit4.createComposeRule
@@ -47,11 +49,21 @@ class SharedElementTest {
rule.testTransition(
fromSceneContent = {
// Foo is at (10, 50) with a size of (20, 80).
- Box(Modifier.offset(10.dp, 50.dp).element(TestElements.Foo).size(20.dp, 80.dp))
+ Box(
+ Modifier.offset(10.dp, 50.dp)
+ .element(TestElements.Foo)
+ .size(20.dp, 80.dp)
+ .background(Color.Red)
+ )
},
toSceneContent = {
// Foo is at (50, 70) with a size of (10, 40).
- Box(Modifier.offset(50.dp, 70.dp).element(TestElements.Foo).size(10.dp, 40.dp))
+ Box(
+ Modifier.offset(50.dp, 70.dp)
+ .element(TestElements.Foo)
+ .size(10.dp, 40.dp)
+ .background(Color.Blue)
+ )
},
transition = {
spec = tween(16 * 4, easing = LinearEasing)
@@ -88,13 +100,23 @@ class SharedElementTest {
fromSceneContent = {
Box(Modifier.fillMaxSize()) {
// Foo is at (10, 50).
- Box(Modifier.offset(10.dp, 50.dp).element(TestElements.Foo))
+ Box(
+ Modifier.offset(10.dp, 50.dp)
+ .element(TestElements.Foo)
+ .size(20.dp)
+ .background(Color.Red)
+ )
}
},
toSceneContent = {
Box(Modifier.fillMaxSize()) {
// Foo is at (50, 60).
- Box(Modifier.offset(50.dp, 60.dp).element(TestElements.Foo))
+ Box(
+ Modifier.offset(50.dp, 60.dp)
+ .element(TestElements.Foo)
+ .size(20.dp)
+ .background(Color.Blue)
+ )
}
},
transition = {
@@ -104,7 +126,11 @@ class SharedElementTest {
sharedElement(TestElements.Foo, enabled = false)
// In SceneA, Foo leaves to the left edge.
- translate(TestElements.Foo.inScene(TestScenes.SceneA), Edge.Left)
+ translate(
+ TestElements.Foo.inScene(TestScenes.SceneA),
+ Edge.Left,
+ startsOutsideLayoutBounds = false,
+ )
// In SceneB, Foo comes from the bottom edge.
translate(TestElements.Foo.inScene(TestScenes.SceneB), Edge.Bottom)
diff --git a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
index 124b61e45ed6..bc160fc02498 100644
--- a/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
+++ b/packages/SystemUI/compose/scene/tests/utils/src/com/android/compose/animation/scene/TestTransition.kt
@@ -25,6 +25,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.semantics.SemanticsNode
import androidx.compose.ui.test.SemanticsNodeInteraction
import androidx.compose.ui.test.SemanticsNodeInteractionsProvider
@@ -63,6 +64,9 @@ interface TransitionTestBuilder {
* Important: [timestamp] must be a multiple of 16 (the duration of a frame on the JVM/Android).
* There is no intermediary state between `t` and `t + 16` , so testing transitions outside of
* `t = 0`, `t = 16`, `t = 32`, etc does not make sense.
+ *
+ * @param builder the builder can run assertions and is passed the CoroutineScope such that the
+ * test can start transitions at any desired point in time.
*/
fun at(timestamp: Long, builder: TransitionTestAssertionScope.() -> Unit)
@@ -85,7 +89,7 @@ interface TransitionTestBuilder {
}
@TransitionTestDsl
-interface TransitionTestAssertionScope {
+interface TransitionTestAssertionScope : CoroutineScope {
/**
* Assert on [element].
*
@@ -312,6 +316,20 @@ fun ComposeContentTestRule.testTransition(
)
}
+fun ComposeContentTestRule.testNestedTransition(
+ states: List<MutableSceneTransitionLayoutState>,
+ changeState: CoroutineScope.(states: List<MutableSceneTransitionLayoutState>) -> Unit,
+ transitionLayout: @Composable (states: List<MutableSceneTransitionLayoutState>) -> Unit,
+ builder: TransitionTestBuilder.() -> Unit,
+) {
+ testTransition(
+ state = states[0],
+ changeState = { changeState(states) },
+ transitionLayout = { transitionLayout(states) },
+ builder = builder,
+ )
+}
+
/** Test the transition from [state] to [to]. */
fun ComposeContentTestRule.testTransition(
state: MutableSceneTransitionLayoutState,
@@ -319,9 +337,15 @@ fun ComposeContentTestRule.testTransition(
transitionLayout: @Composable (state: MutableSceneTransitionLayoutState) -> Unit,
builder: TransitionTestBuilder.() -> Unit,
) {
- val test = transitionTest(builder)
+ lateinit var coroutineScope: CoroutineScope
+ setContent {
+ coroutineScope = rememberCoroutineScope()
+ transitionLayout(state)
+ }
+
val assertionScope =
- object : AutoTransitionTestAssertionScope {
+ object : AutoTransitionTestAssertionScope, CoroutineScope by coroutineScope {
+
var progress = 0f
override fun onElement(
@@ -338,6 +362,16 @@ fun ComposeContentTestRule.testTransition(
from is Int && to is Int -> lerp(from, to, progress)
from is Long && to is Long -> lerp(from, to, progress)
from is Dp && to is Dp -> lerp(from, to, progress)
+ from is Scale && to is Scale ->
+ Scale(
+ lerp(from.scaleX, to.scaleX, progress),
+ lerp(from.scaleY, to.scaleY, progress),
+ interpolate(from.pivot, to.pivot),
+ )
+
+ from is Offset && to is Offset ->
+ Offset(lerp(from.x, to.x, progress), lerp(from.y, to.y, progress))
+
else ->
throw UnsupportedOperationException(
"Interpolation not supported for this type"
@@ -347,14 +381,9 @@ fun ComposeContentTestRule.testTransition(
}
}
- lateinit var coroutineScope: CoroutineScope
- setContent {
- coroutineScope = rememberCoroutineScope()
- transitionLayout(state)
- }
-
// Wait for the UI to be idle then test the before state.
waitForIdle()
+ val test = transitionTest(builder)
test.before(assertionScope)
// Manually advance the clock to the start of the animation.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
index 714461b715d6..daebf131062e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/BiometricDisplayListenerTest.java
@@ -88,7 +88,7 @@ public class BiometricDisplayListenerTest extends SysuiTestCase {
listener.enable();
verify(mDisplayManager).registerDisplayListener(any(), same(mHandler),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED));
}
@Test
@@ -112,7 +112,7 @@ public class BiometricDisplayListenerTest extends SysuiTestCase {
// The listener should register a display listener.
verify(mDisplayManager).registerDisplayListener(mDisplayListenerCaptor.capture(),
- same(mHandler), eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED));
+ same(mHandler), eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED));
// mOnChangedCallback should be invoked for all calls to onDisplayChanged.
mDisplayListenerCaptor.getValue().onDisplayChanged(123);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
index f4cffc5d962a..2e8efdb8c84b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/brightness/data/repository/ScreenBrightnessDisplayManagerRepositoryTest.kt
@@ -20,7 +20,7 @@ import android.hardware.display.BrightnessInfo
import android.hardware.display.BrightnessInfo.BRIGHTNESS_MAX_REASON_NONE
import android.hardware.display.BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF
import android.hardware.display.DisplayManager
-import android.hardware.display.DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS
+import android.hardware.display.DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS
import android.view.Display
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -120,7 +120,7 @@ class ScreenBrightnessDisplayManagerRepositoryTest : SysuiTestCase() {
capture(listenerCaptor),
eq(null),
eq(0),
- eq(PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS),
+ eq(PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS),
)
val newBrightness = BrightnessInfo(0.6f, 0.3f, 0.9f)
@@ -159,7 +159,7 @@ class ScreenBrightnessDisplayManagerRepositoryTest : SysuiTestCase() {
capture(listenerCaptor),
eq(null),
eq(0),
- eq(PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS),
+ eq(PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS),
)
changeBrightnessInfoAndNotify(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
index e6e5665e7694..c585d5c56a4e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/DisplayRepositoryTest.kt
@@ -541,7 +541,7 @@ class DisplayRepositoryTest : SysuiTestCase() {
connectedDisplayListener.capture(),
eq(testHandler),
eq(0),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED),
)
return flowValue
}
@@ -558,9 +558,9 @@ class DisplayRepositoryTest : SysuiTestCase() {
displayListener.capture(),
eq(testHandler),
eq(
- DisplayManager.EVENT_FLAG_DISPLAY_ADDED or
- DisplayManager.EVENT_FLAG_DISPLAY_CHANGED or
- DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
+ DisplayManager.EVENT_TYPE_DISPLAY_ADDED or
+ DisplayManager.EVENT_TYPE_DISPLAY_CHANGED or
+ DisplayManager.EVENT_TYPE_DISPLAY_REMOVED
),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt
index 77be8c718b14..6ec38ba171c3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepositoryTest.kt
@@ -16,8 +16,9 @@
package com.android.systemui.mediarouter.data.repository
-import androidx.test.filters.SmallTest
+import android.media.projection.StopReason
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.Kosmos
@@ -101,7 +102,7 @@ class MediaRouterRepositoryTest : SysuiTestCase() {
origin = CastDevice.CastOrigin.MediaRouter,
)
- underTest.stopCasting(device)
+ underTest.stopCasting(device, StopReason.STOP_UNKNOWN)
assertThat(castController.lastStoppedDevice).isEqualTo(device)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java
index 9f12b189d76a..31a627fe0667 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/CastTileTest.java
@@ -20,6 +20,7 @@ import static junit.framework.Assert.assertTrue;
import static junit.framework.TestCase.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.mock;
@@ -30,6 +31,7 @@ import static org.mockito.Mockito.when;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
import android.media.projection.MediaProjectionInfo;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.service.quicksettings.Tile;
import android.testing.TestableLooper;
@@ -336,7 +338,8 @@ public class CastTileTest extends SysuiTestCase {
mCastTile.handleClick(null /* view */);
mTestableLooper.processAllMessages();
- verify(mController, times(1)).stopCasting(same(device));
+ verify(mController, times(1))
+ .stopCasting(same(device), eq(StopReason.STOP_QS_TILE));
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
index 0fd7c9876f25..fc1d73b62abd 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java
@@ -27,11 +27,13 @@ import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.Dialog;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.platform.test.flag.junit.FlagsParameterization;
import android.service.quicksettings.Tile;
@@ -234,7 +236,7 @@ public class ScreenRecordTileTest extends SysuiTestCase {
mTile.handleClick(null /* view */);
- verify(mController, times(1)).stopRecording();
+ verify(mController, times(1)).stopRecording(eq(StopReason.STOP_QS_TILE));
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
index 0b56d7b64aab..778c73fd8638 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractorTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor
import android.app.Dialog
+import android.media.projection.StopReason
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
@@ -92,7 +93,7 @@ class ScreenRecordTileUserActionInteractorTest : SysuiTestCase() {
underTest.handleInput(QSTileInputTestKtx.click(recordingModel))
- verify(recordingController).stopRecording()
+ verify(recordingController).stopRecording(eq(StopReason.STOP_QS_TILE))
}
@Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index a6a1d4a05dc7..50fa9d29659d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -41,6 +41,7 @@ import android.app.ActivityOptions.LaunchCookie;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Intent;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -199,16 +200,16 @@ public class RecordingServiceTest extends SysuiTestCase {
public void testOnSystemRequestedStop_recordingInProgress_endsRecording() throws IOException {
doReturn(true).when(mController).isRecording();
- mRecordingService.onStopped();
+ mRecordingService.onStopped(StopReason.STOP_UNKNOWN);
- verify(mScreenMediaRecorder).end();
+ verify(mScreenMediaRecorder).end(eq(StopReason.STOP_UNKNOWN));
}
@Test
public void testOnSystemRequestedStop_recordingInProgress_updatesState() {
doReturn(true).when(mController).isRecording();
- mRecordingService.onStopped();
+ mRecordingService.onStopped(StopReason.STOP_UNKNOWN);
assertUpdateState(false);
}
@@ -218,18 +219,18 @@ public class RecordingServiceTest extends SysuiTestCase {
throws IOException {
doReturn(false).when(mController).isRecording();
- mRecordingService.onStopped();
+ mRecordingService.onStopped(StopReason.STOP_UNKNOWN);
- verify(mScreenMediaRecorder, never()).end();
+ verify(mScreenMediaRecorder, never()).end(StopReason.STOP_UNKNOWN);
}
@Test
public void testOnSystemRequestedStop_recorderEndThrowsRuntimeException_releasesRecording()
throws IOException {
doReturn(true).when(mController).isRecording();
- doThrow(new RuntimeException()).when(mScreenMediaRecorder).end();
+ doThrow(new RuntimeException()).when(mScreenMediaRecorder).end(StopReason.STOP_UNKNOWN);
- mRecordingService.onStopped();
+ mRecordingService.onStopped(StopReason.STOP_UNKNOWN);
verify(mScreenMediaRecorder).release();
}
@@ -238,7 +239,7 @@ public class RecordingServiceTest extends SysuiTestCase {
public void testOnSystemRequestedStop_whenRecordingInProgress_showsNotifications() {
doReturn(true).when(mController).isRecording();
- mRecordingService.onStopped();
+ mRecordingService.onStopped(StopReason.STOP_UNKNOWN);
// Processing notification
ArgumentCaptor<Notification> notifCaptor = ArgumentCaptor.forClass(Notification.class);
@@ -271,9 +272,9 @@ public class RecordingServiceTest extends SysuiTestCase {
public void testOnSystemRequestedStop_recorderEndThrowsRuntimeException_showsErrorNotification()
throws IOException {
doReturn(true).when(mController).isRecording();
- doThrow(new RuntimeException()).when(mScreenMediaRecorder).end();
+ doThrow(new RuntimeException()).when(mScreenMediaRecorder).end(anyInt());
- mRecordingService.onStopped();
+ mRecordingService.onStopped(StopReason.STOP_UNKNOWN);
verify(mRecordingService).createErrorSavingNotification(any());
ArgumentCaptor<Notification> notifCaptor = ArgumentCaptor.forClass(Notification.class);
@@ -289,9 +290,9 @@ public class RecordingServiceTest extends SysuiTestCase {
public void testOnSystemRequestedStop_recorderEndThrowsOOMError_releasesRecording()
throws IOException {
doReturn(true).when(mController).isRecording();
- doThrow(new OutOfMemoryError()).when(mScreenMediaRecorder).end();
+ doThrow(new OutOfMemoryError()).when(mScreenMediaRecorder).end(anyInt());
- assertThrows(Throwable.class, () -> mRecordingService.onStopped());
+ assertThrows(Throwable.class, () -> mRecordingService.onStopped(StopReason.STOP_UNKNOWN));
verify(mScreenMediaRecorder).release();
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
index aceea909e595..ade5941d010d 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepositoryTest.kt
@@ -16,6 +16,7 @@
package com.android.systemui.screenrecord.data.repository
+import android.media.projection.StopReason
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
@@ -31,6 +32,7 @@ import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -126,8 +128,8 @@ class ScreenRecordRepositoryTest : SysuiTestCase() {
@Test
fun stopRecording_invokesController() =
testScope.runTest {
- underTest.stopRecording()
+ underTest.stopRecording(StopReason.STOP_PRIVACY_CHIP)
- verify(recordingController).stopRecording()
+ verify(recordingController).stopRecording(eq(StopReason.STOP_PRIVACY_CHIP))
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
index 40f13bbbf908..17076b4d7505 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModelTest.kt
@@ -306,12 +306,13 @@ class NotifChipsViewModelTest : SysuiTestCase() {
@Test
@EnableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
- fun chips_basicTime_hiddenIfAutomaticallyPromoted() =
+ fun chips_basicTime_timeHiddenIfAutomaticallyPromoted() =
kosmos.runTest {
val latest by collectLastValue(underTest.chips)
val promotedContentBuilder =
PromotedNotificationContentModel.Builder("notif").apply {
+ this.wasPromotedAutomatically = true
this.time =
PromotedNotificationContentModel.When(
time = 6543L,
@@ -334,6 +335,36 @@ class NotifChipsViewModelTest : SysuiTestCase() {
}
@Test
+ @EnableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
+ fun chips_basicTime_timeShownIfNotAutomaticallyPromoted() =
+ kosmos.runTest {
+ val latest by collectLastValue(underTest.chips)
+
+ val promotedContentBuilder =
+ PromotedNotificationContentModel.Builder("notif").apply {
+ this.wasPromotedAutomatically = false
+ this.time =
+ PromotedNotificationContentModel.When(
+ time = 6543L,
+ mode = PromotedNotificationContentModel.When.Mode.BasicTime,
+ )
+ }
+ setNotifs(
+ listOf(
+ activeNotificationModel(
+ key = "notif",
+ statusBarChipIcon = mock<StatusBarIconView>(),
+ promotedContent = promotedContentBuilder.build(),
+ )
+ )
+ )
+
+ assertThat(latest).hasSize(1)
+ assertThat(latest!![0])
+ .isInstanceOf(OngoingActivityChipModel.Shown.ShortTimeDelta::class.java)
+ }
+
+ @Test
@DisableFlags(FLAG_PROMOTE_NOTIFICATIONS_AUTOMATICALLY)
fun chips_basicTime_isShortTimeDelta() =
kosmos.runTest {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
index 5fbdfbf17df4..0c992e0b348b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipBackgroundContainerTest.kt
@@ -40,7 +40,7 @@ class ChipBackgroundContainerTest : SysuiTestCase() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
val chipView =
- LayoutInflater.from(context).inflate(R.layout.ongoing_activity_chip, null)
+ LayoutInflater.from(context).inflate(R.layout.ongoing_activity_chip_primary, null)
underTest = chipView.requireViewById(R.id.ongoing_activity_chip_background)
}
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
index 6f7711759603..9483f6df05f5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/view/ChipChronometerTest.kt
@@ -48,7 +48,7 @@ class ChipChronometerTest : SysuiTestCase() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
val chipView =
- LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
+ LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip_primary, null)
textView = chipView.findViewById(R.id.ongoing_activity_chip_time)!!
measureTextView()
calculateDoesNotFixText()
@@ -161,7 +161,7 @@ class ChipChronometerTest : SysuiTestCase() {
private fun measureTextView() {
textView.measure(
View.MeasureSpec.makeMeasureSpec(TEXT_VIEW_MAX_WIDTH, View.MeasureSpec.AT_MOST),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
index 26c6eb5dc47a..92271198cac0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
@@ -35,6 +35,7 @@ import com.android.systemui.SysuiTestCase
import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.promoted.AutomaticPromotionCoordinator.Companion.EXTRA_WAS_AUTOMATICALLY_PROMOTED
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style
import com.android.systemui.testKosmos
@@ -110,6 +111,26 @@ class PromotedNotificationContentExtractorImplTest : SysuiTestCase() {
@Test
@EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+ fun extractContent_wasPromotedAutomatically_false() {
+ val entry = createEntry { extras.putBoolean(EXTRA_WAS_AUTOMATICALLY_PROMOTED, false) }
+
+ val content = extractContent(entry)
+
+ assertThat(content!!.wasPromotedAutomatically).isFalse()
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+ fun extractContent_wasPromotedAutomatically_true() {
+ val entry = createEntry { extras.putBoolean(EXTRA_WAS_AUTOMATICALLY_PROMOTED, true) }
+
+ val content = extractContent(entry)
+
+ assertThat(content!!.wasPromotedAutomatically).isTrue()
+ }
+
+ @Test
+ @EnableFlags(PromotedNotificationUi.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
@DisableFlags(android.app.Flags.FLAG_API_RICH_ONGOING)
fun extractContent_apiFlagOff_shortCriticalTextNotExtracted() {
val entry = createEntry { setShortCriticalText(TEST_SHORT_CRITICAL_TEXT) }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
index f76ee5e3ebc9..cd3539d6b9a5 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaListenerTest.kt
@@ -114,7 +114,8 @@ class OngoingCallControllerViaListenerTest : SysuiTestCase() {
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
+ chipView =
+ LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip_primary, null)
}
MockitoAnnotations.initMocks(this)
@@ -498,7 +499,7 @@ class OngoingCallControllerViaListenerTest : SysuiTestCase() {
lateinit var newChipView: View
TestableLooper.get(this).runWithLooper {
newChipView =
- LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
+ LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip_primary, null)
}
// Change the chip view associated with the controller.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
index 647b5f86fcee..cf512cdee800 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallControllerViaRepoTest.kt
@@ -29,7 +29,6 @@ import android.widget.LinearLayout
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.Flags.FLAG_STATUS_BAR_CALL_CHIP_NOTIFICATION_ICON
-import com.android.systemui.Flags.FLAG_STATUS_BAR_CHIPS_MODERNIZATION
import com.android.systemui.Flags.FLAG_STATUS_BAR_SCREEN_SHARING_CHIPS
import com.android.systemui.Flags.FLAG_STATUS_BAR_USE_REPOS_FOR_CALL_CHIP
import com.android.systemui.SysuiTestCase
@@ -104,7 +103,8 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
fun setUp() {
allowTestableLooperAsMainThread()
TestableLooper.get(this).runWithLooper {
- chipView = LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
+ chipView =
+ LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip_primary, null)
}
whenever(mockStatusBarWindowControllerStore.defaultDisplay)
@@ -134,12 +134,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
testScope.runCurrent()
reset(mockOngoingCallListener)
- whenever(
- mockIActivityManager.getUidProcessState(
- eq(CALL_UID),
- any(),
- )
- )
+ whenever(mockIActivityManager.getUidProcessState(eq(CALL_UID), any()))
.thenReturn(PROC_STATE_INVISIBLE)
}
@@ -225,38 +220,18 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
@Test
fun notifRepoHasOngoingCallNotifThenScreeningNotif_listenerNotifiedTwice() {
- setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Ongoing,
- )
- )
+ setNotifOnRepo(activeNotificationModel(key = "notif", callType = CallType.Ongoing))
- setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Screening,
- )
- )
+ setNotifOnRepo(activeNotificationModel(key = "notif", callType = CallType.Screening))
verify(mockOngoingCallListener, times(2)).onOngoingCallStateChanged(any())
}
@Test
fun notifRepoHasOngoingCallNotifThenScreeningNotif_repoUpdated() {
- setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Ongoing,
- )
- )
+ setNotifOnRepo(activeNotificationModel(key = "notif", callType = CallType.Ongoing))
- setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Screening,
- )
- )
+ setNotifOnRepo(activeNotificationModel(key = "notif", callType = CallType.Screening))
assertThat(ongoingCallRepository.ongoingCallState.value)
.isInstanceOf(OngoingCallModel.NoCall::class.java)
@@ -289,7 +264,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
)
assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
@@ -309,7 +284,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
chipView.measure(
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
- View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
+ View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
)
assertThat(chipView.findViewById<View>(R.id.ongoing_activity_chip_time)?.measuredWidth)
@@ -323,11 +298,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
// Re-create the notification each time so that it's considered a different object and
// will re-trigger the whole flow.
setNotifOnRepo(
- activeNotificationModel(
- key = "notif$i",
- callType = CallType.Ongoing,
- whenTime = 44,
- )
+ activeNotificationModel(key = "notif$i", callType = CallType.Ongoing, whenTime = 44)
)
}
@@ -337,12 +308,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
/** Regression test for b/216248574. */
@Test
fun repoHasCallNotif_getUidProcessStateThrowsException_noCrash() {
- whenever(
- mockIActivityManager.getUidProcessState(
- eq(CALL_UID),
- any(),
- )
- )
+ whenever(mockIActivityManager.getUidProcessState(eq(CALL_UID), any()))
.thenThrow(SecurityException())
// No assert required, just check no crash
@@ -352,14 +318,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
/** Regression test for b/216248574. */
@Test
fun repoHasCallNotif_registerUidObserverThrowsException_noCrash() {
- whenever(
- mockIActivityManager.registerUidObserver(
- any(),
- any(),
- any(),
- any(),
- )
- )
+ whenever(mockIActivityManager.registerUidObserver(any(), any(), any(), any()))
.thenThrow(SecurityException())
// No assert required, just check no crash
@@ -416,11 +375,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
@Test
fun hasOngoingCall_repoHasUnrelatedNotif_returnsFalse() {
setNotifOnRepo(
- activeNotificationModel(
- key = "unrelated",
- callType = CallType.None,
- uid = CALL_UID,
- )
+ activeNotificationModel(key = "unrelated", callType = CallType.None, uid = CALL_UID)
)
assertThat(controller.hasOngoingCall()).isFalse()
@@ -441,20 +396,11 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
@Test
fun hasOngoingCall_repoHasCallNotifAndCallAppNotVisible_returnsTrue() {
- whenever(
- mockIActivityManager.getUidProcessState(
- eq(CALL_UID),
- any(),
- )
- )
+ whenever(mockIActivityManager.getUidProcessState(eq(CALL_UID), any()))
.thenReturn(PROC_STATE_INVISIBLE)
setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Ongoing,
- uid = CALL_UID,
- )
+ activeNotificationModel(key = "notif", callType = CallType.Ongoing, uid = CALL_UID)
)
assertThat(controller.hasOngoingCall()).isTrue()
@@ -466,11 +412,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
.thenReturn(PROC_STATE_VISIBLE)
setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Ongoing,
- uid = CALL_UID,
- )
+ activeNotificationModel(key = "notif", callType = CallType.Ongoing, uid = CALL_UID)
)
assertThat(controller.hasOngoingCall()).isFalse()
@@ -482,11 +424,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
controller.setChipView(invalidChipView)
setNotifOnRepo(
- activeNotificationModel(
- key = "notif",
- callType = CallType.Ongoing,
- uid = CALL_UID,
- )
+ activeNotificationModel(key = "notif", callType = CallType.Ongoing, uid = CALL_UID)
)
assertThat(controller.hasOngoingCall()).isFalse()
@@ -532,7 +470,7 @@ class OngoingCallControllerViaRepoTest : SysuiTestCase() {
lateinit var newChipView: View
TestableLooper.get(this).runWithLooper {
newChipView =
- LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip, null)
+ LayoutInflater.from(mContext).inflate(R.layout.ongoing_activity_chip_primary, null)
}
// Change the chip view associated with the controller.
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java
index 4a5ebd057835..aa71b84d7bbc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/wmshell/TestableBubbleController.java
@@ -25,7 +25,6 @@ import android.view.WindowManager;
import com.android.internal.statusbar.IStatusBarService;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.BubbleController;
import com.android.wm.shell.bubbles.BubbleData;
import com.android.wm.shell.bubbles.BubbleDataRepository;
@@ -33,6 +32,8 @@ import com.android.wm.shell.bubbles.BubbleLogger;
import com.android.wm.shell.bubbles.BubblePositioner;
import com.android.wm.shell.bubbles.properties.BubbleProperties;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -62,7 +63,8 @@ public class TestableBubbleController extends BubbleController {
BubbleDataRepository dataRepository,
IStatusBarService statusBarService,
WindowManager windowManager,
- WindowManagerShellWrapper windowManagerShellWrapper,
+ DisplayInsetsController displayInsetsController,
+ DisplayImeController displayImeController,
UserManager userManager,
LauncherApps launcherApps,
BubbleLogger bubbleLogger,
@@ -81,8 +83,8 @@ public class TestableBubbleController extends BubbleController {
BubbleProperties bubbleProperties) {
super(context, shellInit, shellCommandHandler, shellController, data, Runnable::run,
floatingContentCoordinator, dataRepository, statusBarService, windowManager,
- windowManagerShellWrapper, userManager, launcherApps, bubbleLogger,
- taskStackListener, shellTaskOrganizer, positioner, displayController,
+ displayInsetsController, displayImeController, userManager, launcherApps,
+ bubbleLogger, taskStackListener, shellTaskOrganizer, positioner, displayController,
oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
new SyncExecutor(), taskViewTransitions, transitions,
syncQueue, wmService, bubbleProperties);
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip.xml b/packages/SystemUI/res/layout/ongoing_activity_chip_content.xml
index 51217d4e27bd..6f42286d9fac 100644
--- a/packages/SystemUI/res/layout/ongoing_activity_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip_content.xml
@@ -13,17 +13,11 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-<!-- Have the wrapper frame layout match the parent height so that we get a larger touch area for
- the chip. -->
-<FrameLayout
+
+<merge
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical|start"
- android:layout_marginStart="5dp"
->
- <!-- TODO(b/332662551): Update this content description when this supports more than just
- phone calls. -->
+ >
+
<com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer
android:id="@+id/ongoing_activity_chip_background"
android:layout_width="wrap_content"
@@ -39,7 +33,7 @@
<ImageView
android:src="@*android:drawable/ic_phone"
android:id="@+id/ongoing_activity_chip_icon"
- android:contentDescription="@string/ongoing_phone_call_content_description"
+ android:contentDescription="@string/ongoing_call_content_description"
android:layout_width="@dimen/ongoing_activity_chip_icon_size"
android:layout_height="@dimen/ongoing_activity_chip_icon_size"
android:tint="?android:attr/colorPrimary"
@@ -72,4 +66,4 @@
/>
</com.android.systemui.statusbar.chips.ui.view.ChipBackgroundContainer>
-</FrameLayout>
+</merge>
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip_primary.xml b/packages/SystemUI/res/layout/ongoing_activity_chip_primary.xml
new file mode 100644
index 000000000000..114fe6c0d849
--- /dev/null
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip_primary.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ ~ 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.
+ -->
+
+<FrameLayout
+ style="@style/StatusBar.Chip.RootView">
+
+ <include layout="@layout/ongoing_activity_chip_content" />
+
+</FrameLayout>
+
diff --git a/packages/SystemUI/res/layout/ongoing_activity_chip_secondary.xml b/packages/SystemUI/res/layout/ongoing_activity_chip_secondary.xml
new file mode 100644
index 000000000000..81a782236a49
--- /dev/null
+++ b/packages/SystemUI/res/layout/ongoing_activity_chip_secondary.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ 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.
+ ~ 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.
+ -->
+
+<com.android.systemui.statusbar.chips.ui.view.SecondaryOngoingActivityChip
+ style="@style/StatusBar.Chip.RootView">
+
+ <include layout="@layout/ongoing_activity_chip_content" />
+
+</com.android.systemui.statusbar.chips.ui.view.SecondaryOngoingActivityChip>
+
diff --git a/packages/SystemUI/res/layout/status_bar.xml b/packages/SystemUI/res/layout/status_bar.xml
index 1f4dea91db01..e4da4729ad0d 100644
--- a/packages/SystemUI/res/layout/status_bar.xml
+++ b/packages/SystemUI/res/layout/status_bar.xml
@@ -103,10 +103,10 @@
android:gravity="center_vertical|start"
/>
- <include layout="@layout/ongoing_activity_chip"
+ <include layout="@layout/ongoing_activity_chip_primary"
android:id="@+id/ongoing_activity_chip_primary"/>
- <include layout="@layout/ongoing_activity_chip"
+ <include layout="@layout/ongoing_activity_chip_secondary"
android:id="@+id/ongoing_activity_chip_secondary"
android:visibility="gone"/>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 70a94f9f9a59..6994a55cdbcd 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -782,6 +782,13 @@
<!-- The top margin for the notification children container in its non-expanded form. -->
<dimen name="notification_children_container_margin_top">48dp</dimen>
+ <!-- The spacing between the notification children container in its non-expanded form, and the
+ header text above it, scaling with text size. This value is chosen so that, taking into
+ account the text spacing for both the text in the top line and the text in the container,
+ the distance between them is 4dp with the default screen configuration (and will grow
+ accordingly for larger font sizes). -->
+ <dimen name="notification_2025_children_container_margin_top">@*android:dimen/notification_2025_content_margin_top</dimen>
+
<!-- The height of the gap between adjacent notification sections. -->
<dimen name="notification_section_divider_height">@dimen/notification_side_paddings</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 399c2d60094d..cd37c22c8bc3 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3367,8 +3367,8 @@
<!-- Accessibility announcement to inform user to unlock using the fingerprint sensor [CHAR LIMIT=NONE] -->
<string name="accessibility_fingerprint_bouncer">Authentication required. Touch the fingerprint sensor to authenticate.</string>
- <!-- Content description for a chip in the status bar showing that the user is currently on a phone call. [CHAR LIMIT=NONE] -->
- <string name="ongoing_phone_call_content_description">Ongoing phone call</string>
+ <!-- Content description for a chip in the status bar showing that the user is currently on a call. [CHAR LIMIT=NONE] -->
+ <string name="ongoing_call_content_description">Ongoing call</string>
<!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] -->
<string name="mobile_data_settings_title">Mobile data</string>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 71806781b98e..0503dbfab71d 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -73,6 +73,15 @@
<style name="StatusBar" />
<style name="StatusBar.Chip" />
+ <style name="StatusBar.Chip.RootView">
+ <item name="android:layout_width">wrap_content</item>
+ <!-- Have the root chip view match the parent height so that we get a larger touch area for
+ the chip. -->
+ <item name="android:layout_height">match_parent</item>
+ <item name="android:layout_gravity">center_vertical|start</item>
+ <item name="android:layout_marginStart">5dp</item>
+ </style>
+
<style name="StatusBar.Chip.Text">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java
index 92338ef3773c..1a068c4229c9 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/AmbientVolumeSlider.java
@@ -45,16 +45,31 @@ public class AmbientVolumeSlider extends LinearLayout {
new Slider.OnSliderTouchListener() {
@Override
public void onStartTrackingTouch(@NonNull Slider slider) {
+ mTrackingTouch = true;
}
@Override
public void onStopTrackingTouch(@NonNull Slider slider) {
+ mTrackingTouch = false;
final int value = Math.round(slider.getValue());
for (OnChangeListener listener : mChangeListeners) {
listener.onValueChange(AmbientVolumeSlider.this, value);
}
}
};
+ private final Slider.OnChangeListener mSliderChangeListener = new Slider.OnChangeListener() {
+ @Override
+ public void onValueChange(@NonNull Slider slider, float value, boolean fromUser) {
+ if (fromUser && !mTrackingTouch) {
+ final int roundedValue = Math.round(value);
+ for (OnChangeListener listener : mChangeListeners) {
+ listener.onValueChange(AmbientVolumeSlider.this, roundedValue);
+ }
+ }
+ }
+ };
+ private boolean mTrackingTouch = false;
+
public AmbientVolumeSlider(@Nullable Context context) {
this(context, /* attrs= */ null);
}
@@ -76,6 +91,7 @@ public class AmbientVolumeSlider extends LinearLayout {
mTitle = requireViewById(R.id.ambient_volume_slider_title);
mSlider = requireViewById(R.id.ambient_volume_slider);
mSlider.addOnSliderTouchListener(mSliderTouchListener);
+ mSlider.addOnChangeListener(mSliderChangeListener);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
index ca479f5e6b5f..bee1f7416676 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricDisplayListener.kt
@@ -25,23 +25,25 @@ import com.android.app.tracing.traceSection
import com.android.systemui.biometrics.BiometricDisplayListener.SensorType.Generic
/**
- * A listener for keeping overlays for biometric sensors aligned with the physical device
- * device's screen. The [onChanged] will be dispatched on the [handler]
- * whenever a relevant change to the device's configuration (orientation, fold, display change,
- * etc.) may require the UI to change for the given [sensorType].
+ * A listener for keeping overlays for biometric sensors aligned with the physical device device's
+ * screen. The [onChanged] will be dispatched on the [handler] whenever a relevant change to the
+ * device's configuration (orientation, fold, display change, etc.) may require the UI to change for
+ * the given [sensorType].
*/
class BiometricDisplayListener(
private val context: Context,
private val displayManager: DisplayManager,
private val handler: Handler,
private val sensorType: SensorType = SensorType.Generic,
- private val onChanged: () -> Unit
+ private val onChanged: () -> Unit,
) : DisplayManager.DisplayListener {
private var cachedDisplayInfo = DisplayInfo()
override fun onDisplayAdded(displayId: Int) {}
+
override fun onDisplayRemoved(displayId: Int) {}
+
override fun onDisplayChanged(displayId: Int) {
traceSection({ "BiometricDisplayListener($sensorType)#onDisplayChanged" }) {
val rotationChanged = didRotationChange()
@@ -69,7 +71,7 @@ class BiometricDisplayListener(
displayManager.registerDisplayListener(
this,
handler,
- DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ DisplayManager.EVENT_TYPE_DISPLAY_CHANGED,
)
}
@@ -81,14 +83,15 @@ class BiometricDisplayListener(
/**
* Type of sensor to determine what kind of display changes require layouts.
*
- * The [Generic] type should be used in cases where the modality can vary, such as
- * biometric prompt (and this object will likely change as multi-mode auth is added).
+ * The [Generic] type should be used in cases where the modality can vary, such as biometric
+ * prompt (and this object will likely change as multi-mode auth is added).
*/
sealed class SensorType {
data object Generic : SensorType()
+
data object UnderDisplayFingerprint : SensorType()
- data class SideFingerprint(
- val properties: FingerprintSensorPropertiesInternal
- ) : SensorType()
+
+ data class SideFingerprint(val properties: FingerprintSensorPropertiesInternal) :
+ SensorType()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt
index 6c78b8b0e58a..e6d6293733d4 100644
--- a/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/brightness/data/repository/ScreenBrightnessRepository.kt
@@ -133,7 +133,7 @@ constructor(
listener,
null,
/* eventFlags */ 0,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS,
)
awaitClose { displayManager.unregisterDisplayListener(listener) }
@@ -181,10 +181,11 @@ constructor(
.logDiffForTable(tableBuffer, TABLE_PREFIX_LINEAR, TABLE_COLUMN_BRIGHTNESS, null)
.stateIn(applicationScope, SharingStarted.WhileSubscribed(), LinearBrightness(0f))
- override val isBrightnessOverriddenByWindow = brightnessInfo
- .filterNotNull()
- .map { it.isBrightnessOverrideByWindow }
- .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
+ override val isBrightnessOverriddenByWindow =
+ brightnessInfo
+ .filterNotNull()
+ .map { it.isBrightnessOverrideByWindow }
+ .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
override fun setTemporaryBrightness(value: LinearBrightness) {
apiQueue.trySend(SetBrightnessMethod.Temporary(value))
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index e5acb8235a8f..d4642006e68d 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -20,9 +20,9 @@ import android.annotation.SuppressLint
import android.hardware.display.DisplayManager
import android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED
import android.hardware.display.DisplayManager.DisplayListener
-import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_ADDED
-import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
-import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_REMOVED
+import android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_ADDED
+import android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_CHANGED
+import android.hardware.display.DisplayManager.EVENT_TYPE_DISPLAY_REMOVED
import android.os.Handler
import android.util.Log
import android.view.Display
@@ -147,9 +147,9 @@ constructor(
displayManager.registerDisplayListener(
callback,
backgroundHandler,
- EVENT_FLAG_DISPLAY_ADDED or
- EVENT_FLAG_DISPLAY_CHANGED or
- EVENT_FLAG_DISPLAY_REMOVED,
+ EVENT_TYPE_DISPLAY_ADDED or
+ EVENT_TYPE_DISPLAY_CHANGED or
+ EVENT_TYPE_DISPLAY_REMOVED,
)
awaitClose { displayManager.unregisterDisplayListener(callback) }
}
@@ -279,7 +279,7 @@ constructor(
callback,
backgroundHandler,
/* eventFlags */ 0,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_CONNECTION_CHANGED,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_CONNECTION_CHANGED,
)
awaitClose { displayManager.unregisterDisplayListener(callback) }
}
diff --git a/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt b/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt
index debb667bbb15..a19c9b30f68d 100644
--- a/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/mediarouter/data/repository/MediaRouterRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediarouter.data.repository
+import android.media.projection.StopReason
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
@@ -40,7 +41,7 @@ interface MediaRouterRepository {
val castDevices: StateFlow<List<CastDevice>>
/** Stops the cast to the given device. */
- fun stopCasting(device: CastDevice)
+ fun stopCasting(device: CastDevice, @StopReason stopReason: Int)
}
@SysUISingleton
@@ -67,8 +68,8 @@ constructor(
.map { it.filter { device -> device.origin == CastDevice.CastOrigin.MediaRouter } }
.stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
- override fun stopCasting(device: CastDevice) {
- castController.stopCasting(device)
+ override fun stopCasting(device: CastDevice, @StopReason stopReason: Int) {
+ castController.stopCasting(device, stopReason)
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index ad027b4346d0..30c2adf89e9b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -24,6 +24,7 @@ import android.annotation.NonNull;
import android.app.Dialog;
import android.content.Intent;
import android.media.MediaRouter.RouteInfo;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
@@ -183,7 +184,7 @@ public class CastTile extends QSTileImpl<BooleanState> {
});
}
} else {
- mController.stopCasting(activeDevices.get(0));
+ mController.stopCasting(activeDevices.get(0), StopReason.STOP_QS_TILE);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
index fc825926c374..ec8d30b01eab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java
@@ -18,6 +18,7 @@ package com.android.systemui.qs.tiles;
import android.app.Dialog;
import android.content.Intent;
+import android.media.projection.StopReason;
import android.os.Handler;
import android.os.Looper;
import android.service.quicksettings.Tile;
@@ -226,7 +227,7 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState>
}
private void stopRecording() {
- mController.stopRecording();
+ mController.stopRecording(StopReason.STOP_QS_TILE);
}
private final class Callback implements RecordingController.RecordingStateChangeCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
index 85aa6745e438..94534479db57 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/impl/screenrecord/domain/interactor/ScreenRecordTileUserActionInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.qs.tiles.impl.screenrecord.domain.interactor
+import android.media.projection.StopReason
import android.util.Log
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.animation.DialogCuj
@@ -61,7 +62,9 @@ constructor(
Log.d(TAG, "Cancelling countdown")
withContext(backgroundContext) { recordingController.cancelCountdown() }
}
- is ScreenRecordModel.Recording -> screenRecordRepository.stopRecording()
+ is ScreenRecordModel.Recording -> {
+ screenRecordRepository.stopRecording(StopReason.STOP_QS_TILE)
+ }
is ScreenRecordModel.DoingNothing ->
withContext(mainContext) {
showPrompt(action.expandable, user.identifier)
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
index d7463f8f0c36..9ee99e45ceeb 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingController.java
@@ -23,6 +23,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.media.projection.StopReason;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Process;
@@ -58,6 +59,7 @@ public class RecordingController
private boolean mIsStarting;
private boolean mIsRecording;
private PendingIntent mStopIntent;
+ private @StopReason int mStopReason = StopReason.STOP_UNKNOWN;
private final Bundle mInteractiveBroadcastOption;
private CountDownTimer mCountDownTimer = null;
private final Executor mMainExecutor;
@@ -83,7 +85,7 @@ public class RecordingController
new UserTracker.Callback() {
@Override
public void onUserChanged(int newUser, @NonNull Context userContext) {
- stopRecording();
+ stopRecording(StopReason.STOP_USER_SWITCH);
}
};
@@ -240,9 +242,11 @@ public class RecordingController
}
/**
- * Stop the recording
+ * Stop the recording and sets the stop reason to be used by the RecordingService
+ * @param stopReason the method of the recording stopped (i.e. QS tile, status bar chip, etc.)
*/
- public void stopRecording() {
+ public void stopRecording(@StopReason int stopReason) {
+ mStopReason = stopReason;
try {
if (mStopIntent != null) {
mRecordingControllerLogger.logRecordingStopped();
@@ -277,6 +281,10 @@ public class RecordingController
}
}
+ public @StopReason int getStopReason() {
+ return mStopReason;
+ }
+
@Override
public void addCallback(@NonNull RecordingStateChangeCallback listener) {
mListeners.add(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 8c207d13d50e..f7b52719a4f4 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -26,6 +26,7 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Icon;
import android.media.MediaRecorder;
+import android.media.projection.StopReason;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
@@ -78,6 +79,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
private static final String EXTRA_SHOW_TAPS = "extra_showTaps";
private static final String EXTRA_CAPTURE_TARGET = "extra_captureTarget";
private static final String EXTRA_DISPLAY_ID = "extra_displayId";
+ private static final String EXTRA_STOP_REASON = "extra_stopReason";
protected static final String ACTION_START = "com.android.systemui.screenrecord.START";
protected static final String ACTION_SHOW_START_NOTIF =
@@ -242,7 +244,8 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
// Check user ID - we may be getting a stop intent after user switch, in which case
// we want to post the notifications for that user, which is NOT current user
int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, USER_ID_NOT_SPECIFIED);
- stopService(userId);
+ int stopReason = intent.getIntExtra(EXTRA_STOP_REASON, mController.getStopReason());
+ stopService(userId, stopReason);
break;
case ACTION_SHARE:
@@ -486,11 +489,11 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
getTag(), notificationIdForGroup, groupNotif, currentUser);
}
- private void stopService() {
- stopService(USER_ID_NOT_SPECIFIED);
+ private void stopService(@StopReason int stopReason) {
+ stopService(USER_ID_NOT_SPECIFIED, stopReason);
}
- private void stopService(int userId) {
+ private void stopService(int userId, @StopReason int stopReason) {
if (userId == USER_ID_NOT_SPECIFIED) {
userId = mUserContextTracker.getUserContext().getUserId();
}
@@ -499,7 +502,7 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
setTapsVisible(mOriginalShowTaps);
try {
if (getRecorder() != null) {
- getRecorder().end();
+ getRecorder().end(stopReason);
}
saveRecording(userId);
} catch (RuntimeException exception) {
@@ -598,7 +601,8 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
* @return
*/
protected Intent getNotificationIntent(Context context) {
- return new Intent(context, this.getClass()).setAction(ACTION_STOP_NOTIF);
+ return new Intent(context, this.getClass()).setAction(ACTION_STOP_NOTIF)
+ .putExtra(EXTRA_STOP_REASON, StopReason.STOP_HOST_APP);
}
private Intent getShareIntent(Context context, Uri path) {
@@ -610,14 +614,17 @@ public class RecordingService extends Service implements ScreenMediaRecorderList
@Override
public void onInfo(MediaRecorder mr, int what, int extra) {
Log.d(getTag(), "Media recorder info: " + what);
- onStartCommand(getStopIntent(this), 0, 0);
+ // Stop due to record reaching size limits so log as stopping due to error
+ Intent stopIntent = getStopIntent(this);
+ stopIntent.putExtra(EXTRA_STOP_REASON, StopReason.STOP_ERROR);
+ onStartCommand(stopIntent, 0, 0);
}
@Override
- public void onStopped() {
+ public void onStopped(@StopReason int stopReason) {
if (mController.isRecording()) {
Log.d(getTag(), "Stopping recording because the system requested the stop");
- stopService();
+ stopService(stopReason);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index 2ca0621635a7..f4455bfb7048 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -41,6 +41,7 @@ import android.media.projection.IMediaProjection;
import android.media.projection.IMediaProjectionManager;
import android.media.projection.MediaProjection;
import android.media.projection.MediaProjectionManager;
+import android.media.projection.StopReason;
import android.net.Uri;
import android.os.Handler;
import android.os.IBinder;
@@ -300,7 +301,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
/**
* End screen recording, throws an exception if stopping recording failed
*/
- void end() throws IOException {
+ void end(@StopReason int stopReason) throws IOException {
Closer closer = new Closer();
// MediaRecorder might throw RuntimeException if stopped immediately after starting
@@ -309,7 +310,17 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
closer.register(mMediaRecorder::release);
closer.register(mInputSurface::release);
closer.register(mVirtualDisplay::release);
- closer.register(mMediaProjection::stop);
+ closer.register(() -> {
+ if (stopReason == StopReason.STOP_UNKNOWN) {
+ // Attempt to call MediaProjection#stop() even if it might have already been called.
+ // If projection has already been stopped, then nothing will happen. Else, stop
+ // will be logged as a manually requested stop from host app.
+ mMediaProjection.stop();
+ } else {
+ // In any other case, the stop reason is related to the recorder, so pass it on here
+ mMediaProjection.stop(stopReason);
+ }
+ });
closer.register(this::stopInternalAudioRecording);
closer.close();
@@ -323,7 +334,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
@Override
public void onStop() {
Log.d(TAG, "The system notified about stopping the projection");
- mListener.onStopped();
+ mListener.onStopped(StopReason.STOP_UNKNOWN);
}
private void stopInternalAudioRecording() {
@@ -453,7 +464,7 @@ public class ScreenMediaRecorder extends MediaProjection.Callback {
* For example, this might happen when doing partial screen sharing of an app
* and the app that is being captured is closed.
*/
- void onStopped();
+ void onStopped(@StopReason int stopReason);
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
index 9eeb3b9576d8..b6b8ffa11495 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/data/repository/ScreenRecordRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.screenrecord.data.repository
+import android.media.projection.StopReason
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.screenrecord.RecordingController
@@ -41,7 +42,7 @@ interface ScreenRecordRepository {
val screenRecordState: Flow<ScreenRecordModel>
/** Stops the recording. */
- suspend fun stopRecording()
+ suspend fun stopRecording(@StopReason stopReason: Int)
}
@SysUISingleton
@@ -95,7 +96,7 @@ constructor(
}
}
- override suspend fun stopRecording() {
- withContext(bgCoroutineContext) { recordingController.stopRecording() }
+ override suspend fun stopRecording(@StopReason stopReason: Int) {
+ withContext(bgCoroutineContext) { recordingController.stopRecording(stopReason) }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
index 60ed2de5c532..b0cbc06803df 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/DisplayTrackerImpl.kt
@@ -17,7 +17,7 @@
package com.android.systemui.settings
import android.hardware.display.DisplayManager
-import android.hardware.display.DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS
+import android.hardware.display.DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS
import android.os.Handler
import android.view.Display
import androidx.annotation.GuardedBy
@@ -104,7 +104,7 @@ internal constructor(
displayBrightnessChangedListener,
backgroundHandler,
/* eventFlags */ 0,
- PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS,
+ PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS,
)
}
brightnessCallbacks.add(DisplayTrackerDataItem(WeakReference(callback), executor))
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index 85b50d3320dd..de08e3891902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -132,7 +132,7 @@ constructor(
private val phoneIcon =
Icon.Resource(
com.android.internal.R.drawable.ic_phone,
- ContentDescription.Resource(R.string.ongoing_phone_call_content_description),
+ ContentDescription.Resource(R.string.ongoing_call_content_description),
)
private val TAG = "CallVM".pad()
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
index b3dbf299e7cc..229cef910c6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/casttootherdevice/domain/interactor/MediaRouterChipInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.chips.casttootherdevice.domain.interactor
+import android.media.projection.StopReason
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.log.LogBuffer
@@ -65,7 +66,9 @@ constructor(
/** Stops the currently active MediaRouter cast. */
fun stopCasting() {
- activeCastDevice.value?.let { mediaRouterRepository.stopCasting(it) }
+ activeCastDevice.value?.let {
+ mediaRouterRepository.stopCasting(it, StopReason.STOP_PRIVACY_CHIP)
+ }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index a7dbb47bc609..bcd8cfaa5c5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -100,14 +100,14 @@ constructor(
)
}
- if (Flags.promoteNotificationsAutomatically()) {
+ if (
+ Flags.promoteNotificationsAutomatically() &&
+ this.promotedContent.wasPromotedAutomatically
+ ) {
// When we're promoting notifications automatically, the `when` time set on the
// notification will likely just be set to the current time, which would cause the chip
// to always show "now". We don't want early testers to get that experience since it's
// not what will happen at launch, so just don't show any time.
- // TODO(b/364653005): Only ignore the `when` time if the notification was
- // *automatically* promoted (as opposed to being legitimately promoted by the
- // criteria). We'll need to track that status somehow.
return OngoingActivityChipModel.Shown.IconOnly(icon, colors, onClickListener)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
index f5952f4804fc..0b5e669b5fca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/screenrecord/domain/interactor/ScreenRecordChipInteractor.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.chips.screenrecord.domain.interactor
+import android.media.projection.StopReason
import com.android.systemui.Flags
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
@@ -140,7 +141,7 @@ constructor(
/** Stops the recording. */
fun stopRecording() {
- scope.launch { screenRecordRepository.stopRecording() }
+ scope.launch { screenRecordRepository.stopRecording(StopReason.STOP_PRIVACY_CHIP) }
}
companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index 0c4c1a71ccc7..c40df98f39ba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -149,10 +149,9 @@ object OngoingActivityChipBinder {
// 1. Set up the right visual params.
with(iconView) {
id = CUSTOM_ICON_VIEW_ID
- // TODO(b/354930838): Update the content description to not include "phone" and maybe
- // include the app name.
+ // TODO(b/354930838): For RON chips, use the app name for the content description.
contentDescription =
- context.resources.getString(R.string.ongoing_phone_call_content_description)
+ context.resources.getString(R.string.ongoing_call_content_description)
tintView(iconTint)
}
@@ -349,14 +348,21 @@ object OngoingActivityChipBinder {
}
// Clickable chips need to be a minimum size for accessibility purposes, but let
// non-clickable chips be smaller.
- if (chipModel.onClickListener != null) {
- chipBackgroundView.minimumWidth =
+ val minimumWidth =
+ if (chipModel.onClickListener != null) {
chipBackgroundView.context.resources.getDimensionPixelSize(
R.dimen.min_clickable_item_size
)
- } else {
- chipBackgroundView.minimumWidth = 0
- }
+ } else {
+ 0
+ }
+ // The background view needs the minimum width so it only fills the area required (e.g. the
+ // 3-2-1 screen record countdown chip isn't tappable so it should have a small-width
+ // background).
+ chipBackgroundView.minimumWidth = minimumWidth
+ // The root view needs the minimum width so the second chip can hide if there isn't enough
+ // room for the chip -- see [SecondaryOngoingActivityChip].
+ chipView.minimumWidth = minimumWidth
}
@IdRes private val CUSTOM_ICON_VIEW_ID = R.id.ongoing_activity_chip_custom_icon
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/SecondaryOngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/SecondaryOngoingActivityChip.kt
new file mode 100644
index 000000000000..f790dc94f7f2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/view/SecondaryOngoingActivityChip.kt
@@ -0,0 +1,40 @@
+/*
+ * 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.
+ * 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.chips.ui.view
+
+import android.content.Context
+import android.util.AttributeSet
+import android.widget.FrameLayout
+
+/**
+ * A custom class for the secondary ongoing activity chip. This class will completely hide itself if
+ * there isn't enough room for the mimimum size chip.
+ *
+ * [this.minimumWidth] must be set correctly in order for this class to work.
+ */
+class SecondaryOngoingActivityChip(context: Context, attrs: AttributeSet) :
+ FrameLayout(context, attrs) {
+ override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec)
+ if (measuredWidth < this.minimumWidth) {
+ // There isn't enough room to fit even the minimum content required, so hide completely.
+ // Changing visibility ensures that the content description is not read aloud.
+ visibility = GONE
+ setMeasuredDimension(0, 0)
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt
index bb164848320e..395746280f6a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/AutomaticPromotionCoordinator.kt
@@ -22,7 +22,16 @@ import com.android.systemui.statusbar.notification.collection.coordinator.dagger
import javax.inject.Inject
/** A coordinator that may automatically promote certain notifications. */
-interface AutomaticPromotionCoordinator : Coordinator
+interface AutomaticPromotionCoordinator : Coordinator {
+ companion object {
+ /**
+ * An extra that should be set on notifications that were automatically promoted. Used in
+ * case we want to disable certain features for only automatically promoted notifications
+ * (but not normally promoted notifications).
+ */
+ const val EXTRA_WAS_AUTOMATICALLY_PROMOTED = "android.wasAutomaticallyPromoted"
+ }
+}
/** A default implementation of [AutomaticPromotionCoordinator] that doesn't promote anything. */
@CoordinatorScope
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
index 7d2827666227..df2eb08e8fa4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractor.kt
@@ -24,14 +24,14 @@ import android.app.Notification.EXTRA_CHRONOMETER_COUNT_DOWN
import android.app.Notification.EXTRA_SUB_TEXT
import android.app.Notification.EXTRA_TEXT
import android.app.Notification.EXTRA_TITLE
-import android.app.Notification.FLAG_PROMOTED_ONGOING
import android.app.Notification.ProgressStyle
import android.content.Context
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.shade.ShadeDisplayAware
-import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.promoted.AutomaticPromotionCoordinator.Companion.EXTRA_WAS_AUTOMATICALLY_PROMOTED
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Companion.isPromotedForStatusBarChip
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style
import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.When
import javax.inject.Inject
@@ -65,12 +65,8 @@ constructor(
return null
}
- // Notification.isPromotedOngoing checks the ui_rich_ongoing flag, but we want the status
- // bar chip to be ready before all the features behind the ui_rich_ongoing flag are ready.
- val isPromotedForStatusBarChip =
- StatusBarNotifChips.isEnabled && (notification.flags and FLAG_PROMOTED_ONGOING) != 0
- val isPromoted = notification.isPromotedOngoing() || isPromotedForStatusBarChip
- if (!isPromoted) {
+ // The status bar chips rely on this extractor, so take them into account for promotion.
+ if (!isPromotedForStatusBarChip(notification)) {
logger.logExtractionSkipped(entry, "isPromotedOngoing returned false")
return null
}
@@ -80,6 +76,8 @@ constructor(
// TODO: Pitch a fit if style is unsupported or mandatory fields are missing once
// FLAG_PROMOTED_ONGOING is set reliably and we're not testing status bar chips.
+ contentBuilder.wasPromotedAutomatically =
+ notification.extras.getBoolean(EXTRA_WAS_AUTOMATICALLY_PROMOTED, false)
contentBuilder.skeletonSmallIcon = entry.icons.aodIcon?.sourceIcon
contentBuilder.appName = notification.loadHeaderAppName(context)
contentBuilder.subText = notification.subText()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
index 74809fd8622f..258d80c60cd7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/shared/model/PromotedNotificationContentModel.kt
@@ -17,6 +17,8 @@
package com.android.systemui.statusbar.notification.promoted.shared.model
import android.annotation.DrawableRes
+import android.app.Notification
+import android.app.Notification.FLAG_PROMOTED_ONGOING
import android.graphics.drawable.Icon
import androidx.annotation.ColorInt
import com.android.internal.widget.NotificationProgressModel
@@ -31,6 +33,10 @@ data class PromotedNotificationContentModel(
val identity: Identity,
// for all styles:
+ /**
+ * True if this notification was automatically promoted - see [AutomaticPromotionCoordinator].
+ */
+ val wasPromotedAutomatically: Boolean,
val skeletonSmallIcon: Icon?, // TODO(b/377568176): Make into an IconModel.
val appName: CharSequence?,
val subText: CharSequence?,
@@ -58,6 +64,7 @@ data class PromotedNotificationContentModel(
val progress: NotificationProgressModel?,
) {
class Builder(val key: String) {
+ var wasPromotedAutomatically: Boolean = false
var skeletonSmallIcon: Icon? = null
var appName: CharSequence? = null
var subText: CharSequence? = null
@@ -83,6 +90,7 @@ data class PromotedNotificationContentModel(
fun build() =
PromotedNotificationContentModel(
identity = Identity(key, style),
+ wasPromotedAutomatically = wasPromotedAutomatically,
skeletonSmallIcon = skeletonSmallIcon,
appName = appName,
subText = subText,
@@ -134,5 +142,18 @@ data class PromotedNotificationContentModel(
@JvmStatic
fun featureFlagEnabled(): Boolean =
PromotedNotificationUi.isEnabled || StatusBarNotifChips.isEnabled
+
+ /**
+ * Returns true if the given notification should be considered promoted when deciding
+ * whether or not to show the status bar chip UI.
+ */
+ fun isPromotedForStatusBarChip(notification: Notification): Boolean {
+ // Notification.isPromotedOngoing checks the ui_rich_ongoing flag, but we want the
+ // status bar chip to be ready before all the features behind the ui_rich_ongoing flag
+ // are ready.
+ val isPromotedForStatusBarChip =
+ StatusBarNotifChips.isEnabled && (notification.flags and FLAG_PROMOTED_ONGOING) != 0
+ return notification.isPromotedOngoing() || isPromotedForStatusBarChip
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index df43ff19de86..3ccf5063cd68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.row.wrapper;
+import static android.app.Flags.notificationsRedesignTemplates;
import static android.view.View.VISIBLE;
import static com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.DEFAULT_HEADER_VISIBLE_AMOUNT;
@@ -149,10 +150,15 @@ public class NotificationTemplateViewWrapper extends NotificationHeaderViewWrapp
}
}, TRANSFORMING_VIEW_TEXT);
- mFullHeaderTranslation = ctx.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin)
- - ctx.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.notification_content_margin_top);
+ int contentMargin = ctx.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin);
+ int contentMarginTop =
+ notificationsRedesignTemplates()
+ ? Notification.Builder.getContentMarginTop(ctx,
+ com.android.internal.R.dimen.notification_2025_content_margin_top)
+ : ctx.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.notification_content_margin_top);
+ mFullHeaderTranslation = contentMargin - contentMarginTop;
}
@MainThread
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
index 00cd8ce87738..9fb7fad52bb6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java
@@ -168,8 +168,10 @@ public class NotificationChildrenContainer extends ViewGroup
mDividerHeight = res.getDimensionPixelOffset(
R.dimen.notification_children_container_divider_height);
mDividerAlpha = res.getFloat(R.dimen.notification_divider_alpha);
- mNotificationHeaderMargin = res.getDimensionPixelOffset(
- R.dimen.notification_children_container_margin_top);
+ mNotificationHeaderMargin = notificationsRedesignTemplates()
+ ? Notification.Builder.getContentMarginTop(getContext(),
+ R.dimen.notification_2025_children_container_margin_top)
+ : res.getDimensionPixelOffset(R.dimen.notification_children_container_margin_top);
mNotificationTopPadding = res.getDimensionPixelOffset(
R.dimen.notification_children_container_top_padding);
mHeaderHeight = notificationsRedesignTemplates()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
index 2f7b24393ae0..2bfbf4826053 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/domain/interactor/OngoingCallInteractor.kt
@@ -49,15 +49,18 @@ import kotlinx.coroutines.flow.stateIn
/**
* Interactor for determining whether to show a chip in the status bar for ongoing phone calls.
*
- * This class monitors call notifications and the visibility of call apps to determine the appropriate
- * chip state. It emits:
- * * - [OngoingCallModel.NoCall] when there is no call notification
- * * - [OngoingCallModel.InCallWithVisibleApp] when there is a call notification but the call app is visible
- * * - [OngoingCallModel.InCall] when there is a call notification and the call app is not visible
- * */
+ * This class monitors call notifications and the visibility of call apps to determine the
+ * appropriate chip state. It emits:
+ * * - [OngoingCallModel.NoCall] when there is no call notification
+ * * - [OngoingCallModel.InCallWithVisibleApp] when there is a call notification but the call app is
+ * visible
+ * * - [OngoingCallModel.InCall] when there is a call notification and the call app is not visible
+ */
@OptIn(ExperimentalCoroutinesApi::class)
@SysUISingleton
-class OngoingCallInteractor @Inject constructor(
+class OngoingCallInteractor
+@Inject
+constructor(
@Application private val scope: CoroutineScope,
private val activityManagerRepository: ActivityManagerRepository,
private val statusBarModeRepositoryStore: StatusBarModeRepositoryStore,
@@ -68,44 +71,37 @@ class OngoingCallInteractor @Inject constructor(
) : CoreStartable {
private val logger = Logger(logBuffer, TAG)
- /**
- * Tracks whether the call chip has been swiped away.
- */
+ /** Tracks whether the call chip has been swiped away. */
private val _isChipSwipedAway = MutableStateFlow(false)
val isChipSwipedAway: StateFlow<Boolean> = _isChipSwipedAway.asStateFlow()
- /**
- * The current state of ongoing calls.
- */
+ /** The current state of ongoing calls. */
val ongoingCallState: StateFlow<OngoingCallModel> =
activeNotificationsInteractor.ongoingCallNotification
.flatMapLatest { notification ->
- createOngoingCallStateFlow(
- notification = notification
- )
+ createOngoingCallStateFlow(notification = notification)
}
.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(),
- initialValue = OngoingCallModel.NoCall
+ initialValue = OngoingCallModel.NoCall,
)
@VisibleForTesting
- val isStatusBarRequiredForOngoingCall = combine(
- ongoingCallState,
- isChipSwipedAway
- ) { callState, chipSwipedAway ->
- callState is OngoingCallModel.InCall && !chipSwipedAway
- }
+ val isStatusBarRequiredForOngoingCall =
+ combine(ongoingCallState, isChipSwipedAway) { callState, chipSwipedAway ->
+ callState is OngoingCallModel.InCall && !chipSwipedAway
+ }
@VisibleForTesting
- val isGestureListeningEnabled = combine(
- ongoingCallState,
- statusBarModeRepositoryStore.defaultDisplay.isInFullscreenMode,
- isChipSwipedAway
- ) { callState, isFullscreen, chipSwipedAway ->
- callState is OngoingCallModel.InCall && !chipSwipedAway && isFullscreen
- }
+ val isGestureListeningEnabled =
+ combine(
+ ongoingCallState,
+ statusBarModeRepositoryStore.defaultDisplay.isInFullscreenMode,
+ isChipSwipedAway,
+ ) { callState, isFullscreen, chipSwipedAway ->
+ callState is OngoingCallModel.InCall && !chipSwipedAway && isFullscreen
+ }
private fun createOngoingCallStateFlow(
notification: ActiveNotificationModel?
@@ -121,7 +117,7 @@ class OngoingCallInteractor @Inject constructor(
creationUid = notification.uid,
logger = logger,
identifyingLogTag = TAG,
- )
+ ),
) { model, isVisible ->
deriveOngoingCallState(model, isVisible)
}
@@ -130,22 +126,19 @@ class OngoingCallInteractor @Inject constructor(
override fun start() {
ongoingCallState
.filterIsInstance<OngoingCallModel.NoCall>()
- .onEach {
- _isChipSwipedAway.value = false
- }.launchIn(scope)
+ .onEach { _isChipSwipedAway.value = false }
+ .launchIn(scope)
- isStatusBarRequiredForOngoingCall.onEach { statusBarRequired ->
- setStatusBarRequiredForOngoingCall(statusBarRequired)
- }.launchIn(scope)
+ isStatusBarRequiredForOngoingCall
+ .onEach { statusBarRequired -> setStatusBarRequiredForOngoingCall(statusBarRequired) }
+ .launchIn(scope)
- isGestureListeningEnabled.onEach { isEnabled ->
- updateGestureListening(isEnabled)
- }.launchIn(scope)
+ isGestureListeningEnabled
+ .onEach { isEnabled -> updateGestureListening(isEnabled) }
+ .launchIn(scope)
}
- /**
- * Callback that must run when the status bar is swiped while gesture listening is active.
- */
+ /** Callback that must run when the status bar is swiped while gesture listening is active. */
@VisibleForTesting
fun onStatusBarSwiped() {
logger.d("Status bar chip swiped away")
@@ -154,13 +147,11 @@ class OngoingCallInteractor @Inject constructor(
private fun deriveOngoingCallState(
model: ActiveNotificationModel,
- isVisible: Boolean
+ isVisible: Boolean,
): OngoingCallModel {
return when {
isVisible -> {
- logger.d({ "Call app is visible: uid=$int1" }) {
- int1 = model.uid
- }
+ logger.d({ "Call app is visible: uid=$int1" }) { int1 = model.uid }
OngoingCallModel.InCallWithVisibleApp
}
@@ -173,7 +164,7 @@ class OngoingCallInteractor @Inject constructor(
startTimeMs = model.whenTime,
notificationIconView = model.statusBarChipIconView,
intent = model.contentIntent,
- notificationKey = model.key
+ notificationKey = model.key,
)
}
}
@@ -186,8 +177,9 @@ class OngoingCallInteractor @Inject constructor(
statusBarModeRepositoryStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible(
statusBarRequired
)
- statusBarWindowControllerStore.defaultDisplay
- .setOngoingProcessRequiresStatusBarVisible(statusBarRequired)
+ statusBarWindowControllerStore.defaultDisplay.setOngoingProcessRequiresStatusBarVisible(
+ statusBarRequired
+ )
}
private fun updateGestureListening(isEnabled: Boolean) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index a3dcc3b6f851..ece5a3facdf4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy;
+import android.media.projection.StopReason;
import com.android.systemui.Dumpable;
import com.android.systemui.statusbar.policy.CastController.Callback;
@@ -26,7 +27,7 @@ public interface CastController extends CallbackController<Callback>, Dumpable {
void setCurrentUserId(int currentUserId);
List<CastDevice> getCastDevices();
void startCasting(CastDevice device);
- void stopCasting(CastDevice device);
+ void stopCasting(CastDevice device, @StopReason int stopReason);
/**
* @return whether we have a connected device.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 52f80fbf50fd..ab208506f203 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -185,13 +185,13 @@ public class CastControllerImpl implements CastController {
}
@Override
- public void stopCasting(CastDevice device) {
+ public void stopCasting(CastDevice device, @StopReason int stopReason) {
final boolean isProjection = device.getTag() instanceof MediaProjectionInfo;
mLogger.logStopCasting(isProjection);
if (isProjection) {
final MediaProjectionInfo projection = (MediaProjectionInfo) device.getTag();
if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
- mProjectionManager.stopActiveProjection(StopReason.STOP_QS_TILE);
+ mProjectionManager.stopActiveProjection(stopReason);
} else {
mLogger.logStopCastingNoProjection(projection);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
index afff4858499a..a17f100904be 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingControllerTest.java
@@ -36,6 +36,7 @@ import android.app.Dialog;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
+import android.media.projection.StopReason;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -154,7 +155,7 @@ public class RecordingControllerTest extends SysuiTestCase {
PendingIntent stopIntent = Mockito.mock(PendingIntent.class);
mController.startCountdown(0, 0, startIntent, stopIntent);
- mController.stopRecording();
+ mController.stopRecording(StopReason.STOP_UNKNOWN);
assertFalse(mController.isStarting());
assertFalse(mController.isRecording());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt
index 9fb752a11f56..4471c587efb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/settings/DisplayTrackerImplTest.kt
@@ -17,7 +17,7 @@
package com.android.systemui.settings
import android.hardware.display.DisplayManager
-import android.hardware.display.DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS
+import android.hardware.display.DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS
import android.hardware.display.DisplayManagerGlobal
import android.os.Handler
import android.testing.AndroidTestingRunner
@@ -98,7 +98,7 @@ class DisplayTrackerImplTest : SysuiTestCase() {
any(),
any(),
eq(0L),
- eq(PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS),
+ eq(PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS),
)
}
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 192d66c44aa0..af12d0119c58 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -167,7 +167,6 @@ import com.android.systemui.util.settings.SystemSettings;
import com.android.systemui.util.time.SystemClock;
import com.android.wm.shell.Flags;
import com.android.wm.shell.ShellTaskOrganizer;
-import com.android.wm.shell.WindowManagerShellWrapper;
import com.android.wm.shell.bubbles.Bubble;
import com.android.wm.shell.bubbles.BubbleData;
import com.android.wm.shell.bubbles.BubbleDataRepository;
@@ -184,6 +183,8 @@ import com.android.wm.shell.bubbles.StackEducationView;
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
import com.android.wm.shell.bubbles.properties.BubbleProperties;
import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.FloatingContentCoordinator;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -325,7 +326,9 @@ public class BubblesTest extends SysuiTestCase {
@Mock
private LauncherApps mLauncherApps;
@Mock
- private WindowManagerShellWrapper mWindowManagerShellWrapper;
+ private DisplayInsetsController mDisplayInsetsController;
+ @Mock
+ private DisplayImeController mDisplayImeController;
@Mock
private BubbleLogger mBubbleLogger;
@Mock
@@ -503,7 +506,7 @@ public class BubblesTest extends SysuiTestCase {
mContext,
mock(NotificationManager.class),
mock(NotificationSettingsInteractor.class)
- );
+ );
interruptionDecisionProvider.start();
mShellTaskOrganizer = new ShellTaskOrganizer(mock(ShellInit.class),
@@ -523,7 +526,8 @@ public class BubblesTest extends SysuiTestCase {
mDataRepository,
mStatusBarService,
mWindowManager,
- mWindowManagerShellWrapper,
+ mDisplayInsetsController,
+ mDisplayImeController,
mUserManager,
mLauncherApps,
mBubbleLogger,
@@ -1430,9 +1434,12 @@ public class BubblesTest extends SysuiTestCase {
mPositioner,
mBubbleController.getStackView(),
new BubbleIconFactory(mContext,
- mContext.getResources().getDimensionPixelSize(com.android.wm.shell.R.dimen.bubble_size),
- mContext.getResources().getDimensionPixelSize(com.android.wm.shell.R.dimen.bubble_badge_size),
- mContext.getResources().getColor(com.android.launcher3.icons.R.color.important_conversation),
+ mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.bubble_size),
+ mContext.getResources().getDimensionPixelSize(
+ com.android.wm.shell.R.dimen.bubble_badge_size),
+ mContext.getResources().getColor(
+ com.android.launcher3.icons.R.color.important_conversation),
mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.importance_ring_stroke_width)),
bubble,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt
index 8aa7a03710cb..d5637cbe36b5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/mediarouter/data/repository/FakeMediaRouterRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.mediarouter.data.repository
+import android.media.projection.StopReason
import com.android.systemui.statusbar.policy.CastDevice
import kotlinx.coroutines.flow.MutableStateFlow
@@ -25,7 +26,7 @@ class FakeMediaRouterRepository : MediaRouterRepository {
var lastStoppedDevice: CastDevice? = null
private set
- override fun stopCasting(device: CastDevice) {
+ override fun stopCasting(device: CastDevice, @StopReason stopReason: Int) {
lastStoppedDevice = device
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
index 30b4763118a7..4c9e1740b3b5 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/screenrecord/data/repository/FakeScreenRecordRepository.kt
@@ -16,6 +16,7 @@
package com.android.systemui.screenrecord.data.repository
+import android.media.projection.StopReason
import com.android.systemui.screenrecord.data.model.ScreenRecordModel
import kotlinx.coroutines.flow.MutableStateFlow
@@ -25,7 +26,7 @@ class FakeScreenRecordRepository : ScreenRecordRepository {
var stopRecordingInvoked = false
- override suspend fun stopRecording() {
+ override suspend fun stopRecording(@StopReason stopReason: Int) {
stopRecordingInvoked = true
}
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt
index 2df0c7a5386e..da6b2ae46d2d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/policy/FakeCastController.kt
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.policy
+import android.media.projection.StopReason
import java.io.PrintWriter
class FakeCastController : CastController {
@@ -45,7 +46,7 @@ class FakeCastController : CastController {
override fun startCasting(device: CastDevice?) {}
- override fun stopCasting(device: CastDevice?) {
+ override fun stopCasting(device: CastDevice?, @StopReason stopReason: Int) {
lastStoppedDevice = device
}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java
index 2249bc0b667f..857dc8584be9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/utils/leaks/LeakCheckerCastController.java
@@ -16,6 +16,7 @@
package com.android.systemui.utils.leaks;
+import android.media.projection.StopReason;
import android.testing.LeakCheck;
import com.android.systemui.statusbar.policy.CastController;
@@ -51,7 +52,7 @@ public class LeakCheckerCastController extends BaseLeakChecker<Callback> impleme
}
@Override
- public void stopCasting(CastDevice device) {
+ public void stopCasting(CastDevice device, @StopReason int stopReason) {
}
diff --git a/ravenwood/scripts/extract-last-soong-commands.py b/ravenwood/scripts/extract-last-soong-commands.py
index c08d4aa799a5..0629b77029e0 100755
--- a/ravenwood/scripts/extract-last-soong-commands.py
+++ b/ravenwood/scripts/extract-last-soong-commands.py
@@ -32,7 +32,7 @@ re_command = re.compile(r''' ^\[.*?\] \s* (.*) ''', re.X)
HEADER = r'''#!/bin/bash
set -e # Stop on a failed command
-
+set -x # Print command line before executing
cd "${ANDROID_BUILD_TOP:?}"
'''
@@ -65,16 +65,8 @@ def main(args):
command = m.groups()[0]
count += 1
- out.write(f'### Command {count} ========\n')
-
- # Show the full command line before executing it.
- out.write('#echo ' + shlex.quote(command) + '\n')
- out.write('\n')
-
- # Execute the command.
- out.write('#' + command + '\n')
-
- out.write('\n')
+ out.write(f'### Command {count} ========\n\n')
+ out.write('#' + command + '\n\n')
continue
diff --git a/ravenwood/texts/ravenwood-build.prop b/ravenwood/texts/ravenwood-build.prop
index 93a18cffec50..7cc4454a6e56 100644
--- a/ravenwood/texts/ravenwood-build.prop
+++ b/ravenwood/texts/ravenwood-build.prop
@@ -42,3 +42,4 @@ ro.build.version.release=$$$ro.build.version.release
ro.build.version.release_or_codename=$$$ro.build.version.release_or_codename
ro.build.version.release_or_preview_display=$$$ro.build.version.release_or_preview_display
ro.build.version.sdk=$$$ro.build.version.sdk
+ro.build.version.sdk_full=$$$ro.build.version.sdk_full
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
index 669025f071c0..37276ddac75a 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionManagerServiceImpl.java
@@ -155,23 +155,8 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
int callingPid = Binder.getCallingPid();
final SafeOneTimeExecuteAppFunctionCallback safeExecuteAppFunctionCallback =
- new SafeOneTimeExecuteAppFunctionCallback(executeAppFunctionCallback,
- new SafeOneTimeExecuteAppFunctionCallback.CompletionCallback() {
- @Override
- public void finalizeOnSuccess(
- @NonNull ExecuteAppFunctionResponse result,
- long executionStartTimeMillis) {
- mLoggerWrapper.logAppFunctionSuccess(requestInternal, result,
- callingUid, executionStartTimeMillis);
- }
-
- @Override
- public void finalizeOnError(@NonNull AppFunctionException error,
- long executionStartTimeMillis) {
- mLoggerWrapper.logAppFunctionError(requestInternal,
- error.getErrorCode(), callingUid, executionStartTimeMillis);
- }
- });
+ initializeSafeExecuteAppFunctionCallback(
+ requestInternal, executeAppFunctionCallback, callingUid);
String validatedCallingPackage;
try {
@@ -576,6 +561,38 @@ public class AppFunctionManagerServiceImpl extends IAppFunctionManager.Stub {
}
}
+ /**
+ * Returns a new {@link SafeOneTimeExecuteAppFunctionCallback} initialized with a {@link
+ * SafeOneTimeExecuteAppFunctionCallback.CompletionCallback} that logs the results.
+ */
+ @VisibleForTesting
+ SafeOneTimeExecuteAppFunctionCallback initializeSafeExecuteAppFunctionCallback(
+ @NonNull ExecuteAppFunctionAidlRequest requestInternal,
+ @NonNull IExecuteAppFunctionCallback executeAppFunctionCallback,
+ int callingUid) {
+ return new SafeOneTimeExecuteAppFunctionCallback(
+ executeAppFunctionCallback,
+ new SafeOneTimeExecuteAppFunctionCallback.CompletionCallback() {
+ @Override
+ public void finalizeOnSuccess(
+ @NonNull ExecuteAppFunctionResponse result,
+ long executionStartTimeMillis) {
+ mLoggerWrapper.logAppFunctionSuccess(
+ requestInternal, result, callingUid, executionStartTimeMillis);
+ }
+
+ @Override
+ public void finalizeOnError(
+ @NonNull AppFunctionException error, long executionStartTimeMillis) {
+ mLoggerWrapper.logAppFunctionError(
+ requestInternal,
+ error.getErrorCode(),
+ callingUid,
+ executionStartTimeMillis);
+ }
+ });
+ }
+
private static class AppFunctionMetadataObserver implements ObserverCallback {
@Nullable private final MetadataSyncAdapter mPerUserMetadataSyncAdapter;
diff --git a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java
index 7ba1bbc536f6..666d8fe0044c 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/AppFunctionsLoggerWrapper.java
@@ -26,58 +26,99 @@ import android.content.pm.PackageManager;
import android.os.SystemClock;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.util.Objects;
+import java.util.concurrent.Executor;
/** Wraps AppFunctionsStatsLog. */
public class AppFunctionsLoggerWrapper {
private static final String TAG = AppFunctionsLoggerWrapper.class.getSimpleName();
- private static final int SUCCESS_RESPONSE_CODE = -1;
+ @VisibleForTesting static final int SUCCESS_RESPONSE_CODE = -1;
+
+ private final PackageManager mPackageManager;
+ private final Executor mLoggingExecutor;
+ private final AppFunctionsLoggerClock mLoggerClock;
- private final Context mContext;
+ AppFunctionsLoggerWrapper(@NonNull Context context) {
+ this(context.getPackageManager(), LOGGING_THREAD_EXECUTOR, SystemClock::elapsedRealtime);
+ }
- public AppFunctionsLoggerWrapper(@NonNull Context context) {
- mContext = Objects.requireNonNull(context);
+ @VisibleForTesting
+ AppFunctionsLoggerWrapper(
+ @NonNull PackageManager packageManager,
+ @NonNull Executor executor,
+ AppFunctionsLoggerClock loggerClock) {
+ mLoggingExecutor = Objects.requireNonNull(executor);
+ mPackageManager = Objects.requireNonNull(packageManager);
+ mLoggerClock = loggerClock;
}
- void logAppFunctionSuccess(ExecuteAppFunctionAidlRequest request,
- ExecuteAppFunctionResponse response, int callingUid, long executionStartTimeMillis) {
- logAppFunctionsRequestReported(request, SUCCESS_RESPONSE_CODE,
- response.getResponseDataSize(), callingUid, executionStartTimeMillis);
+ void logAppFunctionSuccess(
+ ExecuteAppFunctionAidlRequest request,
+ ExecuteAppFunctionResponse response,
+ int callingUid,
+ long executionStartTimeMillis) {
+ logAppFunctionsRequestReported(
+ request,
+ SUCCESS_RESPONSE_CODE,
+ response.getResponseDataSize(),
+ callingUid,
+ executionStartTimeMillis);
}
- void logAppFunctionError(ExecuteAppFunctionAidlRequest request, int errorCode, int callingUid,
+ void logAppFunctionError(
+ ExecuteAppFunctionAidlRequest request,
+ int errorCode,
+ int callingUid,
long executionStartTimeMillis) {
- logAppFunctionsRequestReported(request, errorCode, /* responseSizeBytes = */ 0, callingUid,
+ logAppFunctionsRequestReported(
+ request,
+ errorCode,
+ /* responseSizeBytes= */ 0,
+ callingUid,
executionStartTimeMillis);
}
- private void logAppFunctionsRequestReported(ExecuteAppFunctionAidlRequest request,
- int errorCode, int responseSizeBytes, int callingUid, long executionStartTimeMillis) {
+ private void logAppFunctionsRequestReported(
+ ExecuteAppFunctionAidlRequest request,
+ int errorCode,
+ int responseSizeBytes,
+ int callingUid,
+ long executionStartTimeMillis) {
final long e2eRequestLatencyMillis =
- SystemClock.elapsedRealtime() - request.getRequestTime();
+ mLoggerClock.getCurrentTimeMillis() - request.getRequestTime();
final long requestOverheadMillis =
- executionStartTimeMillis > 0 ? (executionStartTimeMillis - request.getRequestTime())
+ executionStartTimeMillis > 0
+ ? (executionStartTimeMillis - request.getRequestTime())
: e2eRequestLatencyMillis;
- LOGGING_THREAD_EXECUTOR.execute(() -> AppFunctionsStatsLog.write(
- AppFunctionsStatsLog.APP_FUNCTIONS_REQUEST_REPORTED,
- /* callerPackageUid= */ callingUid,
- /* targetPackageUid= */
- getPackageUid(request.getClientRequest().getTargetPackageName()),
- /* errorCode= */ errorCode,
- /* requestSizeBytes= */ request.getClientRequest().getRequestDataSize(),
- /* responseSizeBytes= */ responseSizeBytes,
- /* requestDurationMs= */ e2eRequestLatencyMillis,
- /* requestOverheadMs= */ requestOverheadMillis)
- );
+ mLoggingExecutor.execute(
+ () ->
+ AppFunctionsStatsLog.write(
+ AppFunctionsStatsLog.APP_FUNCTIONS_REQUEST_REPORTED,
+ /* callerPackageUid= */ callingUid,
+ /* targetPackageUid= */ getPackageUid(
+ request.getClientRequest().getTargetPackageName()),
+ /* errorCode= */ errorCode,
+ /* requestSizeBytes= */ request.getClientRequest()
+ .getRequestDataSize(),
+ /* responseSizeBytes= */ responseSizeBytes,
+ /* requestDurationMs= */ e2eRequestLatencyMillis,
+ /* requestOverheadMs= */ requestOverheadMillis));
}
private int getPackageUid(String packageName) {
try {
- return mContext.getPackageManager().getPackageUid(packageName, 0);
+ return mPackageManager.getPackageUid(packageName, 0);
} catch (PackageManager.NameNotFoundException e) {
Slog.e(TAG, "Package uid not found for " + packageName);
}
return 0;
}
+
+ /** Wraps a custom clock for easier testing. */
+ interface AppFunctionsLoggerClock {
+ long getCurrentTimeMillis();
+ }
}
diff --git a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java
index a5ae7e310022..4cba8ecb2092 100644
--- a/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java
+++ b/services/appfunctions/java/com/android/server/appfunctions/RunAppFunctionServiceCallback.java
@@ -23,6 +23,7 @@ import android.app.appfunctions.IAppFunctionService;
import android.app.appfunctions.ICancellationCallback;
import android.app.appfunctions.IExecuteAppFunctionCallback;
import android.app.appfunctions.SafeOneTimeExecuteAppFunctionCallback;
+import android.os.SystemClock;
import android.util.Slog;
import com.android.server.appfunctions.RemoteServiceCaller.RunServiceCallCallback;
@@ -52,7 +53,8 @@ public class RunAppFunctionServiceCallback implements RunServiceCallCallback<IAp
@NonNull IAppFunctionService service,
@NonNull ServiceUsageCompleteListener serviceUsageCompleteListener) {
try {
- mSafeExecuteAppFunctionCallback.setExecutionStartTimeMillis();
+ mSafeExecuteAppFunctionCallback.setExecutionStartTimeAfterBindMillis(
+ SystemClock.elapsedRealtime());
service.executeAppFunction(
mRequestInternal.getClientRequest(),
mRequestInternal.getCallingPackage(),
@@ -73,8 +75,7 @@ public class RunAppFunctionServiceCallback implements RunServiceCallCallback<IAp
} catch (Exception e) {
mSafeExecuteAppFunctionCallback.onError(
new AppFunctionException(
- AppFunctionException.ERROR_APP_UNKNOWN_ERROR,
- e.getMessage()));
+ AppFunctionException.ERROR_APP_UNKNOWN_ERROR, e.getMessage()));
serviceUsageCompleteListener.onCompleted();
}
}
@@ -83,7 +84,8 @@ public class RunAppFunctionServiceCallback implements RunServiceCallCallback<IAp
public void onFailedToConnect() {
Slog.e(TAG, "Failed to connect to service");
mSafeExecuteAppFunctionCallback.onError(
- new AppFunctionException(AppFunctionException.ERROR_APP_UNKNOWN_ERROR,
+ new AppFunctionException(
+ AppFunctionException.ERROR_APP_UNKNOWN_ERROR,
"Failed to connect to AppFunctionService"));
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index a1d621d8dd1f..6bf60bf1ddf1 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -301,14 +301,19 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
// if the secure window is shown on a non-secure virtual display.
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
Display display = displayManager.getDisplay(displayId);
- if ((display.getFlags() & Display.FLAG_SECURE) == 0) {
- showToastWhereUidIsRunning(activityInfo.applicationInfo.uid,
- com.android.internal.R.string.vdm_secure_window,
- Toast.LENGTH_LONG, mContext.getMainLooper());
-
- Counter.logIncrementWithUid(
- "virtual_devices.value_secure_window_blocked_count",
- mAttributionSource.getUid());
+ if (display != null) {
+ if ((display.getFlags() & Display.FLAG_SECURE) == 0) {
+ showToastWhereUidIsRunning(activityInfo.applicationInfo.uid,
+ com.android.internal.R.string.vdm_secure_window,
+ Toast.LENGTH_LONG, mContext.getMainLooper());
+
+ Counter.logIncrementWithUid(
+ "virtual_devices.value_secure_window_blocked_count",
+ mAttributionSource.getUid());
+ }
+ } else {
+ Slog.e(TAG, "Calling onSecureWindowShown on a non existent/connected display: "
+ + displayId);
}
}
diff --git a/services/core/java/com/android/server/display/BrightnessRangeController.java b/services/core/java/com/android/server/display/BrightnessRangeController.java
index 4fd92751d498..0f0c9009b4d8 100644
--- a/services/core/java/com/android/server/display/BrightnessRangeController.java
+++ b/services/core/java/com/android/server/display/BrightnessRangeController.java
@@ -59,7 +59,7 @@ class BrightnessRangeController {
mModeChangeCallback = modeChangeCallback;
mHdrClamper = hdrClamper;
mNormalBrightnessModeController = normalBrightnessModeController;
- mUseHdrClamper = flags.isHdrClamperEnabled() && !flags.useNewHdrBrightnessModifier();
+ mUseHdrClamper = !flags.useNewHdrBrightnessModifier();
mNormalBrightnessModeController.resetNbmData(
displayDeviceConfig.getLuxThrottlingData());
if (flags.useNewHdrBrightnessModifier()) {
diff --git a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
index 85b6bbb40b91..addfbf1833b9 100644
--- a/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
+++ b/services/core/java/com/android/server/display/feature/DisplayManagerFlags.java
@@ -46,10 +46,6 @@ public class DisplayManagerFlags {
Flags.FLAG_ENABLE_CONNECTED_DISPLAY_MANAGEMENT,
Flags::enableConnectedDisplayManagement);
- private final FlagState mHdrClamperFlagState = new FlagState(
- Flags.FLAG_ENABLE_HDR_CLAMPER,
- Flags::enableHdrClamper);
-
private final FlagState mAdaptiveToneImprovements1 = new FlagState(
Flags.FLAG_ENABLE_ADAPTIVE_TONE_IMPROVEMENTS_1,
Flags::enableAdaptiveToneImprovements1);
@@ -278,11 +274,6 @@ public class DisplayManagerFlags {
return mConnectedDisplayManagementFlagState.isEnabled();
}
- /** Returns whether hdr clamper is enabled on not. */
- public boolean isHdrClamperEnabled() {
- return mHdrClamperFlagState.isEnabled();
- }
-
/** Returns whether power throttling clamper is enabled on not. */
public boolean isPowerThrottlingClamperEnabled() {
return mPowerThrottlingClamperFlagState.isEnabled();
@@ -585,7 +576,6 @@ public class DisplayManagerFlags {
pw.println(" " + mDisplayOffloadFlagState);
pw.println(" " + mExternalDisplayLimitModeState);
pw.println(" " + mDisplayTopology);
- pw.println(" " + mHdrClamperFlagState);
pw.println(" " + mPowerThrottlingClamperFlagState);
pw.println(" " + mEvenDimmerFlagState);
pw.println(" " + mSmallAreaDetectionFlagState);
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 5f974104f86b..eccbbb14c4ea 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
@@ -37,14 +37,6 @@ flag {
}
flag {
- name: "enable_hdr_clamper"
- namespace: "display_manager"
- description: "Feature flag for HDR Clamper"
- bug: "295100043"
- is_fixed_read_only: true
-}
-
-flag {
name: "enable_power_throttling_clamper"
namespace: "display_manager"
description: "Feature flag for Power Throttling Clamper"
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 02e2882442bf..1dd4a9b93277 100644
--- a/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/mode/DisplayModeDirector.java
@@ -2080,10 +2080,13 @@ public class DisplayModeDirector {
restartObserver();
mDeviceConfigDisplaySettings.startListening();
+ registerDisplayListener();
+ }
+ private void registerDisplayListener() {
mInjector.registerDisplayListener(this, mHandler,
- DisplayManager.EVENT_FLAG_DISPLAY_CHANGED,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS);
+ DisplayManager.EVENT_TYPE_DISPLAY_CHANGED,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS);
}
private void setLoggingEnabled(boolean loggingEnabled) {
@@ -2883,8 +2886,8 @@ public class DisplayModeDirector {
}
mDisplayManagerInternal = mInjector.getDisplayManagerInternal();
mInjector.registerDisplayListener(this, mHandler,
- DisplayManager.EVENT_FLAG_DISPLAY_REMOVED,
- DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS);
+ DisplayManager.EVENT_TYPE_DISPLAY_REMOVED,
+ DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS);
}
/**
diff --git a/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java b/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java
index 11418c147caa..0f78f0df006b 100644
--- a/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java
+++ b/services/core/java/com/android/server/display/mode/ProximitySensorObserver.java
@@ -70,10 +70,14 @@ class ProximitySensorObserver implements
mDozeStateByDisplay.put(d.getDisplayId(), mInjector.isDozeState(d));
}
}
+ registerDisplayListener();
+ }
+
+ private void registerDisplayListener() {
mInjector.registerDisplayListener(this, BackgroundThread.getHandler(),
- DisplayManager.EVENT_FLAG_DISPLAY_ADDED
- | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
- | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
+ DisplayManager.EVENT_TYPE_DISPLAY_ADDED
+ | DisplayManager.EVENT_TYPE_DISPLAY_CHANGED
+ | DisplayManager.EVENT_TYPE_DISPLAY_REMOVED);
}
@GuardedBy("mSensorObserverLock")
diff --git a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
index 625b6bbc0e83..4ec9e839a02f 100644
--- a/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
+++ b/services/core/java/com/android/server/display/mode/SkinThermalStatusObserver.java
@@ -83,12 +83,15 @@ final class SkinThermalStatusObserver extends IThermalEventListener.Stub impleme
if (!mInjector.registerThermalServiceListener(this)) {
return;
}
+ registerDisplayListener();
+ populateInitialDisplayInfo();
+ }
+ private void registerDisplayListener() {
mInjector.registerDisplayListener(this, mHandler,
- DisplayManager.EVENT_FLAG_DISPLAY_ADDED | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
- | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED);
-
- populateInitialDisplayInfo();
+ DisplayManager.EVENT_TYPE_DISPLAY_ADDED
+ | DisplayManager.EVENT_TYPE_DISPLAY_CHANGED
+ | DisplayManager.EVENT_TYPE_DISPLAY_REMOVED);
}
void setLoggingEnabled(boolean enabled) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index a8d5696e8c77..c384b5434bce 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -1345,7 +1345,10 @@ abstract class HdmiCecLocalDevice extends HdmiLocalDevice {
iter.remove();
}
if (mPendingActionClearedCallback != null) {
- mPendingActionClearedCallback.onCleared(this);
+ PendingActionClearedCallback callback = mPendingActionClearedCallback;
+ // To prevent from calling the callback again during handling the callback itself.
+ mPendingActionClearedCallback = null;
+ callback.onCleared(this);
}
}
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index ff40eec0d6c8..7b59d6f1301e 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -482,10 +482,7 @@ import java.util.List;
/* package */
static Message createHalMessage(HubMessage message) {
Message outMessage = new Message();
- outMessage.flags =
- message.getDeliveryParams().isResponseRequired()
- ? Message.FLAG_REQUIRES_DELIVERY_STATUS
- : 0;
+ outMessage.flags = message.isResponseRequired() ? Message.FLAG_REQUIRES_DELIVERY_STATUS : 0;
outMessage.permissions = new String[0];
outMessage.sequenceNumber = message.getMessageSequenceNumber();
outMessage.type = message.getMessageType();
@@ -502,8 +499,9 @@ import java.util.List;
/* package */
static HubMessage createHubMessage(Message message) {
boolean isReliable = (message.flags & Message.FLAG_REQUIRES_DELIVERY_STATUS) != 0;
- return new HubMessage(
- message.type, message.content, new HubMessage.DeliveryParams(isReliable));
+ return new HubMessage.Builder(message.type, message.content)
+ .setResponseRequired(isReliable)
+ .build();
}
/**
diff --git a/services/core/java/com/android/server/power/WakefulnessSessionObserver.java b/services/core/java/com/android/server/power/WakefulnessSessionObserver.java
index 64f0693f14c4..d377c23c9b09 100644
--- a/services/core/java/com/android/server/power/WakefulnessSessionObserver.java
+++ b/services/core/java/com/android/server/power/WakefulnessSessionObserver.java
@@ -205,6 +205,13 @@ public class WakefulnessSessionObserver {
UserHandle.USER_ALL);
mPhysicalDisplayPortIdForDefaultDisplay = getPhysicalDisplayPortId(DEFAULT_DISPLAY);
+ registerDisplayListener();
+ mPowerGroups.append(
+ Display.DEFAULT_DISPLAY_GROUP,
+ new WakefulnessSessionPowerGroup(Display.DEFAULT_DISPLAY_GROUP));
+ }
+
+ private void registerDisplayListener() {
DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
if (displayManager != null) {
displayManager.registerDisplayListener(
@@ -226,12 +233,8 @@ public class WakefulnessSessionObserver {
}
},
mHandler,
- DisplayManager.EVENT_FLAG_DISPLAY_CHANGED);
+ DisplayManager.EVENT_TYPE_DISPLAY_CHANGED);
}
-
- mPowerGroups.append(
- Display.DEFAULT_DISPLAY_GROUP,
- new WakefulnessSessionPowerGroup(Display.DEFAULT_DISPLAY_GROUP));
}
/**
diff --git a/services/core/java/com/android/server/power/hint/HintManagerService.java b/services/core/java/com/android/server/power/hint/HintManagerService.java
index a0bc77e939d1..c4e4c422688d 100644
--- a/services/core/java/com/android/server/power/hint/HintManagerService.java
+++ b/services/core/java/com/android/server/power/hint/HintManagerService.java
@@ -42,6 +42,7 @@ import android.hardware.power.GpuHeadroomParams;
import android.hardware.power.GpuHeadroomResult;
import android.hardware.power.IPower;
import android.hardware.power.SessionConfig;
+import android.hardware.power.SessionMode;
import android.hardware.power.SessionTag;
import android.hardware.power.SupportInfo;
import android.hardware.power.WorkDuration;
@@ -58,6 +59,7 @@ import android.os.PerformanceHintManager;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
import android.os.SessionCreationConfig;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -80,7 +82,6 @@ import com.android.server.FgThread;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemService;
-import com.android.server.power.hint.HintManagerService.AppHintSession.SessionModes;
import com.android.server.utils.Slogf;
import java.io.BufferedReader;
@@ -409,6 +410,29 @@ public final class HintManagerService extends SystemService {
mEnforceCpuHeadroomUserModeCpuTimeCheck = true;
}
+ private boolean tooManyPipelineThreads(int uid) {
+ synchronized (mThreadsUsageObject) {
+ ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(uid);
+ int graphicsPipelineThreadCount = 0;
+ if (threadsSet != null) {
+ // We count the graphics pipeline threads that are
+ // *not* in this session, since those in this session
+ // will be replaced. Then if the count plus the new tids
+ // is over max available graphics pipeline threads we raise
+ // an exception.
+ for (ThreadUsageTracker t : threadsSet) {
+ if (t.isGraphicsPipeline()) {
+ graphicsPipelineThreadCount++;
+ }
+ }
+ if (graphicsPipelineThreadCount > MAX_GRAPHICS_PIPELINE_THREADS_COUNT) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
private ServiceThread createCleanUpThread() {
final ServiceThread handlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_LOWEST, true /*allowIo*/);
@@ -1307,9 +1331,9 @@ public final class HintManagerService extends SystemService {
@VisibleForTesting
final class BinderService extends IHintManager.Stub {
@Override
- public IHintSession createHintSessionWithConfig(@NonNull IBinder token,
- @SessionTag int tag, SessionCreationConfig creationConfig,
- SessionConfig config) {
+ public IHintManager.SessionCreationReturn createHintSessionWithConfig(
+ @NonNull IBinder token, @SessionTag int tag,
+ SessionCreationConfig creationConfig, SessionConfig config) {
if (!isHintSessionSupported()) {
throw new UnsupportedOperationException("PowerHintSessions are not supported!");
}
@@ -1327,8 +1351,24 @@ public final class HintManagerService extends SystemService {
final long identity = Binder.clearCallingIdentity();
final long durationNanos = creationConfig.targetWorkDurationNanos;
- Preconditions.checkArgument(checkGraphicsPipelineValid(creationConfig, callingUid),
- "not enough of available graphics pipeline thread.");
+ boolean isGraphicsPipeline = false;
+ boolean isAutoTimed = false;
+ if (creationConfig.modesToEnable != null) {
+ for (int mode : creationConfig.modesToEnable) {
+ if (mode == SessionMode.GRAPHICS_PIPELINE) {
+ isGraphicsPipeline = true;
+ }
+ if (mode == SessionMode.AUTO_CPU || mode == SessionMode.AUTO_GPU) {
+ isAutoTimed = true;
+ }
+ }
+ }
+
+ if (isAutoTimed) {
+ Preconditions.checkArgument(isGraphicsPipeline,
+ "graphics pipeline mode not enabled for an automatically timed session");
+ }
+
try {
final IntArray nonIsolated = powerhintThreadCleanup() ? new IntArray(tids.length)
: null;
@@ -1446,12 +1486,8 @@ public final class HintManagerService extends SystemService {
}
if (hs != null) {
- boolean isGraphicsPipeline = false;
if (creationConfig.modesToEnable != null) {
for (int sessionMode : creationConfig.modesToEnable) {
- if (sessionMode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
- isGraphicsPipeline = true;
- }
hs.setMode(sessionMode, true);
}
}
@@ -1470,7 +1506,10 @@ public final class HintManagerService extends SystemService {
}
}
- return hs;
+ IHintManager.SessionCreationReturn out = new IHintManager.SessionCreationReturn();
+ out.pipelineThreadLimitExceeded = tooManyPipelineThreads(callingUid);
+ out.session = hs;
+ return out;
} finally {
Binder.restoreCallingIdentity(identity);
}
@@ -1852,45 +1891,6 @@ public final class HintManagerService extends SystemService {
throw new IllegalStateException("Can't find cpu line in " + filePath);
}
- private boolean checkGraphicsPipelineValid(SessionCreationConfig creationConfig, int uid) {
- if (creationConfig.modesToEnable == null) {
- return true;
- }
- boolean setGraphicsPipeline = false;
- for (int modeToEnable : creationConfig.modesToEnable) {
- if (modeToEnable == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
- setGraphicsPipeline = true;
- }
- }
- if (!setGraphicsPipeline) {
- return true;
- }
-
- synchronized (mThreadsUsageObject) {
- // count used graphics pipeline threads for the calling UID
- // consider the case that new tids are overlapping with in session tids
- ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(uid);
- if (threadsSet == null) {
- return true;
- }
-
- final int newThreadCount = creationConfig.tids.length;
- int graphicsPipelineThreadCount = 0;
- for (ThreadUsageTracker t : threadsSet) {
- // count graphics pipeline threads in use
- // and exclude overlapping ones
- if (t.isGraphicsPipeline()) {
- graphicsPipelineThreadCount++;
- if (contains(creationConfig.tids, t.getTid())) {
- graphicsPipelineThreadCount--;
- }
- }
- }
- return graphicsPipelineThreadCount + newThreadCount
- <= MAX_GRAPHICS_PIPELINE_THREADS_COUNT;
- }
- }
-
private void logPerformanceHintSessionAtom(int uid, long sessionId,
long targetDuration, int[] tids, @SessionTag int sessionTag) {
FrameworkStatsLog.write(FrameworkStatsLog.PERFORMANCE_HINT_SESSION_REPORTED, uid,
@@ -1928,11 +1928,6 @@ public final class HintManagerService extends SystemService {
protected Integer mSessionId;
protected boolean mTrackedBySF;
- enum SessionModes {
- POWER_EFFICIENCY,
- GRAPHICS_PIPELINE,
- };
-
protected AppHintSession(
int uid, int pid, int sessionTag, int[] threadIds, IBinder token,
long halSessionPtr, long durationNanos, Integer sessionId) {
@@ -1985,8 +1980,8 @@ public final class HintManagerService extends SystemService {
if (!isHintAllowed()) {
return;
}
- Preconditions.checkArgument(targetDurationNanos > 0, "Expected"
- + " the target duration to be greater than 0.");
+ Preconditions.checkArgument(targetDurationNanos >= 0, "Expected"
+ + " the target duration to be greater than or equal to 0.");
mNativeWrapper.halUpdateTargetWorkDuration(mHalSessionPtr, targetDurationNanos);
mTargetDurationNanos = targetDurationNanos;
}
@@ -2149,6 +2144,11 @@ public final class HintManagerService extends SystemService {
public void setThreads(@NonNull int[] tids) {
setThreadsInternal(tids, true);
+ if (tooManyPipelineThreads(Binder.getCallingUid())) {
+ // This is technically a success but we are going to throw a fit anyway
+ throw new ServiceSpecificException(5,
+ "Not enough available graphics pipeline threads.");
+ }
}
private void setThreadsInternal(int[] tids, boolean checkTid) {
@@ -2156,32 +2156,7 @@ public final class HintManagerService extends SystemService {
throw new IllegalArgumentException("Thread id list can't be empty.");
}
-
final int callingUid = Binder.getCallingUid();
- if (mGraphicsPipeline) {
- synchronized (mThreadsUsageObject) {
- // replace original tids with new tids
- ArraySet<ThreadUsageTracker> threadsSet = mThreadsUsageMap.get(callingUid);
- int graphicsPipelineThreadCount = 0;
- if (threadsSet != null) {
- // We count the graphics pipeline threads that are
- // *not* in this session, since those in this session
- // will be replaced. Then if the count plus the new tids
- // is over max available graphics pipeline threads we raise
- // an exception.
- for (ThreadUsageTracker t : threadsSet) {
- if (t.isGraphicsPipeline() && !contains(mThreadIds, t.getTid())) {
- graphicsPipelineThreadCount++;
- }
- }
- if (graphicsPipelineThreadCount + tids.length
- > MAX_GRAPHICS_PIPELINE_THREADS_COUNT) {
- throw new IllegalArgumentException(
- "Not enough available graphics pipeline threads.");
- }
- }
- }
- }
synchronized (this) {
if (mHalSessionPtr == 0) {
@@ -2315,15 +2290,15 @@ public final class HintManagerService extends SystemService {
}
Preconditions.checkArgument(mode >= 0, "the mode Id value should be"
+ " greater than zero.");
- if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
+ if (mode == SessionMode.POWER_EFFICIENCY) {
mPowerEfficient = enabled;
- } else if (mode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ } else if (mode == SessionMode.GRAPHICS_PIPELINE) {
mGraphicsPipeline = enabled;
}
mNativeWrapper.halSetMode(mHalSessionPtr, mode, enabled);
}
if (enabled) {
- if (mode == SessionModes.POWER_EFFICIENCY.ordinal()) {
+ if (mode == SessionMode.POWER_EFFICIENCY) {
if (!mHasBeenPowerEfficient) {
mHasBeenPowerEfficient = true;
synchronized (mSessionSnapshotMapLock) {
@@ -2342,7 +2317,7 @@ public final class HintManagerService extends SystemService {
sessionSnapshot.logPowerEfficientSession();
}
}
- } else if (mode == SessionModes.GRAPHICS_PIPELINE.ordinal()) {
+ } else if (mode == SessionMode.GRAPHICS_PIPELINE) {
if (!mHasBeenGraphicsPipeline) {
mHasBeenGraphicsPipeline = true;
synchronized (mSessionSnapshotMapLock) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index 0aff1de72cb1..bf57f56df7c2 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -77,6 +77,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLAS
import static com.android.server.wm.ActivityTaskManagerService.ANIMATE;
import static com.android.server.wm.ActivityTaskManagerService.H.FIRST_SUPERVISOR_TASK_MSG;
import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_NONE;
+import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
import static com.android.server.wm.ClientLifecycleManager.shouldDispatchLaunchActivityItemIndependently;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_ALLOWLISTED;
import static com.android.server.wm.LockTaskController.LOCK_TASK_AUTH_LAUNCHABLE;
@@ -2525,7 +2526,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
void scheduleUpdatePictureInPictureModeIfNeeded(Task task, Rect targetRootTaskBounds) {
task.forAllActivities(r -> {
if (!r.attachedToProcess()) return;
- mPipModeChangedActivities.add(r);
+ if (!isPip2ExperimentEnabled()) mPipModeChangedActivities.add(r);
// If we are scheduling pip change, then remove this activity from multi-window
// change list as the processing of pip change will make sure multi-window changed
// message is processed in the right order relative to pip changed.
@@ -2534,7 +2535,7 @@ public class ActivityTaskSupervisor implements RecentTasks.Callbacks {
mPipModeChangedTargetRootTaskBounds = targetRootTaskBounds;
- if (!mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
+ if (!isPip2ExperimentEnabled() && !mHandler.hasMessages(REPORT_PIP_MODE_CHANGED_MSG)) {
mHandler.sendEmptyMessage(REPORT_PIP_MODE_CHANGED_MSG);
}
}
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 89d756ca5aaf..f9a06e2dd04b 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -616,7 +616,6 @@ public class BackgroundActivityStartController {
}
static class BalVerdict {
-
static final BalVerdict BLOCK = new BalVerdict(BAL_BLOCK, false, "Blocked");
static final BalVerdict ALLOW_BY_DEFAULT =
new BalVerdict(BAL_ALLOW_DEFAULT, false, "Default");
@@ -640,6 +639,9 @@ public class BackgroundActivityStartController {
}
public BalVerdict withProcessInfo(String msg, WindowProcessController process) {
+ if (this == BLOCK || this == ALLOW_BY_DEFAULT || this == ALLOW_PRIVILEGED) {
+ return this;
+ }
mProcessInfo = msg + " (uid=" + process.mUid + ",pid=" + process.getPid() + ")";
return this;
}
@@ -653,6 +655,10 @@ public class BackgroundActivityStartController {
}
void setOnlyCreatorAllows(boolean onlyCreatorAllows) {
+ if (this == BLOCK) {
+ // do not modify BLOCK constant
+ return;
+ }
mOnlyCreatorAllows = onlyCreatorAllows;
}
@@ -662,6 +668,10 @@ public class BackgroundActivityStartController {
@VisibleForTesting
BalVerdict setBasedOnRealCaller() {
+ if (this == BLOCK) {
+ // do not modify BLOCK constant
+ return this;
+ }
mBasedOnRealCaller = true;
return this;
}
@@ -669,22 +679,29 @@ public class BackgroundActivityStartController {
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(balCodeToString(mCode));
- if (DEBUG_ACTIVITY_STARTS) {
- builder.append(" (");
- if (mBackground) {
- builder.append("Background ");
- }
- builder.append("Activity start ");
- if (mCode == BAL_BLOCK) {
- builder.append("denied");
- } else {
- builder.append("allowed: ").append(mMessage);
+ if (this != BLOCK) {
+ if (mOnlyCreatorAllows) {
+ builder.append(" [onlyCaller]");
+ } else if (mBasedOnRealCaller) {
+ builder.append(" [realCaller]");
}
- if (mProcessInfo != null) {
- builder.append(" ");
- builder.append(mProcessInfo);
+ if (DEBUG_ACTIVITY_STARTS) {
+ builder.append(" (");
+ if (mBackground) {
+ builder.append("Background ");
+ }
+ builder.append("Activity start ");
+ if (mCode == BAL_BLOCK) {
+ builder.append("denied");
+ } else {
+ builder.append("allowed: ").append(mMessage);
+ }
+ if (mProcessInfo != null) {
+ builder.append(" ");
+ builder.append(mProcessInfo);
+ }
+ builder.append(")");
}
- builder.append(")");
}
return builder.toString();
}
@@ -785,9 +802,8 @@ public class BackgroundActivityStartController {
.setBasedOnRealCaller();
state.setResultForRealCaller(resultForRealCaller);
- if (state.isPendingIntent()) {
- resultForCaller.setOnlyCreatorAllows(
- resultForCaller.allows() && resultForRealCaller.blocks());
+ if (state.isPendingIntent() && resultForCaller.allows() && resultForRealCaller.blocks()) {
+ resultForCaller.setOnlyCreatorAllows(true);
}
// Handle cases with explicit opt-in
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index fb197c566b7d..e45ada9438ae 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -80,6 +80,7 @@ import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WINDOW_ORG
import static com.android.server.wm.ActivityRecord.State.PAUSING;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerService.enforceTaskPermission;
+import static com.android.server.wm.ActivityTaskManagerService.isPip2ExperimentEnabled;
import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
@@ -716,6 +717,8 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
}
if (forceHiddenForPip) {
wc.asTask().setForceHidden(FLAG_FORCE_HIDDEN_FOR_PINNED_TASK, true /* set */);
+ }
+ if (forceHiddenForPip && !isPip2ExperimentEnabled()) {
// When removing pip, make sure that onStop is sent to the app ahead of
// onPictureInPictureModeChanged.
// See also PinnedStackTests#testStopBeforeMultiWindowCallbacksOnDismiss
diff --git a/services/tests/appfunctions/Android.bp b/services/tests/appfunctions/Android.bp
index 836f90b992d6..e48abc24ecf3 100644
--- a/services/tests/appfunctions/Android.bp
+++ b/services/tests/appfunctions/Android.bp
@@ -33,18 +33,20 @@ android_test {
],
static_libs: [
+ "androidx.core_core-ktx",
"androidx.test.core",
- "androidx.test.runner",
"androidx.test.ext.truth",
- "androidx.core_core-ktx",
+ "androidx.test.rules",
+ "androidx.test.runner",
+ "frameworks-base-testutils",
"kotlin-test",
"kotlinx_coroutines_test",
+ "mockito-kotlin2",
+ "mockito-target-extended-minus-junit4",
"platform-test-annotations",
"services.appfunctions",
"servicestests-core-utils",
"truth",
- "frameworks-base-testutils",
- "androidx.test.rules",
],
libs: [
diff --git a/services/tests/appfunctions/src/com/android/server/appfunctions/AppFunctionsLoggingTest.kt b/services/tests/appfunctions/src/com/android/server/appfunctions/AppFunctionsLoggingTest.kt
new file mode 100644
index 000000000000..896d2a21d0ac
--- /dev/null
+++ b/services/tests/appfunctions/src/com/android/server/appfunctions/AppFunctionsLoggingTest.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ * 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.appfunctions
+
+import android.app.appfunctions.AppFunctionException
+import android.app.appfunctions.ExecuteAppFunctionAidlRequest
+import android.app.appfunctions.ExecuteAppFunctionRequest
+import android.app.appfunctions.ExecuteAppFunctionResponse
+import android.app.appfunctions.IAppFunctionService
+import android.app.appfunctions.IExecuteAppFunctionCallback
+import android.app.appfunctions.SafeOneTimeExecuteAppFunctionCallback
+import android.app.appsearch.GenericDocument
+import android.content.Context
+import android.content.pm.PackageManager
+import android.os.UserHandle
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.dx.mockito.inline.extended.ExtendedMockito
+import com.android.modules.utils.testing.ExtendedMockitoRule
+import com.google.common.util.concurrent.MoreExecutors
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+
+/**
+ * Tests that AppFunctionsStatsLog logs AppFunctionsRequestReported with the expected values.
+ */
+@RunWith(AndroidJUnit4::class)
+class AppFunctionsLoggingTest {
+ @get:Rule
+ val mExtendedMockitoRule: ExtendedMockitoRule =
+ ExtendedMockitoRule.Builder(this)
+ .mockStatic(AppFunctionsStatsLog::class.java)
+ .build()
+ private val mContext: Context get() = ApplicationProvider.getApplicationContext()
+ private val mMockPackageManager = mock<PackageManager>()
+ private val mAppFunctionsLoggerWrapper =
+ AppFunctionsLoggerWrapper(
+ mMockPackageManager,
+ MoreExecutors.directExecutor(),
+ { TEST_CURRENT_TIME_MILLIS })
+ private lateinit var mSafeCallback: SafeOneTimeExecuteAppFunctionCallback
+
+ private val mServiceImpl =
+ AppFunctionManagerServiceImpl(
+ mContext,
+ mock<RemoteServiceCaller<IAppFunctionService>>(),
+ mock<CallerValidator>(),
+ mock<ServiceHelper>(),
+ ServiceConfigImpl(),
+ mAppFunctionsLoggerWrapper)
+
+ private val mRequestInternal = ExecuteAppFunctionAidlRequest(
+ ExecuteAppFunctionRequest.Builder(TEST_TARGET_PACKAGE, TEST_FUNCTION_ID).build(),
+ UserHandle.CURRENT, TEST_CALLING_PKG, TEST_INITIAL_REQUEST_TIME_MILLIS
+ )
+
+ @Before
+ fun setup() {
+ whenever(mMockPackageManager.getPackageUid(eq(TEST_TARGET_PACKAGE), any<Int>())).thenReturn(TEST_TARGET_UID)
+ mSafeCallback = mServiceImpl.initializeSafeExecuteAppFunctionCallback(mRequestInternal, mock<IExecuteAppFunctionCallback>(), TEST_CALLING_UID)
+ mSafeCallback.setExecutionStartTimeAfterBindMillis(TEST_EXECUTION_TIME_AFTER_BIND_MILLIS)
+ }
+
+ @Test
+ fun testOnSuccess_logsSuccessResponse() {
+ val response =
+ ExecuteAppFunctionResponse(GenericDocument.Builder<GenericDocument.Builder<*>>("", "", "")
+ .setPropertyLong("longProperty", 42L).setPropertyString("stringProperty", "text").build())
+
+ mSafeCallback.onResult(response)
+
+ ExtendedMockito.verify {
+ AppFunctionsStatsLog.write(
+ /* atomId= */ eq<Int>(AppFunctionsStatsLog.APP_FUNCTIONS_REQUEST_REPORTED),
+ /* callerPackageUid= */ eq<Int>(TEST_CALLING_UID),
+ /* targetPackageUid= */ eq<Int>(TEST_TARGET_UID),
+ /* errorCode= */ eq<Int>(AppFunctionsLoggerWrapper.SUCCESS_RESPONSE_CODE),
+ /* requestSizeBytes= */ eq<Int>(mRequestInternal.clientRequest.requestDataSize),
+ /* responseSizeBytes= */ eq<Int>(response.responseDataSize),
+ /* requestDurationMs= */ eq<Long>(TEST_EXPECTED_E2E_DURATION_MILLIS),
+ /* requestOverheadMs= */ eq<Long>(TEST_EXPECTED_OVERHEAD_DURATION_MILLIS)
+ )
+ }
+ }
+
+ @Test
+ fun testOnError_logsFailureResponse() {
+ mSafeCallback.onError(AppFunctionException(AppFunctionException.ERROR_DENIED, "Error: permission denied"))
+
+ ExtendedMockito.verify {
+ AppFunctionsStatsLog.write(
+ /* atomId= */ eq<Int>(AppFunctionsStatsLog.APP_FUNCTIONS_REQUEST_REPORTED),
+ /* callerPackageUid= */ eq<Int>(TEST_CALLING_UID),
+ /* targetPackageUid= */ eq<Int>(TEST_TARGET_UID),
+ /* errorCode= */ eq<Int>(AppFunctionException.ERROR_DENIED),
+ /* requestSizeBytes= */ eq<Int>(mRequestInternal.clientRequest.requestDataSize),
+ /* responseSizeBytes= */ eq<Int>(0),
+ /* requestDurationMs= */ eq<Long>(TEST_EXPECTED_E2E_DURATION_MILLIS),
+ /* requestOverheadMs= */ eq<Long>(TEST_EXPECTED_OVERHEAD_DURATION_MILLIS)
+ )
+ }
+ }
+
+ private companion object {
+ const val TEST_CALLING_PKG = "com.android.trusted.caller"
+ const val TEST_CALLING_UID = 12345
+ const val TEST_TARGET_PACKAGE = "com.android.trusted.target"
+ const val TEST_TARGET_UID = 54321
+ const val TEST_FUNCTION_ID = "com.android.valid.target.doSomething"
+
+ const val TEST_INITIAL_REQUEST_TIME_MILLIS = 10L
+ const val TEST_EXECUTION_TIME_AFTER_BIND_MILLIS = 20L
+ const val TEST_CURRENT_TIME_MILLIS = 50L
+ const val TEST_EXPECTED_E2E_DURATION_MILLIS =
+ TEST_CURRENT_TIME_MILLIS - TEST_INITIAL_REQUEST_TIME_MILLIS
+ const val TEST_EXPECTED_OVERHEAD_DURATION_MILLIS =
+ TEST_EXECUTION_TIME_AFTER_BIND_MILLIS - TEST_INITIAL_REQUEST_TIME_MILLIS
+ }
+}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
index a8708f9f9e6e..3449c36c3b7f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/BrightnessSynchronizerTest.java
@@ -224,7 +224,7 @@ public class BrightnessSynchronizerTest {
mSynchronizer.startSynchronizing();
verify(mDisplayManagerMock).registerDisplayListener(mDisplayListenerCaptor.capture(),
isA(Handler.class), eq(0L),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
mDisplayListener = mDisplayListenerCaptor.getValue();
verify(mContentResolverSpy).registerContentObserver(eq(BRIGHTNESS_URI), eq(false),
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
index a4dfecb8ed96..7f12e9cf145a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayPowerControllerTest.java
@@ -1401,33 +1401,9 @@ public final class DisplayPowerControllerTest {
}
@Test
- public void testRampRateForHdrContent_HdrClamperOff() {
- float hdrBrightness = 0.8f;
- float clampedBrightness = 0.6f;
- float transitionRate = 1.5f;
-
- DisplayPowerRequest dpr = new DisplayPowerRequest();
- when(mHolder.displayPowerState.getColorFadeLevel()).thenReturn(1.0f);
- when(mHolder.displayPowerState.getScreenBrightness()).thenReturn(.2f);
- when(mHolder.displayPowerState.getSdrScreenBrightness()).thenReturn(.1f);
- when(mHolder.hbmController.getHighBrightnessMode()).thenReturn(
- BrightnessInfo.HIGH_BRIGHTNESS_MODE_HDR);
- when(mHolder.hbmController.getHdrBrightnessValue()).thenReturn(hdrBrightness);
- when(mHolder.hdrClamper.getMaxBrightness()).thenReturn(clampedBrightness);
- when(mHolder.hdrClamper.getTransitionRate()).thenReturn(transitionRate);
-
- mHolder.dpc.requestPowerState(dpr, /* waitForNegativeProximity= */ false);
- advanceTime(1); // Run updatePowerState
-
- verify(mHolder.animator, atLeastOnce()).animateTo(eq(hdrBrightness), anyFloat(),
- eq(BRIGHTNESS_RAMP_RATE_FAST_INCREASE), eq(false));
- }
-
- @Test
public void testRampRateForHdrContent_HdrClamperOn() {
float clampedBrightness = 0.6f;
float transitionRate = 1.5f;
- when(mDisplayManagerFlagsMock.isHdrClamperEnabled()).thenReturn(true);
mHolder = createDisplayPowerController(DISPLAY_ID, UNIQUE_ID, /* isEnabled= */ true);
DisplayPowerRequest dpr = new DisplayPowerRequest();
@@ -2631,6 +2607,8 @@ public final class DisplayPowerControllerTest {
BrightnessClamperController clamperController = mock(BrightnessClamperController.class);
when(hbmController.getCurrentBrightnessMax()).thenReturn(PowerManager.BRIGHTNESS_MAX);
+ when(hdrClamper.clamp(anyFloat())).thenAnswer(
+ invocation -> invocation.getArgument(0));
when(clamperController.clamp(any(), any(), anyFloat(), anyBoolean(),
anyInt())).thenAnswer(
invocation -> DisplayBrightnessState.Builder.from(mDisplayBrightnessState)
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 4e0bab8bf4bd..f154dbcee21a 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
@@ -1225,8 +1225,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
setBrightness(10, 10, displayListener);
@@ -1256,8 +1256,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
setBrightness(10, 10, displayListener);
@@ -1291,8 +1291,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
setBrightness(10, 10, displayListener);
@@ -1325,8 +1325,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
ArgumentCaptor<SensorEventListener> sensorListenerCaptor =
@@ -1404,8 +1404,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
ArgumentCaptor<SensorEventListener> sensorListenerCaptor =
@@ -1464,8 +1464,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
ArgumentCaptor<SensorEventListener> listenerCaptor =
@@ -1630,8 +1630,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
// Get the sensor listener so that we can give it new light sensor events
@@ -1730,8 +1730,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(displayListenerCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_CHANGED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_CHANGED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener displayListener = displayListenerCaptor.getValue();
// Get the sensor listener so that we can give it new light sensor events
@@ -2814,9 +2814,9 @@ public class DisplayModeDirectorTest {
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector, times(2)).registerDisplayListener(DisplayCaptor.capture(),
any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_ADDED
- | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
- | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_ADDED
+ | DisplayManager.EVENT_TYPE_DISPLAY_CHANGED
+ | DisplayManager.EVENT_TYPE_DISPLAY_REMOVED));
DisplayListener displayListener = DisplayCaptor.getAllValues().get(0);
// Verify that there is no proximity vote initially
@@ -2877,8 +2877,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor<DisplayListener> captor =
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_REMOVED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener listener = captor.getValue();
// Specify Limitation
@@ -3000,8 +3000,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor<DisplayListener> captor =
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_REMOVED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener listener = captor.getValue();
final int initialRefreshRate = 60;
@@ -3075,8 +3075,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor<DisplayListener> captor =
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_REMOVED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener listener = captor.getValue();
// Specify Limitation for different display
@@ -3115,8 +3115,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor<DisplayListener> captor =
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_REMOVED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener listener = captor.getValue();
// Specify Limitation
@@ -3200,8 +3200,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor<DisplayListener> captor = ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_REMOVED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener listener = captor.getValue();
// Specify Sunlight limitations
@@ -3239,8 +3239,8 @@ public class DisplayModeDirectorTest {
ArgumentCaptor<DisplayListener> captor =
ArgumentCaptor.forClass(DisplayListener.class);
verify(mInjector).registerDisplayListener(captor.capture(), any(Handler.class),
- eq(DisplayManager.EVENT_FLAG_DISPLAY_REMOVED),
- eq(DisplayManager.PRIVATE_EVENT_FLAG_DISPLAY_BRIGHTNESS));
+ eq(DisplayManager.EVENT_TYPE_DISPLAY_REMOVED),
+ eq(DisplayManager.PRIVATE_EVENT_TYPE_DISPLAY_BRIGHTNESS));
DisplayListener listener = captor.getValue();
// Specify Limitation for different display
diff --git a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
index de6f9bd7527a..bd15bd058fcc 100644
--- a/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
+++ b/services/tests/performancehinttests/src/com/android/server/power/hint/HintManagerServiceTest.java
@@ -391,19 +391,19 @@ public class HintManagerServiceTest {
makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig()).session;
assertNotNull(a);
creationConfig.tids = SESSION_TIDS_B;
creationConfig.targetWorkDurationNanos = DOUBLED_TARGET_DURATION;
IHintSession b = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig()).session;
assertNotEquals(a, b);
creationConfig.tids = SESSION_TIDS_C;
creationConfig.targetWorkDurationNanos = 0L;
IHintSession c = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig()).session;
assertNotNull(c);
verify(mNativeWrapperMock, times(3)).halCreateHintSession(anyInt(), anyInt(),
any(int[].class), anyLong());
@@ -418,7 +418,7 @@ public class HintManagerServiceTest {
SessionConfig config = new SessionConfig();
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, config);
+ SessionTag.OTHER, creationConfig, config).session;
assertNotNull(a);
assertEquals(SESSION_IDS[0], config.id);
@@ -426,7 +426,7 @@ public class HintManagerServiceTest {
creationConfig.tids = SESSION_TIDS_B;
creationConfig.targetWorkDurationNanos = DOUBLED_TARGET_DURATION;
IHintSession b = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.APP, creationConfig, config2);
+ SessionTag.APP, creationConfig, config2).session;
assertNotEquals(a, b);
assertEquals(SESSION_IDS[1], config2.id);
@@ -434,7 +434,7 @@ public class HintManagerServiceTest {
creationConfig.tids = SESSION_TIDS_C;
creationConfig.targetWorkDurationNanos = 0L;
IHintSession c = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.GAME, creationConfig, config3);
+ SessionTag.GAME, creationConfig, config3).session;
assertNotNull(c);
assertEquals(SESSION_IDS[2], config3.id);
verify(mNativeWrapperMock, times(3)).halCreateHintSessionWithConfig(anyInt(), anyInt(),
@@ -465,16 +465,14 @@ public class HintManagerServiceTest {
SessionConfig config = new SessionConfig();
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, config);
+ SessionTag.OTHER, creationConfig, config).session;
assertNotNull(a);
assertEquals(sessionId1, config.id);
creationConfig.tids = createThreads(1, stopLatch1);
- assertThrows(IllegalArgumentException.class, () -> {
- service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, config);
- });
+ assertEquals(service.getBinderServiceInstance().createHintSessionWithConfig(token,
+ SessionTag.OTHER, creationConfig, config).pipelineThreadLimitExceeded, true);
}
@Test
@@ -486,7 +484,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
// Set session to background and calling updateHintAllowedByProcState() would invoke
// pause();
@@ -526,7 +524,7 @@ public class HintManagerServiceTest {
makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig()).session;
a.close();
verify(mNativeWrapperMock, times(1)).halCloseHintSession(anyLong());
@@ -540,16 +538,12 @@ public class HintManagerServiceTest {
makeSessionCreationConfig(SESSION_TIDS_A, DEFAULT_TARGET_DURATION);
IHintSession a = service.getBinderServiceInstance().createHintSessionWithConfig(token,
- SessionTag.OTHER, creationConfig, new SessionConfig());
+ SessionTag.OTHER, creationConfig, new SessionConfig()).session;
assertThrows(IllegalArgumentException.class, () -> {
a.updateTargetWorkDuration(-1L);
});
- assertThrows(IllegalArgumentException.class, () -> {
- a.updateTargetWorkDuration(0L);
- });
-
a.updateTargetWorkDuration(100L);
verify(mNativeWrapperMock, times(1)).halUpdateTargetWorkDuration(anyLong(), eq(100L));
}
@@ -563,7 +557,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
a.updateTargetWorkDuration(100L);
a.reportActualWorkDuration(DURATIONS_THREE, TIMESTAMPS_THREE);
@@ -608,7 +602,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
a.sendHint(PerformanceHintManager.Session.CPU_LOAD_RESET);
verify(mNativeWrapperMock, times(1)).halSendHint(anyLong(),
@@ -637,7 +631,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND, 0, 0);
@@ -661,7 +655,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
service.mUidObserver.onUidStateChanged(
a.mUid, ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND, 0, 0);
@@ -677,7 +671,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
a.updateTargetWorkDuration(100L);
@@ -717,7 +711,7 @@ public class HintManagerServiceTest {
makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
assertNotNull(session1);
// trigger UID state change by making the process foreground->background, but because the
@@ -754,7 +748,7 @@ public class HintManagerServiceTest {
makeSessionCreationConfig(tids1, DEFAULT_TARGET_DURATION);
AppHintSession session1 = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
assertNotNull(session1);
// let all session 1 threads to exit and the cleanup should force pause the session 1
@@ -865,7 +859,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
a.setMode(0, true);
verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
@@ -885,7 +879,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
// Set session to background, then the duration would not be updated.
service.mUidObserver.onUidStateChanged(
@@ -906,7 +900,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
assertThrows(IllegalArgumentException.class, () -> {
a.setMode(-1, true);
@@ -923,7 +917,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
assertNotNull(a);
verify(mNativeWrapperMock, times(1)).halSetMode(anyLong(),
eq(0), eq(true));
@@ -1124,7 +1118,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
// we will start some threads and get their valid TIDs to update
int threadCount = 3;
// the list of TIDs
@@ -1194,7 +1188,7 @@ public class HintManagerServiceTest {
AppHintSession a = (AppHintSession) service.getBinderServiceInstance()
.createHintSessionWithConfig(token, SessionTag.OTHER,
- creationConfig, new SessionConfig());
+ creationConfig, new SessionConfig()).session;
a.updateTargetWorkDuration(100L);
a.reportActualWorkDuration2(WORK_DURATIONS_FIVE);
diff --git a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
index 1811c461e23f..0b281d8d39e2 100644
--- a/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
+++ b/tests/Input/src/com/android/test/input/UinputRecordingIntegrationTests.kt
@@ -21,12 +21,12 @@ import android.cts.input.EventVerifier
import android.graphics.PointF
import android.hardware.input.InputManager
import android.os.ParcelFileDescriptor
+import android.server.wm.CtsWindowInfoUtils.waitForWindowOnTop
import android.util.Log
import android.util.Size
import android.view.InputEvent
import android.view.MotionEvent
import androidx.test.platform.app.InstrumentationRegistry
-import android.server.wm.CtsWindowInfoUtils.waitForStableWindowGeometry
import com.android.cts.input.BatchedEventSplitter
import com.android.cts.input.InputJsonParser
import com.android.cts.input.VirtualDisplayActivityScenario
@@ -37,7 +37,6 @@ import com.android.cts.input.inputeventmatchers.withMotionAction
import com.android.cts.input.inputeventmatchers.withPressure
import com.android.cts.input.inputeventmatchers.withRawCoords
import com.android.cts.input.inputeventmatchers.withSource
-import java.time.Duration
import junit.framework.Assert.fail
import org.hamcrest.Matchers.allOf
import org.junit.Before
@@ -115,7 +114,7 @@ class UinputRecordingIntegrationTests {
testName,
size = testData.displaySize
).use { scenario ->
- waitForStableWindowGeometry(Duration.ofSeconds(5))
+ waitForWindowOnTop(scenario.activity.window)
scenario.activity.window.decorView.requestUnbufferedDispatch(INPUT_DEVICE_SOURCE_ALL)
try {