From cfe5ef4ac7cd59f094b538252161ad74223c47da Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Sat, 12 May 2018 11:09:44 +0200 Subject: Remove Gonk build directories --- dom/media/MediaPermissionGonk.cpp | 522 - dom/media/MediaPermissionGonk.h | 39 - dom/media/moz.build | 13 - .../platforms/gonk/GonkAudioDecoderManager.cpp | 268 - dom/media/platforms/gonk/GonkAudioDecoderManager.h | 59 - dom/media/platforms/gonk/GonkDecoderModule.cpp | 63 - dom/media/platforms/gonk/GonkDecoderModule.h | 37 - dom/media/platforms/gonk/GonkMediaDataDecoder.cpp | 385 - dom/media/platforms/gonk/GonkMediaDataDecoder.h | 214 - .../platforms/gonk/GonkVideoDecoderManager.cpp | 772 - dom/media/platforms/gonk/GonkVideoDecoderManager.h | 149 - dom/media/platforms/gonk/moz.build | 39 - dom/media/platforms/moz.build | 4 - dom/secureelement/SEUtils.jsm | 116 - dom/secureelement/gonk/ACEService.js | 139 - dom/secureelement/gonk/ACEService.manifest | 2 - dom/secureelement/gonk/GPAccessRulesManager.js | 436 - .../gonk/GPAccessRulesManager.manifest | 2 - dom/secureelement/gonk/SecureElement.js | 514 - dom/secureelement/gonk/SecureElement.manifest | 18 - dom/secureelement/gonk/UiccConnector.js | 360 - dom/secureelement/gonk/UiccConnector.manifest | 17 - dom/secureelement/gonk/gp_consts.js | 62 - .../gonk/nsIAccessControlEnforcer.idl | 32 - dom/secureelement/gonk/nsIAccessRulesManager.idl | 50 - .../gonk/nsISecureElementConnector.idl | 124 - dom/secureelement/gonk/se_consts.js | 68 - dom/secureelement/moz.build | 24 - dom/system/gonk/AudioChannelManager.cpp | 181 - dom/system/gonk/AudioChannelManager.h | 87 - dom/system/gonk/AudioManager.cpp | 1412 -- dom/system/gonk/AudioManager.h | 180 - dom/system/gonk/AutoMounter.cpp | 1496 -- dom/system/gonk/AutoMounter.h | 101 - dom/system/gonk/AutoMounterSetting.cpp | 284 - dom/system/gonk/AutoMounterSetting.h | 38 - dom/system/gonk/DataCallInterfaceService.js | 276 - dom/system/gonk/DataCallInterfaceService.manifest | 6 - dom/system/gonk/DataCallManager.js | 1726 --- dom/system/gonk/DataCallManager.manifest | 4 - dom/system/gonk/GeolocationUtil.cpp | 28 - dom/system/gonk/GeolocationUtil.h | 13 - dom/system/gonk/GonkGPSGeolocationProvider.cpp | 706 - dom/system/gonk/GonkGPSGeolocationProvider.h | 103 - dom/system/gonk/MozMtpCommon.h | 56 - dom/system/gonk/MozMtpDatabase.cpp | 1542 -- dom/system/gonk/MozMtpDatabase.h | 288 - dom/system/gonk/MozMtpServer.cpp | 263 - dom/system/gonk/MozMtpServer.h | 61 - dom/system/gonk/MozMtpStorage.cpp | 135 - dom/system/gonk/MozMtpStorage.h | 47 - dom/system/gonk/NetIdManager.cpp | 68 - dom/system/gonk/NetIdManager.h | 45 - dom/system/gonk/NetworkInterfaceListService.js | 110 - .../gonk/NetworkInterfaceListService.manifest | 17 - dom/system/gonk/NetworkManager.js | 1219 -- dom/system/gonk/NetworkManager.manifest | 3 - dom/system/gonk/NetworkService.js | 862 -- dom/system/gonk/NetworkService.manifest | 3 - dom/system/gonk/NetworkUtils.cpp | 2973 ---- dom/system/gonk/NetworkUtils.h | 498 - dom/system/gonk/NetworkWorker.cpp | 271 - dom/system/gonk/NetworkWorker.h | 37 - dom/system/gonk/OpenFileFinder.cpp | 251 - dom/system/gonk/OpenFileFinder.h | 63 - dom/system/gonk/RILSystemMessenger.jsm | 338 - dom/system/gonk/RILSystemMessengerHelper.js | 169 - dom/system/gonk/RILSystemMessengerHelper.manifest | 6 - dom/system/gonk/RadioInterfaceLayer.js | 1324 -- dom/system/gonk/RadioInterfaceLayer.manifest | 18 - dom/system/gonk/SystemProperty.cpp | 98 - dom/system/gonk/SystemProperty.h | 39 - dom/system/gonk/SystemWorkerManager.cpp | 214 - dom/system/gonk/SystemWorkerManager.h | 75 - dom/system/gonk/TetheringService.js | 891 -- dom/system/gonk/TetheringService.manifest | 4 - dom/system/gonk/TimeZoneSettingObserver.cpp | 239 - dom/system/gonk/TimeZoneSettingObserver.h | 20 - dom/system/gonk/Volume.cpp | 596 - dom/system/gonk/Volume.h | 157 - dom/system/gonk/VolumeCommand.cpp | 85 - dom/system/gonk/VolumeCommand.h | 204 - dom/system/gonk/VolumeManager.cpp | 591 - dom/system/gonk/VolumeManager.h | 192 - dom/system/gonk/VolumeManagerLog.h | 27 - dom/system/gonk/VolumeServiceIOThread.cpp | 82 - dom/system/gonk/VolumeServiceIOThread.h | 49 - dom/system/gonk/VolumeServiceTest.cpp | 202 - dom/system/gonk/VolumeServiceTest.h | 19 - dom/system/gonk/android_audio/AudioSystem.h | 1134 -- dom/system/gonk/android_audio/AudioTrack.h | 489 - dom/system/gonk/android_audio/EffectApi.h | 798 - dom/system/gonk/android_audio/IAudioFlinger.h | 184 - .../gonk/android_audio/IAudioFlingerClient.h | 55 - dom/system/gonk/android_audio/IAudioRecord.h | 68 - dom/system/gonk/android_audio/IAudioTrack.h | 89 - dom/system/gonk/android_audio/IEffect.h | 60 - dom/system/gonk/android_audio/IEffectClient.h | 54 - dom/system/gonk/moz.build | 107 - dom/system/gonk/mozstumbler/MozStumbler.cpp | 426 - dom/system/gonk/mozstumbler/MozStumbler.h | 47 - dom/system/gonk/mozstumbler/StumblerLogging.cpp | 13 - dom/system/gonk/mozstumbler/StumblerLogging.h | 18 - .../gonk/mozstumbler/UploadStumbleRunnable.cpp | 151 - .../gonk/mozstumbler/UploadStumbleRunnable.h | 46 - .../gonk/mozstumbler/WriteStumbleOnThread.cpp | 321 - dom/system/gonk/mozstumbler/WriteStumbleOnThread.h | 91 - dom/system/gonk/nsIAudioManager.idl | 58 - dom/system/gonk/nsIDataCallInterfaceService.idl | 268 - dom/system/gonk/nsIDataCallManager.idl | 81 - .../gonk/nsIGonkDataCallInterfaceService.idl | 18 - dom/system/gonk/nsINetworkInterface.idl | 108 - dom/system/gonk/nsINetworkInterfaceListService.idl | 40 - dom/system/gonk/nsINetworkManager.idl | 135 - dom/system/gonk/nsINetworkService.idl | 619 - dom/system/gonk/nsINetworkWorker.idl | 18 - dom/system/gonk/nsIRadioInterfaceLayer.idl | 53 - dom/system/gonk/nsISystemWorkerManager.idl | 16 - dom/system/gonk/nsITetheringService.idl | 39 - dom/system/gonk/nsIVolume.idl | 114 - dom/system/gonk/nsIVolumeMountLock.idl | 12 - dom/system/gonk/nsIVolumeService.idl | 36 - dom/system/gonk/nsIVolumeStat.idl | 12 - dom/system/gonk/nsIWorkerHolder.idl | 11 - dom/system/gonk/nsVolume.cpp | 467 - dom/system/gonk/nsVolume.h | 114 - dom/system/gonk/nsVolumeMountLock.cpp | 171 - dom/system/gonk/nsVolumeMountLock.h | 56 - dom/system/gonk/nsVolumeService.cpp | 553 - dom/system/gonk/nsVolumeService.h | 78 - dom/system/gonk/nsVolumeStat.cpp | 33 - dom/system/gonk/nsVolumeStat.h | 33 - dom/system/gonk/ril_consts.js | 3338 ---- dom/system/gonk/ril_worker.js | 15206 ------------------- dom/system/gonk/ril_worker_buf_object.js | 168 - .../gonk/ril_worker_telephony_request_queue.js | 157 - dom/system/gonk/systemlibs.js | 201 - dom/system/gonk/tests/header_helpers.js | 217 - dom/system/gonk/tests/marionette/head.js | 345 - dom/system/gonk/tests/marionette/manifest.ini | 19 - .../gonk/tests/marionette/ril_jshint/README.md | 9 - .../gonk/tests/marionette/ril_jshint/jshint.js | 11096 -------------- .../gonk/tests/marionette/ril_jshint/jshintrc | 118 - .../gonk/tests/marionette/test_all_network_info.js | 106 - .../gonk/tests/marionette/test_data_connection.js | 70 - .../tests/marionette/test_data_connection_proxy.js | 99 - .../marionette/test_dsds_numRadioInterfaces.js | 43 - .../gonk/tests/marionette/test_fakevolume.js | 25 - .../gonk/tests/marionette/test_geolocation.js | 117 - .../marionette/test_multiple_data_connection.js | 89 - .../marionette/test_network_active_changed.js | 52 - .../test_network_interface_list_service.js | 95 - .../tests/marionette/test_network_interface_mtu.js | 100 - .../gonk/tests/marionette/test_ril_code_quality.py | 371 - .../gonk/tests/marionette/test_screen_state.js | 47 - .../gonk/tests/marionette/test_timezone_changes.js | 135 - dom/system/gonk/tests/test_ril_system_messenger.js | 1187 -- .../gonk/tests/test_ril_worker_barring_password.js | 61 - dom/system/gonk/tests/test_ril_worker_buf.js | 187 - .../gonk/tests/test_ril_worker_cdma_info_rec.js | 234 - .../tests/test_ril_worker_cellbroadcast_config.js | 470 - .../tests/test_ril_worker_cellbroadcast_gsm.js | 230 - .../tests/test_ril_worker_cellbroadcast_umts.js | 105 - dom/system/gonk/tests/test_ril_worker_cf.js | 126 - dom/system/gonk/tests/test_ril_worker_clip.js | 59 - dom/system/gonk/tests/test_ril_worker_clir.js | 122 - dom/system/gonk/tests/test_ril_worker_cw.js | 104 - dom/system/gonk/tests/test_ril_worker_ecm.js | 168 - .../gonk/tests/test_ril_worker_icc_BerTlvHelper.js | 87 - .../gonk/tests/test_ril_worker_icc_CardLock.js | 282 - .../gonk/tests/test_ril_worker_icc_CardState.js | 210 - .../gonk/tests/test_ril_worker_icc_GsmPDUHelper.js | 79 - .../tests/test_ril_worker_icc_ICCContactHelper.js | 1042 -- .../gonk/tests/test_ril_worker_icc_ICCIOHelper.js | 173 - .../gonk/tests/test_ril_worker_icc_ICCPDUHelper.js | 652 - .../tests/test_ril_worker_icc_ICCRecordHelper.js | 1080 -- .../tests/test_ril_worker_icc_ICCUtilsHelper.js | 326 - .../gonk/tests/test_ril_worker_icc_IconLoader.js | 771 - .../tests/test_ril_worker_icc_SimRecordHelper.js | 1648 -- dom/system/gonk/tests/test_ril_worker_ruim.js | 328 - dom/system/gonk/tests/test_ril_worker_sms.js | 273 - dom/system/gonk/tests/test_ril_worker_sms_cdma.js | 298 - .../tests/test_ril_worker_sms_cdmapduhelper.js | 210 - .../gonk/tests/test_ril_worker_sms_gsmpduhelper.js | 282 - .../gonk/tests/test_ril_worker_sms_nl_tables.js | 77 - .../gonk/tests/test_ril_worker_sms_segment_info.js | 115 - .../gonk/tests/test_ril_worker_smsc_address.js | 112 - dom/system/gonk/tests/test_ril_worker_ssn.js | 104 - dom/system/gonk/tests/test_ril_worker_stk.js | 1698 --- .../gonk/tests/test_ril_worker_voiceprivacy.js | 94 - dom/system/gonk/tests/xpcshell.ini | 43 - dom/system/gonk/worker_buf.js | 623 - dom/system/moz.build | 2 - hal/gonk/GonkDiskSpaceWatcher.cpp | 324 - hal/gonk/GonkHal.cpp | 2045 --- hal/gonk/GonkSensor.cpp | 861 -- hal/gonk/GonkSensorsHelpers.cpp | 112 - hal/gonk/GonkSensorsHelpers.h | 226 - hal/gonk/GonkSensorsInterface.cpp | 494 - hal/gonk/GonkSensorsInterface.h | 191 - hal/gonk/GonkSensorsPollInterface.cpp | 431 - hal/gonk/GonkSensorsPollInterface.h | 340 - hal/gonk/GonkSensorsRegistryInterface.cpp | 213 - hal/gonk/GonkSensorsRegistryInterface.h | 182 - hal/gonk/GonkSwitch.cpp | 479 - hal/gonk/SensorsTypes.h | 140 - hal/gonk/SystemService.cpp | 131 - hal/gonk/UeventPoller.cpp | 312 - hal/gonk/UeventPoller.h | 49 - hal/gonk/fanotify.h | 118 - hal/gonk/nsIRecoveryService.idl | 39 - hal/gonk/tavarua.h | 484 - hal/moz.build | 52 +- .../marionette_harness/tests/webapi-tests.ini | 1 - uriloader/exthandler/gonk/nsOSHelperAppService.cpp | 56 - uriloader/exthandler/gonk/nsOSHelperAppService.h | 39 - uriloader/exthandler/moz.build | 2 +- widget/gonk/GeckoTouchDispatcher.cpp | 358 - widget/gonk/GeckoTouchDispatcher.h | 99 - widget/gonk/GfxInfo.cpp | 194 - widget/gonk/GfxInfo.h | 69 - widget/gonk/GonkClipboardData.cpp | 75 - widget/gonk/GonkClipboardData.h | 49 - widget/gonk/GonkKeyMapping.h | 301 - widget/gonk/GonkMemoryPressureMonitoring.cpp | 359 - widget/gonk/GonkMemoryPressureMonitoring.h | 14 - widget/gonk/GonkPermission.cpp | 195 - widget/gonk/GonkPermission.h | 86 - widget/gonk/HwcComposer2D.cpp | 971 -- widget/gonk/HwcComposer2D.h | 123 - widget/gonk/HwcUtils.cpp | 169 - widget/gonk/HwcUtils.h | 135 - widget/gonk/OrientationObserver.cpp | 332 - widget/gonk/OrientationObserver.h | 71 - widget/gonk/ProcessOrientation.cpp | 519 - widget/gonk/ProcessOrientation.h | 111 - widget/gonk/WidgetTraceEvent.cpp | 96 - widget/gonk/hwchal/HwcHAL.cpp | 214 - widget/gonk/hwchal/HwcHAL.h | 70 - widget/gonk/hwchal/HwcHALBase.h | 134 - widget/gonk/libdisplay/BootAnimation.cpp | 726 - widget/gonk/libdisplay/BootAnimation.h | 30 - widget/gonk/libdisplay/DisplaySurface.h | 112 - widget/gonk/libdisplay/FramebufferSurface.cpp | 207 - widget/gonk/libdisplay/FramebufferSurface.h | 93 - widget/gonk/libdisplay/GonkDisplay.h | 91 - widget/gonk/libdisplay/GonkDisplayJB.cpp | 461 - widget/gonk/libdisplay/GonkDisplayJB.h | 85 - widget/gonk/libdisplay/GraphicBufferAlloc.cpp | 53 - widget/gonk/libdisplay/GraphicBufferAlloc.h | 44 - widget/gonk/libdisplay/VirtualDisplaySurface.cpp | 635 - widget/gonk/libdisplay/VirtualDisplaySurface.h | 250 - widget/gonk/libdisplay/moz.build | 59 - widget/gonk/libui/EventHub.cpp | 1549 -- widget/gonk/libui/EventHub.h | 435 - widget/gonk/libui/Input.cpp | 635 - widget/gonk/libui/Input.h | 622 - widget/gonk/libui/InputApplication.cpp | 42 - widget/gonk/libui/InputApplication.h | 83 - widget/gonk/libui/InputDevice.cpp | 184 - widget/gonk/libui/InputDevice.h | 156 - widget/gonk/libui/InputDispatcher.cpp | 4430 ------ widget/gonk/libui/InputDispatcher.h | 1117 -- widget/gonk/libui/InputListener.cpp | 182 - widget/gonk/libui/InputListener.h | 196 - widget/gonk/libui/InputManager.cpp | 93 - widget/gonk/libui/InputManager.h | 109 - widget/gonk/libui/InputReader.cpp | 6510 -------- widget/gonk/libui/InputReader.h | 1811 --- widget/gonk/libui/InputTransport.cpp | 957 -- widget/gonk/libui/InputTransport.h | 443 - widget/gonk/libui/InputWindow.cpp | 64 - widget/gonk/libui/InputWindow.h | 205 - widget/gonk/libui/KeyCharacterMap.cpp | 1153 -- widget/gonk/libui/KeyCharacterMap.h | 257 - widget/gonk/libui/KeyLayoutMap.cpp | 446 - widget/gonk/libui/KeyLayoutMap.h | 117 - widget/gonk/libui/Keyboard.cpp | 300 - widget/gonk/libui/Keyboard.h | 122 - widget/gonk/libui/KeycodeLabels.h | 380 - widget/gonk/libui/PointerController.cpp | 604 - widget/gonk/libui/PointerController.h | 266 - widget/gonk/libui/PowerManager.h | 33 - widget/gonk/libui/SpriteController.cpp | 515 - widget/gonk/libui/SpriteController.h | 319 - widget/gonk/libui/Tokenizer.cpp | 175 - widget/gonk/libui/Tokenizer.h | 136 - widget/gonk/libui/Trace.h | 64 - widget/gonk/libui/VelocityControl.cpp | 110 - widget/gonk/libui/VelocityControl.h | 107 - widget/gonk/libui/VelocityTracker.cpp | 929 -- widget/gonk/libui/VelocityTracker.h | 269 - widget/gonk/libui/VirtualKeyMap.cpp | 171 - widget/gonk/libui/VirtualKeyMap.h | 81 - widget/gonk/libui/android_input.h | 850 -- widget/gonk/libui/android_keycodes.h | 315 - widget/gonk/libui/cutils_log.h | 569 - widget/gonk/libui/cutils_trace.h | 276 - widget/gonk/libui/linux_input.h | 1029 -- widget/gonk/libui/sha1.c | 289 - widget/gonk/libui/sha1.h | 31 - widget/gonk/moz.build | 96 - widget/gonk/nativewindow/FakeSurfaceComposer.cpp | 703 - widget/gonk/nativewindow/FakeSurfaceComposer.h | 175 - widget/gonk/nativewindow/GonkBufferQueue.h | 22 - widget/gonk/nativewindow/GonkBufferQueueJB.cpp | 1036 -- widget/gonk/nativewindow/GonkBufferQueueJB.h | 653 - widget/gonk/nativewindow/GonkBufferQueueKK.cpp | 1265 -- widget/gonk/nativewindow/GonkBufferQueueKK.h | 583 - .../GonkBufferQueueLL/GonkBufferItem.cpp | 193 - .../GonkBufferQueueLL/GonkBufferItem.h | 101 - .../GonkBufferQueueLL/GonkBufferQueueConsumer.cpp | 559 - .../GonkBufferQueueLL/GonkBufferQueueConsumer.h | 173 - .../GonkBufferQueueLL/GonkBufferQueueCore.cpp | 243 - .../GonkBufferQueueLL/GonkBufferQueueCore.h | 251 - .../GonkBufferQueueLL/GonkBufferQueueDefs.h | 36 - .../GonkBufferQueueLL/GonkBufferQueueLL.cpp | 96 - .../GonkBufferQueueLL/GonkBufferQueueLL.h | 94 - .../GonkBufferQueueLL/GonkBufferQueueProducer.cpp | 886 -- .../GonkBufferQueueLL/GonkBufferQueueProducer.h | 216 - .../GonkBufferQueueLL/GonkBufferSlot.cpp | 32 - .../GonkBufferQueueLL/GonkBufferSlot.h | 132 - widget/gonk/nativewindow/GonkConsumerBaseJB.cpp | 245 - widget/gonk/nativewindow/GonkConsumerBaseJB.h | 239 - widget/gonk/nativewindow/GonkConsumerBaseKK.cpp | 252 - widget/gonk/nativewindow/GonkConsumerBaseKK.h | 240 - widget/gonk/nativewindow/GonkConsumerBaseLL.cpp | 257 - widget/gonk/nativewindow/GonkConsumerBaseLL.h | 245 - widget/gonk/nativewindow/GonkNativeWindow.h | 22 - widget/gonk/nativewindow/GonkNativeWindowJB.cpp | 180 - widget/gonk/nativewindow/GonkNativeWindowJB.h | 133 - widget/gonk/nativewindow/GonkNativeWindowKK.cpp | 182 - widget/gonk/nativewindow/GonkNativeWindowKK.h | 135 - widget/gonk/nativewindow/GonkNativeWindowLL.cpp | 204 - widget/gonk/nativewindow/GonkNativeWindowLL.h | 133 - .../gonk/nativewindow/IGonkGraphicBufferConsumer.h | 20 - .../nativewindow/IGonkGraphicBufferConsumerKK.cpp | 480 - .../nativewindow/IGonkGraphicBufferConsumerKK.h | 228 - .../nativewindow/IGonkGraphicBufferConsumerLL.cpp | 565 - .../nativewindow/IGonkGraphicBufferConsumerLL.h | 337 - widget/gonk/nativewindow/moz.build | 104 - widget/gonk/nsAppShell.cpp | 1087 -- widget/gonk/nsAppShell.h | 112 - widget/gonk/nsClipboard.cpp | 366 - widget/gonk/nsClipboard.h | 27 - widget/gonk/nsIdleServiceGonk.cpp | 33 - widget/gonk/nsIdleServiceGonk.h | 47 - widget/gonk/nsLookAndFeel.cpp | 465 - widget/gonk/nsLookAndFeel.h | 40 - widget/gonk/nsScreenManagerGonk.cpp | 1081 -- widget/gonk/nsScreenManagerGonk.h | 228 - widget/gonk/nsWidgetFactory.cpp | 128 - widget/gonk/nsWindow.cpp | 744 - widget/gonk/nsWindow.h | 154 - widget/moz.build | 6 +- 355 files changed, 15 insertions(+), 139695 deletions(-) delete mode 100644 dom/media/MediaPermissionGonk.cpp delete mode 100644 dom/media/MediaPermissionGonk.h delete mode 100644 dom/media/platforms/gonk/GonkAudioDecoderManager.cpp delete mode 100644 dom/media/platforms/gonk/GonkAudioDecoderManager.h delete mode 100644 dom/media/platforms/gonk/GonkDecoderModule.cpp delete mode 100644 dom/media/platforms/gonk/GonkDecoderModule.h delete mode 100644 dom/media/platforms/gonk/GonkMediaDataDecoder.cpp delete mode 100644 dom/media/platforms/gonk/GonkMediaDataDecoder.h delete mode 100644 dom/media/platforms/gonk/GonkVideoDecoderManager.cpp delete mode 100644 dom/media/platforms/gonk/GonkVideoDecoderManager.h delete mode 100644 dom/media/platforms/gonk/moz.build delete mode 100644 dom/secureelement/SEUtils.jsm delete mode 100644 dom/secureelement/gonk/ACEService.js delete mode 100644 dom/secureelement/gonk/ACEService.manifest delete mode 100644 dom/secureelement/gonk/GPAccessRulesManager.js delete mode 100644 dom/secureelement/gonk/GPAccessRulesManager.manifest delete mode 100644 dom/secureelement/gonk/SecureElement.js delete mode 100644 dom/secureelement/gonk/SecureElement.manifest delete mode 100644 dom/secureelement/gonk/UiccConnector.js delete mode 100644 dom/secureelement/gonk/UiccConnector.manifest delete mode 100644 dom/secureelement/gonk/gp_consts.js delete mode 100644 dom/secureelement/gonk/nsIAccessControlEnforcer.idl delete mode 100644 dom/secureelement/gonk/nsIAccessRulesManager.idl delete mode 100644 dom/secureelement/gonk/nsISecureElementConnector.idl delete mode 100644 dom/secureelement/gonk/se_consts.js delete mode 100644 dom/system/gonk/AudioChannelManager.cpp delete mode 100644 dom/system/gonk/AudioChannelManager.h delete mode 100644 dom/system/gonk/AudioManager.cpp delete mode 100644 dom/system/gonk/AudioManager.h delete mode 100644 dom/system/gonk/AutoMounter.cpp delete mode 100644 dom/system/gonk/AutoMounter.h delete mode 100644 dom/system/gonk/AutoMounterSetting.cpp delete mode 100644 dom/system/gonk/AutoMounterSetting.h delete mode 100644 dom/system/gonk/DataCallInterfaceService.js delete mode 100644 dom/system/gonk/DataCallInterfaceService.manifest delete mode 100644 dom/system/gonk/DataCallManager.js delete mode 100644 dom/system/gonk/DataCallManager.manifest delete mode 100644 dom/system/gonk/GeolocationUtil.cpp delete mode 100644 dom/system/gonk/GeolocationUtil.h delete mode 100644 dom/system/gonk/GonkGPSGeolocationProvider.cpp delete mode 100644 dom/system/gonk/GonkGPSGeolocationProvider.h delete mode 100644 dom/system/gonk/MozMtpCommon.h delete mode 100644 dom/system/gonk/MozMtpDatabase.cpp delete mode 100644 dom/system/gonk/MozMtpDatabase.h delete mode 100644 dom/system/gonk/MozMtpServer.cpp delete mode 100644 dom/system/gonk/MozMtpServer.h delete mode 100644 dom/system/gonk/MozMtpStorage.cpp delete mode 100644 dom/system/gonk/MozMtpStorage.h delete mode 100644 dom/system/gonk/NetIdManager.cpp delete mode 100644 dom/system/gonk/NetIdManager.h delete mode 100644 dom/system/gonk/NetworkInterfaceListService.js delete mode 100644 dom/system/gonk/NetworkInterfaceListService.manifest delete mode 100644 dom/system/gonk/NetworkManager.js delete mode 100644 dom/system/gonk/NetworkManager.manifest delete mode 100644 dom/system/gonk/NetworkService.js delete mode 100644 dom/system/gonk/NetworkService.manifest delete mode 100644 dom/system/gonk/NetworkUtils.cpp delete mode 100644 dom/system/gonk/NetworkUtils.h delete mode 100644 dom/system/gonk/NetworkWorker.cpp delete mode 100644 dom/system/gonk/NetworkWorker.h delete mode 100644 dom/system/gonk/OpenFileFinder.cpp delete mode 100644 dom/system/gonk/OpenFileFinder.h delete mode 100644 dom/system/gonk/RILSystemMessenger.jsm delete mode 100644 dom/system/gonk/RILSystemMessengerHelper.js delete mode 100644 dom/system/gonk/RILSystemMessengerHelper.manifest delete mode 100644 dom/system/gonk/RadioInterfaceLayer.js delete mode 100644 dom/system/gonk/RadioInterfaceLayer.manifest delete mode 100644 dom/system/gonk/SystemProperty.cpp delete mode 100644 dom/system/gonk/SystemProperty.h delete mode 100644 dom/system/gonk/SystemWorkerManager.cpp delete mode 100644 dom/system/gonk/SystemWorkerManager.h delete mode 100644 dom/system/gonk/TetheringService.js delete mode 100644 dom/system/gonk/TetheringService.manifest delete mode 100644 dom/system/gonk/TimeZoneSettingObserver.cpp delete mode 100644 dom/system/gonk/TimeZoneSettingObserver.h delete mode 100644 dom/system/gonk/Volume.cpp delete mode 100644 dom/system/gonk/Volume.h delete mode 100644 dom/system/gonk/VolumeCommand.cpp delete mode 100644 dom/system/gonk/VolumeCommand.h delete mode 100644 dom/system/gonk/VolumeManager.cpp delete mode 100644 dom/system/gonk/VolumeManager.h delete mode 100644 dom/system/gonk/VolumeManagerLog.h delete mode 100644 dom/system/gonk/VolumeServiceIOThread.cpp delete mode 100644 dom/system/gonk/VolumeServiceIOThread.h delete mode 100644 dom/system/gonk/VolumeServiceTest.cpp delete mode 100644 dom/system/gonk/VolumeServiceTest.h delete mode 100644 dom/system/gonk/android_audio/AudioSystem.h delete mode 100644 dom/system/gonk/android_audio/AudioTrack.h delete mode 100644 dom/system/gonk/android_audio/EffectApi.h delete mode 100644 dom/system/gonk/android_audio/IAudioFlinger.h delete mode 100644 dom/system/gonk/android_audio/IAudioFlingerClient.h delete mode 100644 dom/system/gonk/android_audio/IAudioRecord.h delete mode 100644 dom/system/gonk/android_audio/IAudioTrack.h delete mode 100644 dom/system/gonk/android_audio/IEffect.h delete mode 100644 dom/system/gonk/android_audio/IEffectClient.h delete mode 100644 dom/system/gonk/moz.build delete mode 100644 dom/system/gonk/mozstumbler/MozStumbler.cpp delete mode 100644 dom/system/gonk/mozstumbler/MozStumbler.h delete mode 100644 dom/system/gonk/mozstumbler/StumblerLogging.cpp delete mode 100644 dom/system/gonk/mozstumbler/StumblerLogging.h delete mode 100644 dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp delete mode 100644 dom/system/gonk/mozstumbler/UploadStumbleRunnable.h delete mode 100644 dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp delete mode 100644 dom/system/gonk/mozstumbler/WriteStumbleOnThread.h delete mode 100644 dom/system/gonk/nsIAudioManager.idl delete mode 100644 dom/system/gonk/nsIDataCallInterfaceService.idl delete mode 100644 dom/system/gonk/nsIDataCallManager.idl delete mode 100644 dom/system/gonk/nsIGonkDataCallInterfaceService.idl delete mode 100644 dom/system/gonk/nsINetworkInterface.idl delete mode 100644 dom/system/gonk/nsINetworkInterfaceListService.idl delete mode 100644 dom/system/gonk/nsINetworkManager.idl delete mode 100644 dom/system/gonk/nsINetworkService.idl delete mode 100644 dom/system/gonk/nsINetworkWorker.idl delete mode 100644 dom/system/gonk/nsIRadioInterfaceLayer.idl delete mode 100644 dom/system/gonk/nsISystemWorkerManager.idl delete mode 100644 dom/system/gonk/nsITetheringService.idl delete mode 100644 dom/system/gonk/nsIVolume.idl delete mode 100644 dom/system/gonk/nsIVolumeMountLock.idl delete mode 100644 dom/system/gonk/nsIVolumeService.idl delete mode 100644 dom/system/gonk/nsIVolumeStat.idl delete mode 100644 dom/system/gonk/nsIWorkerHolder.idl delete mode 100644 dom/system/gonk/nsVolume.cpp delete mode 100644 dom/system/gonk/nsVolume.h delete mode 100644 dom/system/gonk/nsVolumeMountLock.cpp delete mode 100644 dom/system/gonk/nsVolumeMountLock.h delete mode 100644 dom/system/gonk/nsVolumeService.cpp delete mode 100644 dom/system/gonk/nsVolumeService.h delete mode 100644 dom/system/gonk/nsVolumeStat.cpp delete mode 100644 dom/system/gonk/nsVolumeStat.h delete mode 100644 dom/system/gonk/ril_consts.js delete mode 100644 dom/system/gonk/ril_worker.js delete mode 100644 dom/system/gonk/ril_worker_buf_object.js delete mode 100644 dom/system/gonk/ril_worker_telephony_request_queue.js delete mode 100644 dom/system/gonk/systemlibs.js delete mode 100644 dom/system/gonk/tests/header_helpers.js delete mode 100644 dom/system/gonk/tests/marionette/head.js delete mode 100644 dom/system/gonk/tests/marionette/manifest.ini delete mode 100644 dom/system/gonk/tests/marionette/ril_jshint/README.md delete mode 100644 dom/system/gonk/tests/marionette/ril_jshint/jshint.js delete mode 100644 dom/system/gonk/tests/marionette/ril_jshint/jshintrc delete mode 100644 dom/system/gonk/tests/marionette/test_all_network_info.js delete mode 100644 dom/system/gonk/tests/marionette/test_data_connection.js delete mode 100644 dom/system/gonk/tests/marionette/test_data_connection_proxy.js delete mode 100644 dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js delete mode 100644 dom/system/gonk/tests/marionette/test_fakevolume.js delete mode 100644 dom/system/gonk/tests/marionette/test_geolocation.js delete mode 100644 dom/system/gonk/tests/marionette/test_multiple_data_connection.js delete mode 100644 dom/system/gonk/tests/marionette/test_network_active_changed.js delete mode 100644 dom/system/gonk/tests/marionette/test_network_interface_list_service.js delete mode 100644 dom/system/gonk/tests/marionette/test_network_interface_mtu.js delete mode 100644 dom/system/gonk/tests/marionette/test_ril_code_quality.py delete mode 100644 dom/system/gonk/tests/marionette/test_screen_state.js delete mode 100644 dom/system/gonk/tests/marionette/test_timezone_changes.js delete mode 100644 dom/system/gonk/tests/test_ril_system_messenger.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_barring_password.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_buf.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_cf.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_clip.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_clir.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_cw.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_ecm.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_CardLock.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_CardState.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_ruim.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_sms.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_sms_cdma.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_sms_segment_info.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_smsc_address.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_ssn.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_stk.js delete mode 100644 dom/system/gonk/tests/test_ril_worker_voiceprivacy.js delete mode 100644 dom/system/gonk/tests/xpcshell.ini delete mode 100644 dom/system/gonk/worker_buf.js delete mode 100644 hal/gonk/GonkDiskSpaceWatcher.cpp delete mode 100644 hal/gonk/GonkHal.cpp delete mode 100644 hal/gonk/GonkSensor.cpp delete mode 100644 hal/gonk/GonkSensorsHelpers.cpp delete mode 100644 hal/gonk/GonkSensorsHelpers.h delete mode 100644 hal/gonk/GonkSensorsInterface.cpp delete mode 100644 hal/gonk/GonkSensorsInterface.h delete mode 100644 hal/gonk/GonkSensorsPollInterface.cpp delete mode 100644 hal/gonk/GonkSensorsPollInterface.h delete mode 100644 hal/gonk/GonkSensorsRegistryInterface.cpp delete mode 100644 hal/gonk/GonkSensorsRegistryInterface.h delete mode 100644 hal/gonk/GonkSwitch.cpp delete mode 100644 hal/gonk/SensorsTypes.h delete mode 100644 hal/gonk/SystemService.cpp delete mode 100644 hal/gonk/UeventPoller.cpp delete mode 100644 hal/gonk/UeventPoller.h delete mode 100644 hal/gonk/fanotify.h delete mode 100644 hal/gonk/nsIRecoveryService.idl delete mode 100644 hal/gonk/tavarua.h delete mode 100644 uriloader/exthandler/gonk/nsOSHelperAppService.cpp delete mode 100644 uriloader/exthandler/gonk/nsOSHelperAppService.h delete mode 100644 widget/gonk/GeckoTouchDispatcher.cpp delete mode 100644 widget/gonk/GeckoTouchDispatcher.h delete mode 100644 widget/gonk/GfxInfo.cpp delete mode 100644 widget/gonk/GfxInfo.h delete mode 100644 widget/gonk/GonkClipboardData.cpp delete mode 100644 widget/gonk/GonkClipboardData.h delete mode 100644 widget/gonk/GonkKeyMapping.h delete mode 100644 widget/gonk/GonkMemoryPressureMonitoring.cpp delete mode 100644 widget/gonk/GonkMemoryPressureMonitoring.h delete mode 100644 widget/gonk/GonkPermission.cpp delete mode 100644 widget/gonk/GonkPermission.h delete mode 100644 widget/gonk/HwcComposer2D.cpp delete mode 100644 widget/gonk/HwcComposer2D.h delete mode 100644 widget/gonk/HwcUtils.cpp delete mode 100644 widget/gonk/HwcUtils.h delete mode 100644 widget/gonk/OrientationObserver.cpp delete mode 100644 widget/gonk/OrientationObserver.h delete mode 100644 widget/gonk/ProcessOrientation.cpp delete mode 100644 widget/gonk/ProcessOrientation.h delete mode 100644 widget/gonk/WidgetTraceEvent.cpp delete mode 100644 widget/gonk/hwchal/HwcHAL.cpp delete mode 100644 widget/gonk/hwchal/HwcHAL.h delete mode 100644 widget/gonk/hwchal/HwcHALBase.h delete mode 100644 widget/gonk/libdisplay/BootAnimation.cpp delete mode 100644 widget/gonk/libdisplay/BootAnimation.h delete mode 100644 widget/gonk/libdisplay/DisplaySurface.h delete mode 100644 widget/gonk/libdisplay/FramebufferSurface.cpp delete mode 100644 widget/gonk/libdisplay/FramebufferSurface.h delete mode 100644 widget/gonk/libdisplay/GonkDisplay.h delete mode 100644 widget/gonk/libdisplay/GonkDisplayJB.cpp delete mode 100644 widget/gonk/libdisplay/GonkDisplayJB.h delete mode 100644 widget/gonk/libdisplay/GraphicBufferAlloc.cpp delete mode 100644 widget/gonk/libdisplay/GraphicBufferAlloc.h delete mode 100644 widget/gonk/libdisplay/VirtualDisplaySurface.cpp delete mode 100644 widget/gonk/libdisplay/VirtualDisplaySurface.h delete mode 100644 widget/gonk/libdisplay/moz.build delete mode 100644 widget/gonk/libui/EventHub.cpp delete mode 100644 widget/gonk/libui/EventHub.h delete mode 100644 widget/gonk/libui/Input.cpp delete mode 100644 widget/gonk/libui/Input.h delete mode 100644 widget/gonk/libui/InputApplication.cpp delete mode 100644 widget/gonk/libui/InputApplication.h delete mode 100644 widget/gonk/libui/InputDevice.cpp delete mode 100644 widget/gonk/libui/InputDevice.h delete mode 100644 widget/gonk/libui/InputDispatcher.cpp delete mode 100644 widget/gonk/libui/InputDispatcher.h delete mode 100644 widget/gonk/libui/InputListener.cpp delete mode 100644 widget/gonk/libui/InputListener.h delete mode 100644 widget/gonk/libui/InputManager.cpp delete mode 100644 widget/gonk/libui/InputManager.h delete mode 100644 widget/gonk/libui/InputReader.cpp delete mode 100644 widget/gonk/libui/InputReader.h delete mode 100644 widget/gonk/libui/InputTransport.cpp delete mode 100644 widget/gonk/libui/InputTransport.h delete mode 100644 widget/gonk/libui/InputWindow.cpp delete mode 100644 widget/gonk/libui/InputWindow.h delete mode 100644 widget/gonk/libui/KeyCharacterMap.cpp delete mode 100644 widget/gonk/libui/KeyCharacterMap.h delete mode 100644 widget/gonk/libui/KeyLayoutMap.cpp delete mode 100644 widget/gonk/libui/KeyLayoutMap.h delete mode 100644 widget/gonk/libui/Keyboard.cpp delete mode 100644 widget/gonk/libui/Keyboard.h delete mode 100644 widget/gonk/libui/KeycodeLabels.h delete mode 100644 widget/gonk/libui/PointerController.cpp delete mode 100644 widget/gonk/libui/PointerController.h delete mode 100644 widget/gonk/libui/PowerManager.h delete mode 100644 widget/gonk/libui/SpriteController.cpp delete mode 100644 widget/gonk/libui/SpriteController.h delete mode 100644 widget/gonk/libui/Tokenizer.cpp delete mode 100644 widget/gonk/libui/Tokenizer.h delete mode 100644 widget/gonk/libui/Trace.h delete mode 100644 widget/gonk/libui/VelocityControl.cpp delete mode 100644 widget/gonk/libui/VelocityControl.h delete mode 100644 widget/gonk/libui/VelocityTracker.cpp delete mode 100644 widget/gonk/libui/VelocityTracker.h delete mode 100644 widget/gonk/libui/VirtualKeyMap.cpp delete mode 100644 widget/gonk/libui/VirtualKeyMap.h delete mode 100644 widget/gonk/libui/android_input.h delete mode 100644 widget/gonk/libui/android_keycodes.h delete mode 100644 widget/gonk/libui/cutils_log.h delete mode 100644 widget/gonk/libui/cutils_trace.h delete mode 100644 widget/gonk/libui/linux_input.h delete mode 100644 widget/gonk/libui/sha1.c delete mode 100644 widget/gonk/libui/sha1.h delete mode 100644 widget/gonk/moz.build delete mode 100644 widget/gonk/nativewindow/FakeSurfaceComposer.cpp delete mode 100644 widget/gonk/nativewindow/FakeSurfaceComposer.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueue.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueJB.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueJB.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueKK.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueKK.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp delete mode 100644 widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h delete mode 100644 widget/gonk/nativewindow/GonkConsumerBaseJB.cpp delete mode 100644 widget/gonk/nativewindow/GonkConsumerBaseJB.h delete mode 100644 widget/gonk/nativewindow/GonkConsumerBaseKK.cpp delete mode 100644 widget/gonk/nativewindow/GonkConsumerBaseKK.h delete mode 100644 widget/gonk/nativewindow/GonkConsumerBaseLL.cpp delete mode 100644 widget/gonk/nativewindow/GonkConsumerBaseLL.h delete mode 100644 widget/gonk/nativewindow/GonkNativeWindow.h delete mode 100644 widget/gonk/nativewindow/GonkNativeWindowJB.cpp delete mode 100644 widget/gonk/nativewindow/GonkNativeWindowJB.h delete mode 100644 widget/gonk/nativewindow/GonkNativeWindowKK.cpp delete mode 100644 widget/gonk/nativewindow/GonkNativeWindowKK.h delete mode 100644 widget/gonk/nativewindow/GonkNativeWindowLL.cpp delete mode 100644 widget/gonk/nativewindow/GonkNativeWindowLL.h delete mode 100644 widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h delete mode 100644 widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp delete mode 100644 widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h delete mode 100644 widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp delete mode 100644 widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h delete mode 100644 widget/gonk/nativewindow/moz.build delete mode 100644 widget/gonk/nsAppShell.cpp delete mode 100644 widget/gonk/nsAppShell.h delete mode 100644 widget/gonk/nsClipboard.cpp delete mode 100644 widget/gonk/nsClipboard.h delete mode 100644 widget/gonk/nsIdleServiceGonk.cpp delete mode 100644 widget/gonk/nsIdleServiceGonk.h delete mode 100644 widget/gonk/nsLookAndFeel.cpp delete mode 100644 widget/gonk/nsLookAndFeel.h delete mode 100644 widget/gonk/nsScreenManagerGonk.cpp delete mode 100644 widget/gonk/nsScreenManagerGonk.h delete mode 100644 widget/gonk/nsWidgetFactory.cpp delete mode 100644 widget/gonk/nsWindow.cpp delete mode 100644 widget/gonk/nsWindow.h diff --git a/dom/media/MediaPermissionGonk.cpp b/dom/media/MediaPermissionGonk.cpp deleted file mode 100644 index 2a9cbf331..000000000 --- a/dom/media/MediaPermissionGonk.cpp +++ /dev/null @@ -1,522 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MediaManager.h" -#include "MediaPermissionGonk.h" - -#include "nsArray.h" -#include "nsCOMPtr.h" -#include "nsIContentPermissionPrompt.h" -#include "nsIDocument.h" -#include "nsIDOMNavigatorUserMedia.h" -#include "nsIStringEnumerator.h" -#include "nsJSUtils.h" -#include "nsQueryObject.h" -#include "nsPIDOMWindow.h" -#include "nsTArray.h" -#include "GetUserMediaRequest.h" -#include "mozilla/dom/PBrowserChild.h" -#include "mozilla/dom/MediaStreamTrackBinding.h" -#include "mozilla/dom/MediaStreamError.h" -#include "nsISupportsPrimitives.h" -#include "nsServiceManagerUtils.h" -#include "nsArrayUtils.h" -#include "nsContentPermissionHelper.h" -#include "mozilla/dom/PermissionMessageUtils.h" - -#define AUDIO_PERMISSION_NAME "audio-capture" -#define VIDEO_PERMISSION_NAME "video-capture" - -using namespace mozilla::dom; - -namespace mozilla { - -static MediaPermissionManager *gMediaPermMgr = nullptr; - -static void -CreateDeviceNameList(nsTArray > &aDevices, - nsTArray &aDeviceNameList) -{ - for (uint32_t i = 0; i < aDevices.Length(); ++i) { - nsString name; - nsresult rv = aDevices[i]->GetName(name); - NS_ENSURE_SUCCESS_VOID(rv); - aDeviceNameList.AppendElement(name); - } -} - -static already_AddRefed -FindDeviceByName(nsTArray > &aDevices, - const nsAString &aDeviceName) -{ - for (uint32_t i = 0; i < aDevices.Length(); ++i) { - nsCOMPtr device = aDevices[i]; - nsString deviceName; - device->GetName(deviceName); - if (deviceName.Equals(aDeviceName)) { - return device.forget(); - } - } - - return nullptr; -} - -// Helper function for notifying permission granted -static nsresult -NotifyPermissionAllow(const nsAString &aCallID, nsTArray > &aDevices) -{ - nsresult rv; - nsCOMPtr array = nsArray::Create(); - - for (uint32_t i = 0; i < aDevices.Length(); ++i) { - rv = array->AppendElement(aDevices.ElementAt(i), /*weak =*/ false); - NS_ENSURE_SUCCESS(rv, rv); - } - - nsCOMPtr obs = services::GetObserverService(); - NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); - - return obs->NotifyObservers(array, "getUserMedia:response:allow", - aCallID.BeginReading()); -} - -// Helper function for notifying permision denial or error -static nsresult -NotifyPermissionDeny(const nsAString &aCallID, const nsAString &aErrorMsg) -{ - nsresult rv; - nsCOMPtr supportsString = - do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = supportsString->SetData(aErrorMsg); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr obs = services::GetObserverService(); - NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE); - - return obs->NotifyObservers(supportsString, "getUserMedia:response:deny", - aCallID.BeginReading()); -} - -namespace { - -/** - * MediaPermissionRequest will send a prompt ipdl request to b2g process according - * to its owned type. - */ -class MediaPermissionRequest : public nsIContentPermissionRequest -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICONTENTPERMISSIONREQUEST - - MediaPermissionRequest(RefPtr &aRequest, - nsTArray > &aDevices); - - already_AddRefed GetOwner(); - -protected: - virtual ~MediaPermissionRequest() {} - -private: - nsresult DoAllow(const nsString &audioDevice, const nsString &videoDevice); - - bool mAudio; // Request for audio permission - bool mVideo; // Request for video permission - RefPtr mRequest; - nsTArray > mAudioDevices; // candidate audio devices - nsTArray > mVideoDevices; // candidate video devices - nsCOMPtr mRequester; -}; - -// MediaPermissionRequest -NS_IMPL_ISUPPORTS(MediaPermissionRequest, nsIContentPermissionRequest) - -MediaPermissionRequest::MediaPermissionRequest(RefPtr &aRequest, - nsTArray > &aDevices) - : mRequest(aRequest) -{ - dom::MediaStreamConstraints constraints; - mRequest->GetConstraints(constraints); - - mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean(); - mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean(); - - for (uint32_t i = 0; i < aDevices.Length(); ++i) { - nsCOMPtr device(aDevices[i]); - nsAutoString deviceType; - device->GetType(deviceType); - if (mAudio && deviceType.EqualsLiteral("audio")) { - mAudioDevices.AppendElement(device); - } - if (mVideo && deviceType.EqualsLiteral("video")) { - mVideoDevices.AppendElement(device); - } - } - - nsCOMPtr window = GetOwner(); - mRequester = new nsContentPermissionRequester(window); -} - -// nsIContentPermissionRequest methods -NS_IMETHODIMP -MediaPermissionRequest::GetTypes(nsIArray** aTypes) -{ - nsCOMPtr types = do_CreateInstance(NS_ARRAY_CONTRACTID); - //XXX append device list - if (mAudio) { - nsTArray audioDeviceNames; - CreateDeviceNameList(mAudioDevices, audioDeviceNames); - nsCOMPtr AudioType = - new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME), - NS_LITERAL_CSTRING("unused"), - audioDeviceNames); - types->AppendElement(AudioType, false); - } - if (mVideo) { - nsTArray videoDeviceNames; - CreateDeviceNameList(mVideoDevices, videoDeviceNames); - nsCOMPtr VideoType = - new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME), - NS_LITERAL_CSTRING("unused"), - videoDeviceNames); - types->AppendElement(VideoType, false); - } - NS_IF_ADDREF(*aTypes = types); - - return NS_OK; -} - -NS_IMETHODIMP -MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal) -{ - NS_ENSURE_ARG_POINTER(aRequestingPrincipal); - - nsCOMPtr window = - nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner(); - NS_ENSURE_TRUE(window, NS_ERROR_FAILURE); - - nsCOMPtr doc = window->GetExtantDoc(); - NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE); - - NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal()); - return NS_OK; -} - -NS_IMETHODIMP -MediaPermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow) -{ - NS_ENSURE_ARG_POINTER(aRequestingWindow); - nsCOMPtr window = - nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner(); - window.forget(aRequestingWindow); - return NS_OK; -} - -NS_IMETHODIMP -MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement) -{ - NS_ENSURE_ARG_POINTER(aRequestingElement); - *aRequestingElement = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -MediaPermissionRequest::Cancel() -{ - nsString callID; - mRequest->GetCallID(callID); - NotifyPermissionDeny(callID, NS_LITERAL_STRING("SecurityError")); - return NS_OK; -} - -NS_IMETHODIMP -MediaPermissionRequest::Allow(JS::HandleValue aChoices) -{ - // check if JS object - if (!aChoices.isObject()) { - MOZ_ASSERT(false, "Not a correct format of PermissionChoice"); - return NS_ERROR_INVALID_ARG; - } - // iterate through audio-capture and video-capture - AutoJSAPI jsapi; - if (!jsapi.Init(&aChoices.toObject())) { - return NS_ERROR_UNEXPECTED; - } - JSContext* cx = jsapi.cx(); - JS::Rooted obj(cx, &aChoices.toObject()); - JS::Rooted v(cx); - - // get selected audio device name - nsString audioDevice; - if (mAudio) { - if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) { - return NS_ERROR_FAILURE; - } - nsAutoJSString deviceName; - if (!deviceName.init(cx, v)) { - MOZ_ASSERT(false, "Couldn't initialize string from aChoices"); - return NS_ERROR_FAILURE; - } - audioDevice = deviceName; - } - - // get selected video device name - nsString videoDevice; - if (mVideo) { - if (!JS_GetProperty(cx, obj, VIDEO_PERMISSION_NAME, &v) || !v.isString()) { - return NS_ERROR_FAILURE; - } - nsAutoJSString deviceName; - if (!deviceName.init(cx, v)) { - MOZ_ASSERT(false, "Couldn't initialize string from aChoices"); - return NS_ERROR_FAILURE; - } - videoDevice = deviceName; - } - - return DoAllow(audioDevice, videoDevice); -} - -NS_IMETHODIMP -MediaPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester) -{ - NS_ENSURE_ARG_POINTER(aRequester); - - nsCOMPtr requester = mRequester; - requester.forget(aRequester); - return NS_OK; -} - -nsresult -MediaPermissionRequest::DoAllow(const nsString &audioDevice, - const nsString &videoDevice) -{ - nsTArray > selectedDevices; - if (mAudio) { - nsCOMPtr device = - FindDeviceByName(mAudioDevices, audioDevice); - if (device) { - selectedDevices.AppendElement(device); - } - } - - if (mVideo) { - nsCOMPtr device = - FindDeviceByName(mVideoDevices, videoDevice); - if (device) { - selectedDevices.AppendElement(device); - } - } - - nsString callID; - mRequest->GetCallID(callID); - return NotifyPermissionAllow(callID, selectedDevices); -} - -already_AddRefed -MediaPermissionRequest::GetOwner() -{ - nsCOMPtr window = - nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner(); - return window.forget(); -} - -// Success callback for MediaManager::GetUserMediaDevices(). -class MediaDeviceSuccessCallback: public nsIGetUserMediaDevicesSuccessCallback -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIGETUSERMEDIADEVICESSUCCESSCALLBACK - - explicit MediaDeviceSuccessCallback(RefPtr &aRequest) - : mRequest(aRequest) {} - -protected: - virtual ~MediaDeviceSuccessCallback() {} - -private: - nsresult DoPrompt(RefPtr &req); - RefPtr mRequest; -}; - -NS_IMPL_ISUPPORTS(MediaDeviceSuccessCallback, nsIGetUserMediaDevicesSuccessCallback) - -// nsIGetUserMediaDevicesSuccessCallback method -NS_IMETHODIMP -MediaDeviceSuccessCallback::OnSuccess(nsIVariant* aDevices) -{ - nsIID elementIID; - uint16_t elementType; - void* rawArray; - uint32_t arrayLen; - - nsresult rv; - rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray); - NS_ENSURE_SUCCESS(rv, rv); - - if (elementType != nsIDataType::VTYPE_INTERFACE) { - free(rawArray); - return NS_ERROR_FAILURE; - } - - // Create array for nsIMediaDevice - nsTArray > devices; - - nsISupports **supportsArray = reinterpret_cast(rawArray); - for (uint32_t i = 0; i < arrayLen; ++i) { - nsCOMPtr device(do_QueryInterface(supportsArray[i])); - devices.AppendElement(device); - NS_IF_RELEASE(supportsArray[i]); // explicitly decrease reference count for raw pointer - } - free(rawArray); // explicitly free for the memory from nsIVariant::GetAsArray - - // Send MediaPermissionRequest - RefPtr req = new MediaPermissionRequest(mRequest, devices); - rv = DoPrompt(req); - - NS_ENSURE_SUCCESS(rv, rv); - return NS_OK; -} - -// Trigger permission prompt UI -nsresult -MediaDeviceSuccessCallback::DoPrompt(RefPtr &req) -{ - nsCOMPtr window(req->GetOwner()); - return dom::nsContentPermissionUtils::AskPermission(req, window); -} - -// Error callback for MediaManager::GetUserMediaDevices() -class MediaDeviceErrorCallback: public nsIDOMGetUserMediaErrorCallback -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK - - explicit MediaDeviceErrorCallback(const nsAString &aCallID) - : mCallID(aCallID) {} - -protected: - virtual ~MediaDeviceErrorCallback() {} - -private: - const nsString mCallID; -}; - -NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback) - -// nsIDOMGetUserMediaErrorCallback method -NS_IMETHODIMP -MediaDeviceErrorCallback::OnError(nsISupports* aError) -{ - RefPtr error = do_QueryObject(aError); - if (!error) { - return NS_ERROR_NO_INTERFACE; - } - - nsString name; - error->GetName(name); - return NotifyPermissionDeny(mCallID, name); -} - -} // namespace anonymous - -// MediaPermissionManager -NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver) - -MediaPermissionManager* -MediaPermissionManager::GetInstance() -{ - if (!gMediaPermMgr) { - gMediaPermMgr = new MediaPermissionManager(); - } - - return gMediaPermMgr; -} - -MediaPermissionManager::MediaPermissionManager() -{ - nsCOMPtr obs = services::GetObserverService(); - if (obs) { - obs->AddObserver(this, "getUserMedia:request", false); - obs->AddObserver(this, "xpcom-shutdown", false); - } -} - -MediaPermissionManager::~MediaPermissionManager() -{ - this->Deinit(); -} - -nsresult -MediaPermissionManager::Deinit() -{ - nsCOMPtr obs = services::GetObserverService(); - if (obs) { - obs->RemoveObserver(this, "getUserMedia:request"); - obs->RemoveObserver(this, "xpcom-shutdown"); - } - return NS_OK; -} - -// nsIObserver method -NS_IMETHODIMP -MediaPermissionManager::Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) -{ - nsresult rv; - if (!strcmp(aTopic, "getUserMedia:request")) { - RefPtr req = - static_cast(aSubject); - rv = HandleRequest(req); - - if (NS_FAILED(rv)) { - nsString callID; - req->GetCallID(callID); - NotifyPermissionDeny(callID, NS_LITERAL_STRING("unable to enumerate media device")); - } - } else if (!strcmp(aTopic, "xpcom-shutdown")) { - rv = this->Deinit(); - } else { - // not reachable - rv = NS_ERROR_FAILURE; - } - return rv; -} - -// Handle GetUserMediaRequest, query available media device first. -nsresult -MediaPermissionManager::HandleRequest(RefPtr &req) -{ - nsString callID; - req->GetCallID(callID); - uint64_t innerWindowID = req->InnerWindowID(); - - nsCOMPtr innerWindow = - nsGlobalWindow::GetInnerWindowWithId(innerWindowID)->AsInner(); - if (!innerWindow) { - MOZ_ASSERT(false, "No inner window"); - return NS_ERROR_FAILURE; - } - - nsCOMPtr onSuccess = - new MediaDeviceSuccessCallback(req); - nsCOMPtr onError = - new MediaDeviceErrorCallback(callID); - - dom::MediaStreamConstraints constraints; - req->GetConstraints(constraints); - - RefPtr MediaMgr = MediaManager::GetInstance(); - nsresult rv = MediaMgr->GetUserMediaDevices(innerWindow, constraints, - onSuccess, onError, - innerWindowID, callID); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -} // namespace mozilla diff --git a/dom/media/MediaPermissionGonk.h b/dom/media/MediaPermissionGonk.h deleted file mode 100644 index 0a2fac056..000000000 --- a/dom/media/MediaPermissionGonk.h +++ /dev/null @@ -1,39 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef DOM_MEDIA_MEDIAPERMISSIONGONK_H -#define DOM_MEDIA_MEDIAPERMISSIONGONK_H - -#include "nsError.h" -#include "nsIObserver.h" -#include "nsISupportsImpl.h" -#include "GetUserMediaRequest.h" - -namespace mozilla { - -/** - * The observer to create the MediaPermissionMgr. This is the entry point of - * permission request on b2g. - */ -class MediaPermissionManager : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - static MediaPermissionManager* GetInstance(); - -protected: - virtual ~MediaPermissionManager(); - -private: - MediaPermissionManager(); - nsresult Deinit(); - nsresult HandleRequest(RefPtr &req); -}; - -} // namespace mozilla - -#endif // DOM_MEDIA_MEDIAPERMISSIONGONK_H - diff --git a/dom/media/moz.build b/dom/media/moz.build index d1885793b..4d036a5f6 100644 --- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -169,11 +169,6 @@ IPDL_SOURCES += [ 'webrtc/PWebrtcGlobal.ipdl' ] -if CONFIG['MOZ_B2G']: - EXPORTS.mozilla += [ - 'MediaPermissionGonk.h', - ] - EXPORTS.mozilla.dom += [ 'AudioStreamTrack.h', 'AudioTrack.h', @@ -270,11 +265,6 @@ UNIFIED_SOURCES += [ if CONFIG['OS_TARGET'] == 'WINNT': SOURCES += [ 'ThreadPoolCOMListener.cpp' ] -if CONFIG['MOZ_B2G']: - SOURCES += [ - 'MediaPermissionGonk.cpp', - ] - # DecoderTraits.cpp needs to be built separately because of Mac OS X headers. SOURCES += [ 'DecoderTraits.cpp', @@ -325,9 +315,6 @@ else: if CONFIG['ANDROID_VERSION'] > '15': DEFINES['MOZ_OMX_WEBM_DECODER'] = True -if CONFIG['MOZ_GONK_MEDIACODEC']: - DEFINES['MOZ_GONK_MEDIACODEC'] = True - include('/ipc/chromium/chromium-config.mozbuild') # Suppress some GCC warnings being treated as errors: diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp b/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp deleted file mode 100644 index 0bc3fbea9..000000000 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.cpp +++ /dev/null @@ -1,268 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "MediaCodecProxy.h" -#include -#include -#include -#include "GonkAudioDecoderManager.h" -#include "MediaDecoderReader.h" -#include "VideoUtils.h" -#include "nsTArray.h" -#include "mozilla/Logging.h" -#include "stagefright/MediaBuffer.h" -#include "stagefright/MetaData.h" -#include "stagefright/MediaErrors.h" -#include -#include -#include "media/openmax/OMX_Audio.h" -#include "MediaData.h" -#include "MediaInfo.h" - -#define CODECCONFIG_TIMEOUT_US 10000LL -#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL - -#include -#define GADM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkAudioDecoderManager", __VA_ARGS__) - -#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -using namespace android; -typedef android::MediaCodecProxy MediaCodecProxy; - -namespace mozilla { - -GonkAudioDecoderManager::GonkAudioDecoderManager(const AudioInfo& aConfig) - : mAudioChannels(aConfig.mChannels) - , mAudioRate(aConfig.mRate) - , mAudioProfile(aConfig.mProfile) - , mAudioCompactor(mAudioQueue) -{ - MOZ_COUNT_CTOR(GonkAudioDecoderManager); - MOZ_ASSERT(mAudioChannels); - mCodecSpecificData = aConfig.mCodecSpecificConfig; - mMimeType = aConfig.mMimeType; -} - -GonkAudioDecoderManager::~GonkAudioDecoderManager() -{ - MOZ_COUNT_DTOR(GonkAudioDecoderManager); -} - -RefPtr -GonkAudioDecoderManager::Init() -{ - if (InitMediaCodecProxy()) { - return InitPromise::CreateAndResolve(TrackType::kAudioTrack, __func__); - } else { - return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } -} - -bool -GonkAudioDecoderManager::InitMediaCodecProxy() -{ - status_t rv = OK; - if (!InitLoopers(MediaData::AUDIO_DATA)) { - return false; - } - - mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, mMimeType.get(), false); - if (!mDecoder.get()) { - return false; - } - if (!mDecoder->AllocateAudioMediaCodec()) - { - mDecoder = nullptr; - return false; - } - sp format = new AMessage; - // Fixed values - GADM_LOG("Configure audio mime type:%s, chan no:%d, sample-rate:%d, profile:%d", - mMimeType.get(), mAudioChannels, mAudioRate, mAudioProfile); - format->setString("mime", mMimeType.get()); - format->setInt32("channel-count", mAudioChannels); - format->setInt32("sample-rate", mAudioRate); - format->setInt32("aac-profile", mAudioProfile); - status_t err = mDecoder->configure(format, nullptr, nullptr, 0); - if (err != OK || !mDecoder->Prepare()) { - return false; - } - - if (mMimeType.EqualsLiteral("audio/mp4a-latm")) { - rv = mDecoder->Input(mCodecSpecificData->Elements(), mCodecSpecificData->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG, - CODECCONFIG_TIMEOUT_US); - } - - if (rv == OK) { - return true; - } else { - GADM_LOG("Failed to input codec specific data!"); - return false; - } -} - -nsresult -GonkAudioDecoderManager::CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset) -{ - if (!(aBuffer != nullptr && aBuffer->data() != nullptr)) { - GADM_LOG("Audio Buffer is not valid!"); - return NS_ERROR_UNEXPECTED; - } - - int64_t timeUs; - if (!aBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - return NS_ERROR_UNEXPECTED; - } - - if (aBuffer->range_length() == 0) { - // Some decoders may return spurious empty buffers that we just want to ignore - // quoted from Android's AwesomePlayer.cpp - return NS_ERROR_NOT_AVAILABLE; - } - - if (mLastTime > timeUs) { - GADM_LOG("Output decoded sample time is revert. time=%lld", timeUs); - MOZ_ASSERT(false); - return NS_ERROR_NOT_AVAILABLE; - } - mLastTime = timeUs; - - const uint8_t *data = static_cast(aBuffer->data()); - size_t dataOffset = aBuffer->range_offset(); - size_t size = aBuffer->range_length(); - - uint32_t frames = size / (2 * mAudioChannels); - - CheckedInt64 duration = FramesToUsecs(frames, mAudioRate); - if (!duration.isValid()) { - return NS_ERROR_UNEXPECTED; - } - - typedef AudioCompactor::NativeCopy OmxCopy; - mAudioCompactor.Push(aStreamOffset, - timeUs, - mAudioRate, - frames, - mAudioChannels, - OmxCopy(data+dataOffset, - size, - mAudioChannels)); - return NS_OK; -} - -nsresult -GonkAudioDecoderManager::Output(int64_t aStreamOffset, - RefPtr& aOutData) -{ - aOutData = nullptr; - if (mAudioQueue.GetSize() > 0) { - aOutData = mAudioQueue.PopFront(); - return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK; - } - - status_t err; - MediaBuffer* audioBuffer = nullptr; - err = mDecoder->Output(&audioBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US); - AutoReleaseMediaBuffer a(audioBuffer, mDecoder.get()); - - switch (err) { - case OK: - { - nsresult rv = CreateAudioData(audioBuffer, aStreamOffset); - NS_ENSURE_SUCCESS(rv, rv); - break; - } - case android::INFO_FORMAT_CHANGED: - { - // If the format changed, update our cached info. - GADM_LOG("Decoder format changed"); - sp audioCodecFormat; - - if (mDecoder->getOutputFormat(&audioCodecFormat) != OK || - audioCodecFormat == nullptr) { - return NS_ERROR_UNEXPECTED; - } - - int32_t codec_channel_count = 0; - int32_t codec_sample_rate = 0; - - if (!audioCodecFormat->findInt32("channel-count", &codec_channel_count) || - !audioCodecFormat->findInt32("sample-rate", &codec_sample_rate)) { - return NS_ERROR_UNEXPECTED; - } - - // Update AudioInfo - AudioConfig::ChannelLayout layout(codec_channel_count); - if (!layout.IsValid()) { - return NS_ERROR_FAILURE; - } - mAudioChannels = codec_channel_count; - mAudioRate = codec_sample_rate; - - return Output(aStreamOffset, aOutData); - } - case android::INFO_OUTPUT_BUFFERS_CHANGED: - { - GADM_LOG("Info Output Buffers Changed"); - if (mDecoder->UpdateOutputBuffers()) { - return Output(aStreamOffset, aOutData); - } - return NS_ERROR_FAILURE; - } - case -EAGAIN: - { - return NS_ERROR_NOT_AVAILABLE; - } - case android::ERROR_END_OF_STREAM: - { - GADM_LOG("Got EOS frame!"); - nsresult rv = CreateAudioData(audioBuffer, aStreamOffset); - NS_ENSURE_SUCCESS(rv, NS_ERROR_ABORT); - MOZ_ASSERT(mAudioQueue.GetSize() > 0); - mAudioQueue.Finish(); - break; - } - case -ETIMEDOUT: - { - GADM_LOG("Timeout. can try again next time"); - return NS_ERROR_UNEXPECTED; - } - default: - { - GADM_LOG("Decoder failed, err=%d", err); - return NS_ERROR_UNEXPECTED; - } - } - - if (mAudioQueue.GetSize() > 0) { - aOutData = mAudioQueue.PopFront(); - // Return NS_ERROR_ABORT at the last sample. - return mAudioQueue.AtEndOfStream() ? NS_ERROR_ABORT : NS_OK; - } - - return NS_ERROR_NOT_AVAILABLE; -} - -void -GonkAudioDecoderManager::ProcessFlush() -{ - GADM_LOG("FLUSH<<<"); - mAudioQueue.Reset(); - GADM_LOG(">>>FLUSH"); - GonkDecoderManager::ProcessFlush(); -} - -void -GonkAudioDecoderManager::ResetEOS() -{ - GADM_LOG("ResetEOS(<<<"); - mAudioQueue.Reset(); - GADM_LOG(">>>ResetEOS("); - GonkDecoderManager::ResetEOS(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkAudioDecoderManager.h b/dom/media/platforms/gonk/GonkAudioDecoderManager.h deleted file mode 100644 index aa35d620e..000000000 --- a/dom/media/platforms/gonk/GonkAudioDecoderManager.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if !defined(GonkAudioDecoderManager_h_) -#define GonkAudioDecoderManager_h_ - -#include "AudioCompactor.h" -#include "mozilla/RefPtr.h" -#include "GonkMediaDataDecoder.h" - -using namespace android; - -namespace android { -class MOZ_EXPORT MediaBuffer; -} // namespace android - -namespace mozilla { - -class GonkAudioDecoderManager : public GonkDecoderManager { -typedef android::MediaCodecProxy MediaCodecProxy; -public: - GonkAudioDecoderManager(const AudioInfo& aConfig); - - virtual ~GonkAudioDecoderManager(); - - RefPtr Init() override; - - nsresult Output(int64_t aStreamOffset, - RefPtr& aOutput) override; - - void ProcessFlush() override; - virtual void ResetEOS() override; - - const char* GetDescriptionName() const override - { - return "gonk audio decoder"; - } - -private: - bool InitMediaCodecProxy(); - - nsresult CreateAudioData(MediaBuffer* aBuffer, int64_t aStreamOffset); - - uint32_t mAudioChannels; - uint32_t mAudioRate; - const uint32_t mAudioProfile; - - MediaQueue mAudioQueue; - - AudioCompactor mAudioCompactor; - -}; - -} // namespace mozilla - -#endif // GonkAudioDecoderManager_h_ diff --git a/dom/media/platforms/gonk/GonkDecoderModule.cpp b/dom/media/platforms/gonk/GonkDecoderModule.cpp deleted file mode 100644 index 537bc299c..000000000 --- a/dom/media/platforms/gonk/GonkDecoderModule.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "GonkDecoderModule.h" -#include "GonkVideoDecoderManager.h" -#include "GonkAudioDecoderManager.h" -#include "mozilla/DebugOnly.h" -#include "GonkMediaDataDecoder.h" - -namespace mozilla { -GonkDecoderModule::GonkDecoderModule() -{ -} - -GonkDecoderModule::~GonkDecoderModule() -{ -} - -already_AddRefed -GonkDecoderModule::CreateVideoDecoder(const CreateDecoderParams& aParams) -{ - RefPtr decoder = - new GonkMediaDataDecoder(new GonkVideoDecoderManager(aParams.mImageContainer, aParams.VideoConfig()), - aParams.mCallback); - return decoder.forget(); -} - -already_AddRefed -GonkDecoderModule::CreateAudioDecoder(const CreateDecoderParams& aParams) -{ - RefPtr decoder = - new GonkMediaDataDecoder(new GonkAudioDecoderManager(aParams.AudioConfig()), - aParams.mCallback); - return decoder.forget(); -} - -PlatformDecoderModule::ConversionRequired -GonkDecoderModule::DecoderNeedsConversion(const TrackInfo& aConfig) const -{ - if (aConfig.IsVideo()) { - return ConversionRequired::kNeedAnnexB; - } else { - return ConversionRequired::kNeedNone; - } -} - -bool -GonkDecoderModule::SupportsMimeType(const nsACString& aMimeType, - DecoderDoctorDiagnostics* aDiagnostics) const -{ - return aMimeType.EqualsLiteral("audio/mp4a-latm") || - aMimeType.EqualsLiteral("audio/3gpp") || - aMimeType.EqualsLiteral("audio/amr-wb") || - aMimeType.EqualsLiteral("audio/mpeg") || - aMimeType.EqualsLiteral("video/mp4") || - aMimeType.EqualsLiteral("video/mp4v-es") || - aMimeType.EqualsLiteral("video/avc") || - aMimeType.EqualsLiteral("video/3gpp"); -} - -} // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkDecoderModule.h b/dom/media/platforms/gonk/GonkDecoderModule.h deleted file mode 100644 index 4f29f0e75..000000000 --- a/dom/media/platforms/gonk/GonkDecoderModule.h +++ /dev/null @@ -1,37 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if !defined(GonkPlatformDecoderModule_h_) -#define GonkPlatformDecoderModule_h_ - -#include "PlatformDecoderModule.h" - -namespace mozilla { - -class GonkDecoderModule : public PlatformDecoderModule { -public: - GonkDecoderModule(); - virtual ~GonkDecoderModule(); - - // Decode thread. - already_AddRefed - CreateVideoDecoder(const CreateDecoderParams& aParams) override; - - // Decode thread. - already_AddRefed - CreateAudioDecoder(const CreateDecoderParams& aParams) override; - - ConversionRequired - DecoderNeedsConversion(const TrackInfo& aConfig) const override; - - bool SupportsMimeType(const nsACString& aMimeType, - DecoderDoctorDiagnostics* aDiagnostics) const override; - -}; - -} // namespace mozilla - -#endif diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp b/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp deleted file mode 100644 index 6d59d72e1..000000000 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "GonkMediaDataDecoder.h" -#include "VideoUtils.h" -#include "nsTArray.h" -#include "MediaCodecProxy.h" - -#include - -#include "mozilla/Logging.h" -#include -#define GMDD_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkMediaDataDecoder", __VA_ARGS__) -#define INPUT_TIMEOUT_US 0LL // Don't wait for buffer if none is available. -#define MIN_QUEUED_SAMPLES 2 - -#ifdef DEBUG -#include -#endif - -#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) - -using namespace android; - -namespace mozilla { - -bool -GonkDecoderManager::InitLoopers(MediaData::Type aType) -{ - MOZ_ASSERT(mDecodeLooper.get() == nullptr && mTaskLooper.get() == nullptr); - MOZ_ASSERT(aType == MediaData::VIDEO_DATA || aType == MediaData::AUDIO_DATA); - - const char* suffix = (aType == MediaData::VIDEO_DATA ? "video" : "audio"); - mDecodeLooper = new ALooper; - android::AString name("MediaCodecProxy/"); - name.append(suffix); - mDecodeLooper->setName(name.c_str()); - - mTaskLooper = new ALooper; - name.setTo("GonkDecoderManager/"); - name.append(suffix); - mTaskLooper->setName(name.c_str()); - mTaskLooper->registerHandler(this); - -#ifdef DEBUG - sp findThreadId(new AMessage(kNotifyFindLooperId, id())); - findThreadId->post(); -#endif - - return mDecodeLooper->start() == OK && mTaskLooper->start() == OK; -} - -nsresult -GonkDecoderManager::Input(MediaRawData* aSample) -{ - RefPtr sample; - - if (aSample) { - sample = aSample; - } else { - // It means EOS with empty sample. - sample = new MediaRawData(); - } - { - MutexAutoLock lock(mMutex); - mQueuedSamples.AppendElement(sample); - } - - sp input = new AMessage(kNotifyProcessInput, id()); - if (!aSample) { - input->setInt32("input-eos", 1); - } - input->post(); - return NS_OK; -} - -int32_t -GonkDecoderManager::ProcessQueuedSamples() -{ - MOZ_ASSERT(OnTaskLooper()); - - MutexAutoLock lock(mMutex); - status_t rv; - while (mQueuedSamples.Length()) { - RefPtr data = mQueuedSamples.ElementAt(0); - rv = mDecoder->Input(reinterpret_cast(data->Data()), - data->Size(), - data->mTime, - 0, - INPUT_TIMEOUT_US); - if (rv == OK) { - mQueuedSamples.RemoveElementAt(0); - mWaitOutput.AppendElement(WaitOutputInfo(data->mOffset, data->mTime, - /* eos */ data->Data() == nullptr)); - } else if (rv == -EAGAIN || rv == -ETIMEDOUT) { - // In most cases, EAGAIN or ETIMEOUT are safe because OMX can't fill - // buffer on time. - break; - } else { - return rv; - } - } - return mQueuedSamples.Length(); -} - -nsresult -GonkDecoderManager::Flush() -{ - if (mDecoder == nullptr) { - GMDD_LOG("Decoder is not initialized"); - return NS_ERROR_UNEXPECTED; - } - - if (!mInitPromise.IsEmpty()) { - return NS_OK; - } - - { - MutexAutoLock lock(mMutex); - mQueuedSamples.Clear(); - } - - MonitorAutoLock lock(mFlushMonitor); - mIsFlushing = true; - sp flush = new AMessage(kNotifyProcessFlush, id()); - flush->post(); - while (mIsFlushing) { - lock.Wait(); - } - return NS_OK; -} - -nsresult -GonkDecoderManager::Shutdown() -{ - if (mDecoder.get()) { - mDecoder->stop(); - mDecoder->ReleaseMediaResources(); - mDecoder = nullptr; - } - - mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); - - return NS_OK; -} - -size_t -GonkDecoderManager::NumQueuedSamples() -{ - MutexAutoLock lock(mMutex); - return mQueuedSamples.Length(); -} - -void -GonkDecoderManager::ProcessInput(bool aEndOfStream) -{ - MOZ_ASSERT(OnTaskLooper()); - - status_t rv = ProcessQueuedSamples(); - if (rv >= 0) { - if (!aEndOfStream && rv <= MIN_QUEUED_SAMPLES) { - mDecodeCallback->InputExhausted(); - } - - if (mToDo.get() == nullptr) { - mToDo = new AMessage(kNotifyDecoderActivity, id()); - if (aEndOfStream) { - mToDo->setInt32("input-eos", 1); - } - mDecoder->requestActivityNotification(mToDo); - } else if (aEndOfStream) { - mToDo->setInt32("input-eos", 1); - } - } else { - GMDD_LOG("input processed: error#%d", rv); - mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - __func__)); - } -} - -void -GonkDecoderManager::ProcessFlush() -{ - MOZ_ASSERT(OnTaskLooper()); - - mLastTime = INT64_MIN; - MonitorAutoLock lock(mFlushMonitor); - mWaitOutput.Clear(); - if (mDecoder->flush() != OK) { - GMDD_LOG("flush error"); - mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - __func__)); - } - mIsFlushing = false; - lock.NotifyAll(); -} - -// Use output timestamp to determine which output buffer is already returned -// and remove corresponding info, except for EOS, from the waiting list. -// This method handles the cases that audio decoder sends multiple output -// buffers for one input. -void -GonkDecoderManager::UpdateWaitingList(int64_t aForgetUpTo) -{ - MOZ_ASSERT(OnTaskLooper()); - - size_t i; - for (i = 0; i < mWaitOutput.Length(); i++) { - const auto& item = mWaitOutput.ElementAt(i); - if (item.mEOS || item.mTimestamp > aForgetUpTo) { - break; - } - } - if (i > 0) { - mWaitOutput.RemoveElementsAt(0, i); - } -} - -void -GonkDecoderManager::ProcessToDo(bool aEndOfStream) -{ - MOZ_ASSERT(OnTaskLooper()); - - MOZ_ASSERT(mToDo.get() != nullptr); - mToDo.clear(); - - if (NumQueuedSamples() > 0 && ProcessQueuedSamples() < 0) { - mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - __func__)); - return; - } - - while (mWaitOutput.Length() > 0) { - RefPtr output; - WaitOutputInfo wait = mWaitOutput.ElementAt(0); - nsresult rv = Output(wait.mOffset, output); - if (rv == NS_OK) { - MOZ_ASSERT(output); - mDecodeCallback->Output(output); - UpdateWaitingList(output->mTime); - } else if (rv == NS_ERROR_ABORT) { - // EOS - MOZ_ASSERT(mQueuedSamples.IsEmpty()); - if (output) { - mDecodeCallback->Output(output); - UpdateWaitingList(output->mTime); - } - MOZ_ASSERT(mWaitOutput.Length() == 1); - mWaitOutput.RemoveElementAt(0); - mDecodeCallback->DrainComplete(); - ResetEOS(); - return; - } else if (rv == NS_ERROR_NOT_AVAILABLE) { - break; - } else { - mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - __func__)); - return; - } - } - - if (!aEndOfStream && NumQueuedSamples() <= MIN_QUEUED_SAMPLES) { - mDecodeCallback->InputExhausted(); - // No need to shedule todo task this time because InputExhausted() will - // cause Input() to be invoked and do it for us. - return; - } - - if (NumQueuedSamples() || mWaitOutput.Length() > 0) { - mToDo = new AMessage(kNotifyDecoderActivity, id()); - if (aEndOfStream) { - mToDo->setInt32("input-eos", 1); - } - mDecoder->requestActivityNotification(mToDo); - } -} - -void -GonkDecoderManager::ResetEOS() -{ - // After eos, android::MediaCodec needs to be flushed to receive next input - mWaitOutput.Clear(); - if (mDecoder->flush() != OK) { - GMDD_LOG("flush error"); - mDecodeCallback->Error(MediaResult(NS_ERROR_DOM_MEDIA_FATAL_ERR, - __func__)); - } -} - -void -GonkDecoderManager::onMessageReceived(const sp &aMessage) -{ - switch (aMessage->what()) { - case kNotifyProcessInput: - { - int32_t eos = 0; - ProcessInput(aMessage->findInt32("input-eos", &eos) && eos); - break; - } - case kNotifyProcessFlush: - { - ProcessFlush(); - break; - } - case kNotifyDecoderActivity: - { - int32_t eos = 0; - ProcessToDo(aMessage->findInt32("input-eos", &eos) && eos); - break; - } -#ifdef DEBUG - case kNotifyFindLooperId: - { - mTaskLooperId = androidGetThreadId(); - MOZ_ASSERT(mTaskLooperId); - break; - } -#endif - default: - { - TRESPASS(); - break; - } - } -} - -#ifdef DEBUG -bool -GonkDecoderManager::OnTaskLooper() -{ - return androidGetThreadId() == mTaskLooperId; -} -#endif - -GonkMediaDataDecoder::GonkMediaDataDecoder(GonkDecoderManager* aManager, - MediaDataDecoderCallback* aCallback) - : mManager(aManager) -{ - MOZ_COUNT_CTOR(GonkMediaDataDecoder); - mManager->SetDecodeCallback(aCallback); -} - -GonkMediaDataDecoder::~GonkMediaDataDecoder() -{ - MOZ_COUNT_DTOR(GonkMediaDataDecoder); -} - -RefPtr -GonkMediaDataDecoder::Init() -{ - return mManager->Init(); -} - -void -GonkMediaDataDecoder::Shutdown() -{ - mManager->Shutdown(); - - // Because codec allocated runnable and init promise is at reader TaskQueue, - // so manager needs to be destroyed at reader TaskQueue to prevent racing. - mManager = nullptr; -} - -// Inserts data into the decoder's pipeline. -void -GonkMediaDataDecoder::Input(MediaRawData* aSample) -{ - mManager->Input(aSample); -} - -void -GonkMediaDataDecoder::Flush() -{ - mManager->Flush(); -} - -void -GonkMediaDataDecoder::Drain() -{ - mManager->Input(nullptr); -} - -} // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkMediaDataDecoder.h b/dom/media/platforms/gonk/GonkMediaDataDecoder.h deleted file mode 100644 index bba2a8645..000000000 --- a/dom/media/platforms/gonk/GonkMediaDataDecoder.h +++ /dev/null @@ -1,214 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if !defined(GonkMediaDataDecoder_h_) -#define GonkMediaDataDecoder_h_ -#include "PlatformDecoderModule.h" -#include - -namespace android { -struct ALooper; -class MediaBuffer; -class MediaCodecProxy; -} // namespace android - -namespace mozilla { -class MediaRawData; - -// Manage the data flow from inputting encoded data and outputting decode data. -class GonkDecoderManager : public android::AHandler { -public: - typedef TrackInfo::TrackType TrackType; - typedef MediaDataDecoder::InitPromise InitPromise; - - virtual ~GonkDecoderManager() {} - - virtual RefPtr Init() = 0; - virtual const char* GetDescriptionName() const = 0; - - // Asynchronously send sample into mDecoder. If out of input buffer, aSample - // will be queued for later re-send. - nsresult Input(MediaRawData* aSample); - - // Flush the queued samples and signal decoder to throw all pending input/output away. - nsresult Flush(); - - // Shutdown decoder and rejects the init promise. - virtual nsresult Shutdown(); - - // How many samples are waiting for processing. - size_t NumQueuedSamples(); - - // Set callback for decoder events, such as requesting more input, - // returning output, or reporting error. - void SetDecodeCallback(MediaDataDecoderCallback* aCallback) - { - mDecodeCallback = aCallback; - } - -protected: - GonkDecoderManager() - : mMutex("GonkDecoderManager") - , mLastTime(INT64_MIN) - , mFlushMonitor("GonkDecoderManager::Flush") - , mIsFlushing(false) - , mDecodeCallback(nullptr) - {} - - bool InitLoopers(MediaData::Type aType); - - void onMessageReceived(const android::sp &aMessage) override; - - // Produces decoded output. It returns NS_OK on success, or NS_ERROR_NOT_AVAILABLE - // when output is not produced yet. - // If this returns a failure code other than NS_ERROR_NOT_AVAILABLE, an error - // will be reported through mDecodeCallback. - virtual nsresult Output(int64_t aStreamOffset, - RefPtr& aOutput) = 0; - - // Send queued samples to OMX. It returns how many samples are still in - // queue after processing, or negative error code if failed. - int32_t ProcessQueuedSamples(); - - void ProcessInput(bool aEndOfStream); - virtual void ProcessFlush(); - void ProcessToDo(bool aEndOfStream); - virtual void ResetEOS(); - - RefPtr mCodecSpecificData; - - nsAutoCString mMimeType; - - // MediaCodedc's wrapper that performs the decoding. - android::sp mDecoder; - // Looper for mDecoder to run on. - android::sp mDecodeLooper; - // Looper to run decode tasks such as processing input, output, flush, and - // recycling output buffers. - android::sp mTaskLooper; - // Message codes for tasks running on mTaskLooper. - enum { - // Decoder will send this to indicate internal state change such as input or - // output buffers availability. Used to run pending input & output tasks. - kNotifyDecoderActivity = 'nda ', - // Signal the decoder to flush. - kNotifyProcessFlush = 'npf ', - // Used to process queued samples when there is new input. - kNotifyProcessInput = 'npi ', -#ifdef DEBUG - kNotifyFindLooperId = 'nfli', -#endif - }; - - MozPromiseHolder mInitPromise; - - Mutex mMutex; // Protects mQueuedSamples. - // A queue that stores the samples waiting to be sent to mDecoder. - // Empty element means EOS and there shouldn't be any sample be queued after it. - // Samples are queued in caller's thread and dequeued in mTaskLooper. - nsTArray> mQueuedSamples; - - // The last decoded frame presentation time. Only accessed on mTaskLooper. - int64_t mLastTime; - - Monitor mFlushMonitor; // Waits for flushing to complete. - bool mIsFlushing; // Protected by mFlushMonitor. - - // Remembers the notification that is currently waiting for the decoder event - // to avoid requesting more than one notification at the time, which is - // forbidden by mDecoder. - android::sp mToDo; - - // Stores sample info for output buffer processing later. - struct WaitOutputInfo { - WaitOutputInfo(int64_t aOffset, int64_t aTimestamp, bool aEOS) - : mOffset(aOffset) - , mTimestamp(aTimestamp) - , mEOS(aEOS) - {} - const int64_t mOffset; - const int64_t mTimestamp; - const bool mEOS; - }; - - nsTArray mWaitOutput; - - MediaDataDecoderCallback* mDecodeCallback; // Reports decoder output or error. - -private: - void UpdateWaitingList(int64_t aForgetUpTo); - -#ifdef DEBUG - typedef void* LooperId; - - bool OnTaskLooper(); - LooperId mTaskLooperId; -#endif -}; - -class AutoReleaseMediaBuffer -{ -public: - AutoReleaseMediaBuffer(android::MediaBuffer* aBuffer, android::MediaCodecProxy* aCodec) - : mBuffer(aBuffer) - , mCodec(aCodec) - {} - - ~AutoReleaseMediaBuffer() - { - MOZ_ASSERT(mCodec.get()); - if (mBuffer) { - mCodec->ReleaseMediaBuffer(mBuffer); - } - } - - android::MediaBuffer* forget() - { - android::MediaBuffer* tmp = mBuffer; - mBuffer = nullptr; - return tmp; - } - -private: - android::MediaBuffer* mBuffer; - android::sp mCodec; -}; - -// Samples are decoded using the GonkDecoder (MediaCodec) -// created by the GonkDecoderManager. This class implements -// the higher-level logic that drives mapping the Gonk to the async -// MediaDataDecoder interface. The specifics of decoding the exact stream -// type are handled by GonkDecoderManager and the GonkDecoder it creates. -class GonkMediaDataDecoder : public MediaDataDecoder { -public: - GonkMediaDataDecoder(GonkDecoderManager* aDecoderManager, - MediaDataDecoderCallback* aCallback); - - ~GonkMediaDataDecoder(); - - RefPtr Init() override; - - void Input(MediaRawData* aSample) override; - - void Flush() override; - - void Drain() override; - - void Shutdown() override; - - const char* GetDescriptionName() const override - { - return "gonk decoder"; - } - -private: - - android::sp mManager; -}; - -} // namespace mozilla - -#endif // GonkMediaDataDecoder_h_ diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp b/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp deleted file mode 100644 index 0c7b3b6af..000000000 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.cpp +++ /dev/null @@ -1,772 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "MediaCodecProxy.h" -#include -#include -#include -#include "GonkVideoDecoderManager.h" -#include "GrallocImages.h" -#include "MediaDecoderReader.h" -#include "ImageContainer.h" -#include "VideoUtils.h" -#include "nsThreadUtils.h" -#include "Layers.h" -#include "mozilla/Logging.h" -#include -#include -#include -#include -#include "GonkNativeWindow.h" -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/layers/TextureClient.h" -#include "mozilla/layers/TextureClientRecycleAllocator.h" -#include - -#define CODECCONFIG_TIMEOUT_US 10000LL -#define READ_OUTPUT_BUFFER_TIMEOUT_US 0LL - -#include -#define GVDM_LOG(...) __android_log_print(ANDROID_LOG_DEBUG, "GonkVideoDecoderManager", __VA_ARGS__) - -#define LOG(...) MOZ_LOG(sPDMLog, mozilla::LogLevel::Debug, (__VA_ARGS__)) -using namespace mozilla::layers; -using namespace android; -typedef android::MediaCodecProxy MediaCodecProxy; - -namespace mozilla { - -class GonkTextureClientAllocationHelper : public layers::ITextureClientAllocationHelper -{ -public: - GonkTextureClientAllocationHelper(uint32_t aGrallocFormat, - gfx::IntSize aSize) - : ITextureClientAllocationHelper(gfx::SurfaceFormat::UNKNOWN, - aSize, - BackendSelector::Content, - TextureFlags::DEALLOCATE_CLIENT, - ALLOC_DISALLOW_BUFFERTEXTURECLIENT) - , mGrallocFormat(aGrallocFormat) - {} - - already_AddRefed Allocate(KnowsCompositor* aAllocator) override - { - uint32_t usage = android::GraphicBuffer::USAGE_SW_READ_OFTEN | - android::GraphicBuffer::USAGE_SW_WRITE_OFTEN | - android::GraphicBuffer::USAGE_HW_TEXTURE; - - GrallocTextureData* texData = GrallocTextureData::Create(mSize, mGrallocFormat, - gfx::BackendType::NONE, - usage, aAllocator->GetTextureForwarder()); - if (!texData) { - return nullptr; - } - sp graphicBuffer = texData->GetGraphicBuffer(); - if (!graphicBuffer.get()) { - return nullptr; - } - RefPtr textureClient = - TextureClient::CreateWithData(texData, TextureFlags::DEALLOCATE_CLIENT, aAllocator->GetTextureForwarder()); - return textureClient.forget(); - } - - bool IsCompatible(TextureClient* aTextureClient) override - { - if (!aTextureClient) { - return false; - } - sp graphicBuffer = - static_cast(aTextureClient->GetInternalData())->GetGraphicBuffer(); - if (!graphicBuffer.get() || - static_cast(graphicBuffer->getPixelFormat()) != mGrallocFormat || - aTextureClient->GetSize() != mSize) { - return false; - } - return true; - } - -private: - uint32_t mGrallocFormat; -}; - -GonkVideoDecoderManager::GonkVideoDecoderManager( - mozilla::layers::ImageContainer* aImageContainer, - const VideoInfo& aConfig) - : mConfig(aConfig) - , mImageContainer(aImageContainer) - , mColorConverterBufferSize(0) - , mPendingReleaseItemsLock("GonkVideoDecoderManager::mPendingReleaseItemsLock") - , mNeedsCopyBuffer(false) -{ - MOZ_COUNT_CTOR(GonkVideoDecoderManager); -} - -GonkVideoDecoderManager::~GonkVideoDecoderManager() -{ - MOZ_COUNT_DTOR(GonkVideoDecoderManager); -} - -nsresult -GonkVideoDecoderManager::Shutdown() -{ - mVideoCodecRequest.DisconnectIfExists(); - return GonkDecoderManager::Shutdown(); -} - -RefPtr -GonkVideoDecoderManager::Init() -{ - mNeedsCopyBuffer = false; - - uint32_t maxWidth, maxHeight; - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.moz.omx.hw.max_width", propValue, "-1"); - maxWidth = -1 == atoi(propValue) ? MAX_VIDEO_WIDTH : atoi(propValue); - property_get("ro.moz.omx.hw.max_height", propValue, "-1"); - maxHeight = -1 == atoi(propValue) ? MAX_VIDEO_HEIGHT : atoi(propValue) ; - - if (uint32_t(mConfig.mImage.width * mConfig.mImage.height) > maxWidth * maxHeight) { - GVDM_LOG("Video resolution exceeds hw codec capability"); - return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } - - // Validate the container-reported frame and pictureRect sizes. This ensures - // that our video frame creation code doesn't overflow. - if (!IsValidVideoRegion(mConfig.mImage, mConfig.ImageRect(), mConfig.mDisplay)) { - GVDM_LOG("It is not a valid region"); - return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } - - mReaderTaskQueue = AbstractThread::GetCurrent()->AsTaskQueue(); - MOZ_ASSERT(mReaderTaskQueue); - - if (mDecodeLooper.get() != nullptr) { - return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } - - if (!InitLoopers(MediaData::VIDEO_DATA)) { - return InitPromise::CreateAndReject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - } - - RefPtr p = mInitPromise.Ensure(__func__); - android::sp self = this; - mDecoder = MediaCodecProxy::CreateByType(mDecodeLooper, - mConfig.mMimeType.get(), - false); - - uint32_t capability = MediaCodecProxy::kEmptyCapability; - if (mDecoder->getCapability(&capability) == OK && (capability & - MediaCodecProxy::kCanExposeGraphicBuffer)) { -#if ANDROID_VERSION >= 21 - sp consumer; - GonkBufferQueue::createBufferQueue(&mGraphicBufferProducer, &consumer); - mNativeWindow = new GonkNativeWindow(consumer); -#else - mNativeWindow = new GonkNativeWindow(); -#endif - } - - mVideoCodecRequest.Begin(mDecoder->AsyncAllocateVideoMediaCodec() - ->Then(mReaderTaskQueue, __func__, - [self] (bool) -> void { - self->mVideoCodecRequest.Complete(); - self->codecReserved(); - }, [self] (bool) -> void { - self->mVideoCodecRequest.Complete(); - self->codecCanceled(); - })); - - return p; -} - -nsresult -GonkVideoDecoderManager::CreateVideoData(MediaBuffer* aBuffer, - int64_t aStreamOffset, - VideoData **v) -{ - *v = nullptr; - RefPtr data; - int64_t timeUs; - int32_t keyFrame; - - if (aBuffer == nullptr) { - GVDM_LOG("Video Buffer is not valid!"); - return NS_ERROR_UNEXPECTED; - } - - AutoReleaseMediaBuffer autoRelease(aBuffer, mDecoder.get()); - - if (!aBuffer->meta_data()->findInt64(kKeyTime, &timeUs)) { - GVDM_LOG("Decoder did not return frame time"); - return NS_ERROR_UNEXPECTED; - } - - if (mLastTime > timeUs) { - GVDM_LOG("Output decoded sample time is revert. time=%lld", timeUs); - return NS_ERROR_NOT_AVAILABLE; - } - mLastTime = timeUs; - - if (aBuffer->range_length() == 0) { - // Some decoders may return spurious empty buffers that we just want to ignore - // quoted from Android's AwesomePlayer.cpp - return NS_ERROR_NOT_AVAILABLE; - } - - if (!aBuffer->meta_data()->findInt32(kKeyIsSyncFrame, &keyFrame)) { - keyFrame = 0; - } - - gfx::IntRect picture = - mConfig.ScaledImageRect(mFrameInfo.mWidth, mFrameInfo.mHeight); - if (aBuffer->graphicBuffer().get()) { - data = CreateVideoDataFromGraphicBuffer(aBuffer, picture); - if (data && !mNeedsCopyBuffer) { - // RecycleCallback() will be responsible for release the buffer. - autoRelease.forget(); - } - mNeedsCopyBuffer = false; - } else { - data = CreateVideoDataFromDataBuffer(aBuffer, picture); - } - - if (!data) { - return NS_ERROR_UNEXPECTED; - } - // Fill necessary info. - data->mOffset = aStreamOffset; - data->mTime = timeUs; - data->mKeyframe = keyFrame; - - data.forget(v); - return NS_OK; -} - -// Copy pixels from one planar YUV to another. -static void -CopyYUV(PlanarYCbCrData& aSource, PlanarYCbCrData& aDestination) -{ - // Fill Y plane. - uint8_t* srcY = aSource.mYChannel; - gfx::IntSize ySize = aSource.mYSize; - uint8_t* destY = aDestination.mYChannel; - // Y plane. - for (int i = 0; i < ySize.height; i++) { - memcpy(destY, srcY, ySize.width); - srcY += aSource.mYStride; - destY += aDestination.mYStride; - } - - // Fill UV plane. - // Line start - uint8_t* srcU = aSource.mCbChannel; - uint8_t* srcV = aSource.mCrChannel; - uint8_t* destU = aDestination.mCbChannel; - uint8_t* destV = aDestination.mCrChannel; - - gfx::IntSize uvSize = aSource.mCbCrSize; - for (int i = 0; i < uvSize.height; i++) { - uint8_t* su = srcU; - uint8_t* sv = srcV; - uint8_t* du = destU; - uint8_t* dv =destV; - for (int j = 0; j < uvSize.width; j++) { - *du++ = *su++; - *dv++ = *sv++; - // Move to next pixel. - su += aSource.mCbSkip; - sv += aSource.mCrSkip; - du += aDestination.mCbSkip; - dv += aDestination.mCrSkip; - } - // Move to next line. - srcU += aSource.mCbCrStride; - srcV += aSource.mCbCrStride; - destU += aDestination.mCbCrStride; - destV += aDestination.mCbCrStride; - } -} - -inline static int -Align(int aX, int aAlign) -{ - return (aX + aAlign - 1) & ~(aAlign - 1); -} - -// Venus formats are doucmented in kernel/include/media/msm_media_info.h: -// * Y_Stride : Width aligned to 128 -// * UV_Stride : Width aligned to 128 -// * Y_Scanlines: Height aligned to 32 -// * UV_Scanlines: Height/2 aligned to 16 -// * Total size = align((Y_Stride * Y_Scanlines -// * + UV_Stride * UV_Scanlines + 4096), 4096) -static void -CopyVenus(uint8_t* aSrc, uint8_t* aDest, uint32_t aWidth, uint32_t aHeight) -{ - size_t yStride = Align(aWidth, 128); - uint8_t* s = aSrc; - uint8_t* d = aDest; - for (size_t i = 0; i < aHeight; i++) { - memcpy(d, s, aWidth); - s += yStride; - d += yStride; - } - size_t uvStride = yStride; - size_t uvLines = (aHeight + 1) / 2; - size_t ySize = yStride * Align(aHeight, 32); - s = aSrc + ySize; - d = aDest + ySize; - for (size_t i = 0; i < uvLines; i++) { - memcpy(d, s, aWidth); - s += uvStride; - d += uvStride; - } -} - -static void -CopyGraphicBuffer(sp& aSource, sp& aDestination) -{ - void* srcPtr = nullptr; - aSource->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &srcPtr); - void* destPtr = nullptr; - aDestination->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &destPtr); - MOZ_ASSERT(srcPtr && destPtr); - - // Build PlanarYCbCrData for source buffer. - PlanarYCbCrData srcData; - switch (aSource->getPixelFormat()) { - case HAL_PIXEL_FORMAT_YV12: { - // Android YV12 format is defined in system/core/include/system/graphics.h - srcData.mYChannel = static_cast(srcPtr); - srcData.mYSkip = 0; - srcData.mYSize.width = aSource->getWidth(); - srcData.mYSize.height = aSource->getHeight(); - srcData.mYStride = aSource->getStride(); - // 4:2:0. - srcData.mCbCrSize.width = srcData.mYSize.width / 2; - srcData.mCbCrSize.height = srcData.mYSize.height / 2; - srcData.mCrChannel = srcData.mYChannel + (srcData.mYStride * srcData.mYSize.height); - // Aligned to 16 bytes boundary. - srcData.mCbCrStride = Align(srcData.mYStride / 2, 16); - srcData.mCrSkip = 0; - srcData.mCbChannel = srcData.mCrChannel + (srcData.mCbCrStride * srcData.mCbCrSize.height); - srcData.mCbSkip = 0; - - // Build PlanarYCbCrData for destination buffer. - PlanarYCbCrData destData; - destData.mYChannel = static_cast(destPtr); - destData.mYSkip = 0; - destData.mYSize.width = aDestination->getWidth(); - destData.mYSize.height = aDestination->getHeight(); - destData.mYStride = aDestination->getStride(); - // 4:2:0. - destData.mCbCrSize.width = destData.mYSize.width / 2; - destData.mCbCrSize.height = destData.mYSize.height / 2; - destData.mCrChannel = destData.mYChannel + (destData.mYStride * destData.mYSize.height); - // Aligned to 16 bytes boundary. - destData.mCbCrStride = Align(destData.mYStride / 2, 16); - destData.mCrSkip = 0; - destData.mCbChannel = destData.mCrChannel + (destData.mCbCrStride * destData.mCbCrSize.height); - destData.mCbSkip = 0; - - CopyYUV(srcData, destData); - break; - } - case GrallocImage::HAL_PIXEL_FORMAT_YCbCr_420_SP_VENUS: - CopyVenus(static_cast(srcPtr), - static_cast(destPtr), - aSource->getWidth(), - aSource->getHeight()); - break; - default: - NS_ERROR("Unsupported input gralloc image type. Should never be here."); - } - - - aSource->unlock(); - aDestination->unlock(); -} - -already_AddRefed -GonkVideoDecoderManager::CreateVideoDataFromGraphicBuffer(MediaBuffer* aSource, - gfx::IntRect& aPicture) -{ - sp srcBuffer(aSource->graphicBuffer()); - RefPtr textureClient; - - if (mNeedsCopyBuffer) { - // Copy buffer contents for bug 1199809. - if (!mCopyAllocator) { - RefPtr bridge = layers::ImageBridgeChild::GetSingleton(); - mCopyAllocator = new TextureClientRecycleAllocator(bridge); - } - if (!mCopyAllocator) { - GVDM_LOG("Create buffer allocator failed!"); - return nullptr; - } - - gfx::IntSize size(srcBuffer->getWidth(), srcBuffer->getHeight()); - GonkTextureClientAllocationHelper helper(srcBuffer->getPixelFormat(), size); - textureClient = mCopyAllocator->CreateOrRecycle(helper); - if (!textureClient) { - GVDM_LOG("Copy buffer allocation failed!"); - return nullptr; - } - - sp destBuffer = - static_cast(textureClient->GetInternalData())->GetGraphicBuffer(); - - CopyGraphicBuffer(srcBuffer, destBuffer); - } else { - textureClient = mNativeWindow->getTextureClientFromBuffer(srcBuffer.get()); - textureClient->SetRecycleCallback(GonkVideoDecoderManager::RecycleCallback, this); - static_cast(textureClient->GetInternalData())->SetMediaBuffer(aSource); - } - - RefPtr data = - VideoData::CreateAndCopyIntoTextureClient(mConfig, - 0, // Filled later by caller. - 0, // Filled later by caller. - 1, // No way to pass sample duration from muxer to - // OMX codec, so we hardcode the duration here. - textureClient, - false, // Filled later by caller. - -1, - aPicture); - return data.forget(); -} - -already_AddRefed -GonkVideoDecoderManager::CreateVideoDataFromDataBuffer(MediaBuffer* aSource, gfx::IntRect& aPicture) -{ - if (!aSource->data()) { - GVDM_LOG("No data in Video Buffer!"); - return nullptr; - } - uint8_t *yuv420p_buffer = (uint8_t *)aSource->data(); - int32_t stride = mFrameInfo.mStride; - int32_t slice_height = mFrameInfo.mSliceHeight; - - // Converts to OMX_COLOR_FormatYUV420Planar - if (mFrameInfo.mColorFormat != OMX_COLOR_FormatYUV420Planar) { - ARect crop; - crop.top = 0; - crop.bottom = mFrameInfo.mHeight; - crop.left = 0; - crop.right = mFrameInfo.mWidth; - yuv420p_buffer = GetColorConverterBuffer(mFrameInfo.mWidth, mFrameInfo.mHeight); - if (mColorConverter.convertDecoderOutputToI420(aSource->data(), - mFrameInfo.mWidth, mFrameInfo.mHeight, crop, yuv420p_buffer) != OK) { - GVDM_LOG("Color conversion failed!"); - return nullptr; - } - stride = mFrameInfo.mWidth; - slice_height = mFrameInfo.mHeight; - } - - size_t yuv420p_y_size = stride * slice_height; - size_t yuv420p_u_size = ((stride + 1) / 2) * ((slice_height + 1) / 2); - uint8_t *yuv420p_y = yuv420p_buffer; - uint8_t *yuv420p_u = yuv420p_y + yuv420p_y_size; - uint8_t *yuv420p_v = yuv420p_u + yuv420p_u_size; - - VideoData::YCbCrBuffer b; - b.mPlanes[0].mData = yuv420p_y; - b.mPlanes[0].mWidth = mFrameInfo.mWidth; - b.mPlanes[0].mHeight = mFrameInfo.mHeight; - b.mPlanes[0].mStride = stride; - b.mPlanes[0].mOffset = 0; - b.mPlanes[0].mSkip = 0; - - b.mPlanes[1].mData = yuv420p_u; - b.mPlanes[1].mWidth = (mFrameInfo.mWidth + 1) / 2; - b.mPlanes[1].mHeight = (mFrameInfo.mHeight + 1) / 2; - b.mPlanes[1].mStride = (stride + 1) / 2; - b.mPlanes[1].mOffset = 0; - b.mPlanes[1].mSkip = 0; - - b.mPlanes[2].mData = yuv420p_v; - b.mPlanes[2].mWidth =(mFrameInfo.mWidth + 1) / 2; - b.mPlanes[2].mHeight = (mFrameInfo.mHeight + 1) / 2; - b.mPlanes[2].mStride = (stride + 1) / 2; - b.mPlanes[2].mOffset = 0; - b.mPlanes[2].mSkip = 0; - - RefPtr data = - VideoData::CreateAndCopyData(mConfig, - mImageContainer, - 0, // Filled later by caller. - 0, // Filled later by caller. - 1, // We don't know the duration. - b, - 0, // Filled later by caller. - -1, - aPicture); - - return data.forget(); -} - -bool -GonkVideoDecoderManager::SetVideoFormat() -{ - // read video metadata from MediaCodec - sp codecFormat; - if (mDecoder->getOutputFormat(&codecFormat) == OK) { - AString mime; - int32_t width = 0; - int32_t height = 0; - int32_t stride = 0; - int32_t slice_height = 0; - int32_t color_format = 0; - int32_t crop_left = 0; - int32_t crop_top = 0; - int32_t crop_right = 0; - int32_t crop_bottom = 0; - if (!codecFormat->findString("mime", &mime) || - !codecFormat->findInt32("width", &width) || - !codecFormat->findInt32("height", &height) || - !codecFormat->findInt32("stride", &stride) || - !codecFormat->findInt32("slice-height", &slice_height) || - !codecFormat->findInt32("color-format", &color_format) || - !codecFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) { - GVDM_LOG("Failed to find values"); - return false; - } - mFrameInfo.mWidth = width; - mFrameInfo.mHeight = height; - mFrameInfo.mStride = stride; - mFrameInfo.mSliceHeight = slice_height; - mFrameInfo.mColorFormat = color_format; - - nsIntSize displaySize(width, height); - if (!IsValidVideoRegion(mConfig.mDisplay, - mConfig.ScaledImageRect(width, height), - displaySize)) { - GVDM_LOG("It is not a valid region"); - return false; - } - return true; - } - GVDM_LOG("Fail to get output format"); - return false; -} - -// Blocks until decoded sample is produced by the deoder. -nsresult -GonkVideoDecoderManager::Output(int64_t aStreamOffset, - RefPtr& aOutData) -{ - aOutData = nullptr; - status_t err; - if (mDecoder == nullptr) { - GVDM_LOG("Decoder is not inited"); - return NS_ERROR_UNEXPECTED; - } - MediaBuffer* outputBuffer = nullptr; - err = mDecoder->Output(&outputBuffer, READ_OUTPUT_BUFFER_TIMEOUT_US); - - switch (err) { - case OK: - { - RefPtr data; - nsresult rv = CreateVideoData(outputBuffer, aStreamOffset, getter_AddRefs(data)); - if (rv == NS_ERROR_NOT_AVAILABLE) { - // Decoder outputs a empty video buffer, try again - return NS_ERROR_NOT_AVAILABLE; - } else if (rv != NS_OK || data == nullptr) { - GVDM_LOG("Failed to create VideoData"); - return NS_ERROR_UNEXPECTED; - } - aOutData = data; - return NS_OK; - } - case android::INFO_FORMAT_CHANGED: - { - // If the format changed, update our cached info. - GVDM_LOG("Decoder format changed"); - if (!SetVideoFormat()) { - return NS_ERROR_UNEXPECTED; - } - return Output(aStreamOffset, aOutData); - } - case android::INFO_OUTPUT_BUFFERS_CHANGED: - { - if (mDecoder->UpdateOutputBuffers()) { - return Output(aStreamOffset, aOutData); - } - GVDM_LOG("Fails to update output buffers!"); - return NS_ERROR_FAILURE; - } - case -EAGAIN: - { -// GVDM_LOG("Need to try again!"); - return NS_ERROR_NOT_AVAILABLE; - } - case android::ERROR_END_OF_STREAM: - { - GVDM_LOG("Got the EOS frame!"); - RefPtr data; - nsresult rv = CreateVideoData(outputBuffer, aStreamOffset, getter_AddRefs(data)); - if (rv == NS_ERROR_NOT_AVAILABLE) { - // For EOS, no need to do any thing. - return NS_ERROR_ABORT; - } - if (rv != NS_OK || data == nullptr) { - GVDM_LOG("Failed to create video data"); - return NS_ERROR_UNEXPECTED; - } - aOutData = data; - return NS_ERROR_ABORT; - } - case -ETIMEDOUT: - { - GVDM_LOG("Timeout. can try again next time"); - return NS_ERROR_UNEXPECTED; - } - default: - { - GVDM_LOG("Decoder failed, err=%d", err); - return NS_ERROR_UNEXPECTED; - } - } - - return NS_OK; -} - -void -GonkVideoDecoderManager::codecReserved() -{ - if (mInitPromise.IsEmpty()) { - return; - } - GVDM_LOG("codecReserved"); - sp format = new AMessage; - sp surface; - status_t rv = OK; - // Fixed values - GVDM_LOG("Configure video mime type: %s, width:%d, height:%d", mConfig.mMimeType.get(), mConfig.mImage.width, mConfig.mImage.height); - format->setString("mime", mConfig.mMimeType.get()); - format->setInt32("width", mConfig.mImage.width); - format->setInt32("height", mConfig.mImage.height); - // Set the "moz-use-undequeued-bufs" to use the undeque buffers to accelerate - // the video decoding. - format->setInt32("moz-use-undequeued-bufs", 1); - if (mNativeWindow != nullptr) { -#if ANDROID_VERSION >= 21 - surface = new Surface(mGraphicBufferProducer); -#else - surface = new Surface(mNativeWindow->getBufferQueue()); -#endif - } - mDecoder->configure(format, surface, nullptr, 0); - mDecoder->Prepare(); - - if (mConfig.mMimeType.EqualsLiteral("video/mp4v-es")) { - rv = mDecoder->Input(mConfig.mCodecSpecificConfig->Elements(), - mConfig.mCodecSpecificConfig->Length(), 0, - android::MediaCodec::BUFFER_FLAG_CODECCONFIG, - CODECCONFIG_TIMEOUT_US); - } - - if (rv != OK) { - GVDM_LOG("Failed to configure codec!!!!"); - mInitPromise.Reject(NS_ERROR_DOM_MEDIA_FATAL_ERR, __func__); - return; - } - - mInitPromise.Resolve(TrackType::kVideoTrack, __func__); -} - -void -GonkVideoDecoderManager::codecCanceled() -{ - GVDM_LOG("codecCanceled"); - mInitPromise.RejectIfExists(NS_ERROR_DOM_MEDIA_CANCELED, __func__); -} - -// Called on GonkDecoderManager::mTaskLooper thread. -void -GonkVideoDecoderManager::onMessageReceived(const sp &aMessage) -{ - switch (aMessage->what()) { - case kNotifyPostReleaseBuffer: - { - ReleaseAllPendingVideoBuffers(); - break; - } - - default: - { - GonkDecoderManager::onMessageReceived(aMessage); - break; - } - } -} - -uint8_t * -GonkVideoDecoderManager::GetColorConverterBuffer(int32_t aWidth, int32_t aHeight) -{ - // Allocate a temporary YUV420Planer buffer. - size_t yuv420p_y_size = aWidth * aHeight; - size_t yuv420p_u_size = ((aWidth + 1) / 2) * ((aHeight + 1) / 2); - size_t yuv420p_v_size = yuv420p_u_size; - size_t yuv420p_size = yuv420p_y_size + yuv420p_u_size + yuv420p_v_size; - if (mColorConverterBufferSize != yuv420p_size) { - mColorConverterBuffer = MakeUnique(yuv420p_size); - mColorConverterBufferSize = yuv420p_size; - } - return mColorConverterBuffer.get(); -} - -/* static */ -void -GonkVideoDecoderManager::RecycleCallback(TextureClient* aClient, void* aClosure) -{ - MOZ_ASSERT(aClient && !aClient->IsDead()); - GonkVideoDecoderManager* videoManager = static_cast(aClosure); - GrallocTextureData* client = static_cast(aClient->GetInternalData()); - aClient->ClearRecycleCallback(); - FenceHandle handle = aClient->GetAndResetReleaseFenceHandle(); - videoManager->PostReleaseVideoBuffer(client->GetMediaBuffer(), handle); -} - -void GonkVideoDecoderManager::PostReleaseVideoBuffer( - android::MediaBuffer *aBuffer, - FenceHandle aReleaseFence) -{ - { - MutexAutoLock autoLock(mPendingReleaseItemsLock); - if (aBuffer) { - mPendingReleaseItems.AppendElement(ReleaseItem(aBuffer, aReleaseFence)); - } - } - sp notify = - new AMessage(kNotifyPostReleaseBuffer, id()); - notify->post(); - -} - -void GonkVideoDecoderManager::ReleaseAllPendingVideoBuffers() -{ - nsTArray releasingItems; - { - MutexAutoLock autoLock(mPendingReleaseItemsLock); - releasingItems.AppendElements(mPendingReleaseItems); - mPendingReleaseItems.Clear(); - } - - // Free all pending video buffers without holding mPendingReleaseItemsLock. - size_t size = releasingItems.Length(); - for (size_t i = 0; i < size; i++) { - RefPtr fdObj = releasingItems[i].mReleaseFence.GetAndResetFdObj(); - sp fence = new Fence(fdObj->GetAndResetFd()); - fence->waitForever("GonkVideoDecoderManager"); - mDecoder->ReleaseMediaBuffer(releasingItems[i].mBuffer); - } - releasingItems.Clear(); -} - -} // namespace mozilla diff --git a/dom/media/platforms/gonk/GonkVideoDecoderManager.h b/dom/media/platforms/gonk/GonkVideoDecoderManager.h deleted file mode 100644 index 343bb2a5c..000000000 --- a/dom/media/platforms/gonk/GonkVideoDecoderManager.h +++ /dev/null @@ -1,149 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim:set ts=2 sw=2 sts=2 et cindent: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#if !defined(GonkVideoDecoderManager_h_) -#define GonkVideoDecoderManager_h_ - -#include "nsRect.h" -#include "GonkMediaDataDecoder.h" -#include "mozilla/RefPtr.h" -#include "I420ColorConverterHelper.h" -#include "MediaCodecProxy.h" -#include "GonkNativeWindow.h" -#include "mozilla/layers/FenceUtils.h" -#include "mozilla/UniquePtr.h" -#include - -using namespace android; - -namespace android { -class MediaBuffer; -struct MOZ_EXPORT AString; -class GonkNativeWindow; -} // namespace android - -namespace mozilla { - -namespace layers { -class TextureClient; -class TextureClientRecycleAllocator; -} // namespace mozilla::layers - -class GonkVideoDecoderManager : public GonkDecoderManager { -typedef android::MediaCodecProxy MediaCodecProxy; -typedef mozilla::layers::TextureClient TextureClient; - -public: - GonkVideoDecoderManager(mozilla::layers::ImageContainer* aImageContainer, - const VideoInfo& aConfig); - - virtual ~GonkVideoDecoderManager(); - - RefPtr Init() override; - - nsresult Output(int64_t aStreamOffset, - RefPtr& aOutput) override; - - nsresult Shutdown() override; - - const char* GetDescriptionName() const override - { - return "gonk video decoder"; - } - - static void RecycleCallback(TextureClient* aClient, void* aClosure); - -protected: - // Bug 1199809: workaround to avoid sending the graphic buffer by making a - // copy of output buffer after calling flush(). Bug 1203859 was created to - // reimplementing Gonk PDM on top of OpenMax IL directly. Its buffer - // management will work better with Gecko and solve problems like this. - void ProcessFlush() override - { - mNeedsCopyBuffer = true; - GonkDecoderManager::ProcessFlush(); - } - -private: - struct FrameInfo - { - int32_t mWidth = 0; - int32_t mHeight = 0; - int32_t mStride = 0; - int32_t mSliceHeight = 0; - int32_t mColorFormat = 0; - int32_t mCropLeft = 0; - int32_t mCropTop = 0; - int32_t mCropRight = 0; - int32_t mCropBottom = 0; - }; - - void onMessageReceived(const android::sp &aMessage) override; - - bool SetVideoFormat(); - - nsresult CreateVideoData(MediaBuffer* aBuffer, int64_t aStreamOffset, VideoData** aOutData); - already_AddRefed CreateVideoDataFromGraphicBuffer(android::MediaBuffer* aSource, - gfx::IntRect& aPicture); - already_AddRefed CreateVideoDataFromDataBuffer(android::MediaBuffer* aSource, - gfx::IntRect& aPicture); - - uint8_t* GetColorConverterBuffer(int32_t aWidth, int32_t aHeight); - - // For codec resource management - void codecReserved(); - void codecCanceled(); - - void ReleaseAllPendingVideoBuffers(); - void PostReleaseVideoBuffer(android::MediaBuffer *aBuffer, - layers::FenceHandle mReleaseFence); - - VideoInfo mConfig; - - RefPtr mImageContainer; - RefPtr mCopyAllocator; - - MozPromiseRequestHolder mVideoCodecRequest; - FrameInfo mFrameInfo; - - // color converter - android::I420ColorConverterHelper mColorConverter; - UniquePtr mColorConverterBuffer; - size_t mColorConverterBufferSize; - - android::sp mNativeWindow; -#if ANDROID_VERSION >= 21 - android::sp mGraphicBufferProducer; -#endif - - enum { - kNotifyPostReleaseBuffer = 'nprb', - }; - - struct ReleaseItem { - ReleaseItem(android::MediaBuffer* aBuffer, layers::FenceHandle& aFence) - : mBuffer(aBuffer) - , mReleaseFence(aFence) {} - android::MediaBuffer* mBuffer; - layers::FenceHandle mReleaseFence; - }; - nsTArray mPendingReleaseItems; - - // The lock protects mPendingReleaseItems. - Mutex mPendingReleaseItemsLock; - - // This TaskQueue should be the same one in mDecodeCallback->OnReaderTaskQueue(). - // It is for codec resource mangement, decoding task should not dispatch to it. - RefPtr mReaderTaskQueue; - - // Bug 1199809: do we need to make a copy of output buffer? Used only when - // the decoder outputs graphic buffers. - bool mNeedsCopyBuffer; -}; - -} // namespace mozilla - -#endif // GonkVideoDecoderManager_h_ diff --git a/dom/media/platforms/gonk/moz.build b/dom/media/platforms/gonk/moz.build deleted file mode 100644 index 014594977..000000000 --- a/dom/media/platforms/gonk/moz.build +++ /dev/null @@ -1,39 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -EXPORTS += [ - 'GonkAudioDecoderManager.h', - 'GonkDecoderModule.h', - 'GonkMediaDataDecoder.h', - 'GonkVideoDecoderManager.h', -] -UNIFIED_SOURCES += [ - 'GonkAudioDecoderManager.cpp', - 'GonkDecoderModule.cpp', - 'GonkMediaDataDecoder.cpp', - 'GonkVideoDecoderManager.cpp', -] -LOCAL_INCLUDES += [ - '/dom/media/omx/', -] -include('/ipc/chromium/chromium-config.mozbuild') - -# Suppress some GCC/clang warnings being treated as errors: -# - about attributes on forward declarations for types that are already -# defined, which complains about an important MOZ_EXPORT for android::AString -# - about multi-character constants which are used in codec-related code -if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: - CXXFLAGS += [ - '-Wno-error=attributes', - '-Wno-error=multichar' - ] - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include',] -] diff --git a/dom/media/platforms/moz.build b/dom/media/platforms/moz.build index 310820c91..3fb0cc842 100644 --- a/dom/media/platforms/moz.build +++ b/dom/media/platforms/moz.build @@ -70,10 +70,6 @@ if CONFIG['MOZ_APPLEMEDIA']: '-framework AudioToolbox', ] -if CONFIG['MOZ_GONK_MEDIACODEC']: - DEFINES['MOZ_GONK_MEDIACODEC'] = True - DIRS += ['gonk'] - include('/ipc/chromium/chromium-config.mozbuild') if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': diff --git a/dom/secureelement/SEUtils.jsm b/dom/secureelement/SEUtils.jsm deleted file mode 100644 index d5980b19c..000000000 --- a/dom/secureelement/SEUtils.jsm +++ /dev/null @@ -1,116 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -"use strict"; - -this.SEUtils = { - byteArrayToHexString: function byteArrayToHexString(array) { - let hexStr = ""; - - let len = array ? array.length : 0; - for (let i = 0; i < len; i++) { - let hex = (array[i] & 0xff).toString(16); - hex = (hex.length === 1) ? "0" + hex : hex; - hexStr += hex; - } - - return hexStr.toUpperCase(); - }, - - hexStringToByteArray: function hexStringToByteArray(hexStr) { - if (typeof hexStr !== "string" || hexStr.length % 2 !== 0) { - return []; - } - - let array = []; - for (let i = 0, len = hexStr.length; i < len; i += 2) { - array.push(parseInt(hexStr.substr(i, 2), 16)); - } - - return array; - }, - - arraysEqual: function arraysEqual(a1, a2) { - if (!a1 || !a2) { - return false; - } - - if (a1.length !== a2.length) { - return false; - } - - for (let i = 0, len = a1.length; i < len; i++) { - if (a1[i] !== a2[i]) { - return false; - } - } - - return true; - }, - - ensureIsArray: function ensureIsArray(obj) { - return Array.isArray(obj) ? obj : [obj]; - }, - - /** - * parseTLV is intended primarily to be used to parse Global Platform Device - * Technology secure element access control data. - * - * The parsed result value is an internal format only. - * - * All tags will be treated as simple Tag Length Values (TLV), (i.e. with a - * plain value, not subject to further unpacking), unless those tags are - * listed in the containerTags array. - * - * @param bytes - byte array - * @param containerTags - byte array of tags - */ - parseTLV: function parseTLV(bytes, containerTags) { - let result = {}; - - if (typeof bytes === "string") { - bytes = this.hexStringToByteArray(bytes); - } - - if (!Array.isArray(bytes)) { - debug("Passed value is not an array nor a string."); - return null; - } - - for (let pos = 0; pos < bytes.length; ) { - let tag = bytes[pos], - length = bytes[pos + 1], - value = bytes.slice(pos + 2, pos + 2 + length), - parsed = null; - - // Support for 0xFF padded files (GPD 7.1.2) - if (tag === 0xFF) { - break; - } - - if (containerTags.indexOf(tag) >= 0) { - parsed = this.parseTLV(value, containerTags); - } else { - parsed = value; - } - - // Internal parsed format. - if (!result[tag]) { - result[tag] = parsed; - } else if (Array.isArray(result[tag])) { - result[tag].push(parsed); - } else { - result[tag] = [result[tag], parsed]; - } - - pos = pos + 2 + length; - } - - return result; - } -}; - -this.EXPORTED_SYMBOLS = ["SEUtils"]; diff --git a/dom/secureelement/gonk/ACEService.js b/dom/secureelement/gonk/ACEService.js deleted file mode 100644 index b52ba5fab..000000000 --- a/dom/secureelement/gonk/ACEService.js +++ /dev/null @@ -1,139 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -"use strict"; - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "SE", function() { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -var DEBUG = SE.DEBUG_ACE; -function debug(msg) { - if (DEBUG) { - dump("ACEservice: " + msg + "\n"); - } -} - -/** - * Implements decision making algorithm as described in GPD specification, - * mostly in 3.1, 3.2 and 4.2.3. - * - * TODO: Bug 1137533: Implement GPAccessRulesManager APDU filters - */ -function GPAccessDecision(rules, certHash, aid) { - this.rules = rules; - this.certHash = certHash; - this.aid = aid; -} - -GPAccessDecision.prototype = { - isAccessAllowed: function isAccessAllowed() { - // GPD SE Access Control v1.1, 3.4.1, Table 3-2: (Conflict resolution) - // If a specific rule allows, all other non-specific access is denied. - // Conflicting specific rules will resolve to the first Allowed == "true" - // match. Given no specific rule, the global "All" rules will determine - // access. "Some", skips further processing if access Allowed == "true". - // - // Access must be decided before the SE connector openChannel, and the - // exchangeAPDU call. - // - // NOTE: This implementation may change with the introduction of APDU - // filters. - let decision = this.rules.some(this._decideAppAccess.bind(this)); - return decision; - }, - - _decideAppAccess: function _decideAppAccess(rule) { - let appMatched, appletMatched; - - // GPD SE AC 4.2.3: Algorithm for Applying Rules - // Specific rule overrides global rule. - // - // DeviceAppID is the application hash, and the AID is SE Applet ID: - // - // GPD SE AC 4.2.3 A: - // SearchRuleFor(DeviceAppID, AID) - // GPD SE AC 4.2.3 B: If no rule fits A: - // SearchRuleFor(, AID) - // GPD SE AC 4.2.3 C: If no rule fits A or B: - // SearchRuleFor(DeviceAppID, ) - // GPD SE AC 4.2.3 D: If no rule fits A, B, or C: - // SearchRuleFor(, ) - - // Device App - appMatched = Array.isArray(rule.application) ? - // GPD SE AC 4.2.3 A and 4.2.3 C (DeviceAppID rule) - this._appCertHashMatches(rule.application) : - // GPD SE AC 4.2.3 B and 4.2.3 D (All Device Applications) - rule.application === Ci.nsIAccessRulesManager.ALLOW_ALL; - - if (!appMatched) { - return false; // bail out early. - } - - // SE Applet - appletMatched = Array.isArray(rule.applet) ? - // GPD SE AC 4.2.3 A and 4.2.3 B (AID rule) - SEUtils.arraysEqual(rule.applet, this.aid) : - // GPD SE AC 4.2.3 C and 4.2.3 D (All AID) - rule.applet === Ci.nsIAccessRulesManager.ALL_APPLET; - - return appletMatched; - }, - - _appCertHashMatches: function _appCertHashMatches(hashArray) { - if (!Array.isArray(hashArray)) { - return false; - } - - return !!(hashArray.find((hash) => { - return SEUtils.arraysEqual(hash, this.certHash); - })); - } -}; - -function ACEService() { - this._rulesManagers = new Map(); - - this._rulesManagers.set( - SE.TYPE_UICC, - Cc["@mozilla.org/secureelement/access-control/rules-manager;1"] - .createInstance(Ci.nsIAccessRulesManager)); -} - -ACEService.prototype = { - _rulesManagers: null, - - isAccessAllowed: function isAccessAllowed(localId, seType, aid) { - if(!Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps")) { - debug("Certified apps debug enabled, allowing access"); - return Promise.resolve(true); - } - - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - _getDevCertHashForApp: function getDevCertHashForApp(manifestURL) { - throw Components.results.NS_ERROR_NOT_IMPLEMENTED; - }, - - classID: Components.ID("{882a7463-2ca7-4d61-a89a-10eb6fd70478}"), - contractID: "@mozilla.org/secureelement/access-control/ace;1", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessControlEnforcer]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ACEService]); - diff --git a/dom/secureelement/gonk/ACEService.manifest b/dom/secureelement/gonk/ACEService.manifest deleted file mode 100644 index 40949c83d..000000000 --- a/dom/secureelement/gonk/ACEService.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {882a7463-2ca7-4d61-a89a-10eb6fd70478} ACEService.js -contract @mozilla.org/secureelement/access-control/ace;1 {882a7463-2ca7-4d61-a89a-10eb6fd70478} \ No newline at end of file diff --git a/dom/secureelement/gonk/GPAccessRulesManager.js b/dom/secureelement/gonk/GPAccessRulesManager.js deleted file mode 100644 index dce11ec09..000000000 --- a/dom/secureelement/gonk/GPAccessRulesManager.js +++ /dev/null @@ -1,436 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -"use strict"; - -const Ci = Components.interfaces; -const Cu = Components.utils; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/Task.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyServiceGetter(this, "UiccConnector", - "@mozilla.org/secureelement/connector/uicc;1", - "nsISecureElementConnector"); - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "SE", function() { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -XPCOMUtils.defineLazyGetter(this, "GP", function() { - let obj = {}; - Cu.import("resource://gre/modules/gp_consts.js", obj); - return obj; -}); - -var DEBUG = SE.DEBUG_ACE; -function debug(msg) { - if (DEBUG) { - dump("-*- GPAccessRulesManager " + msg); - } -} - -/** - * Based on [1] - "GlobalPlatform Device Technology - * Secure Element Access Control Version 1.0". - * GPAccessRulesManager reads and parses access rules from SE file system - * as defined in section #7 of [1]: "Structure of Access Rule Files (ARF)". - * Rules retrieval from ARA-M applet is not implmented due to lack of - * commercial implemenations of ARA-M. - * @todo Bug 1137537: Implement ARA-M support according to section #4 of [1] - */ -function GPAccessRulesManager() {} - -GPAccessRulesManager.prototype = { - // source [1] section 7.1.3 PKCS#15 Selection - PKCS_AID: "a000000063504b43532d3135", - - // APDUs (ISO 7816-4) for accessing rules on SE file system - // see for more details: http://www.cardwerk.com/smartcards/ - // smartcard_standard_ISO7816-4_6_basic_interindustry_commands.aspx - READ_BINARY: [GP.CLA_SM, GP.INS_RB, GP.P1_RB, GP.P2_RB], - GET_RESPONSE: [GP.CLA_SM, GP.INS_GR, GP.P1_GR, GP.P2_GR], - SELECT_BY_DF: [GP.CLA_SM, GP.INS_SF, GP.P1_SF_DF, GP.P2_SF_FCP], - - // Non-null if there is a channel open - channel: null, - - // Refresh tag path in the acMain file as described in GPD spec, - // sections 7.1.5 and C.1. - REFRESH_TAG_PATH: [GP.TAG_SEQUENCE, GP.TAG_OCTETSTRING], - refreshTag: null, - - // Contains rules as read from the SE - rules: [], - - // Returns the latest rules. Results are cached. - getAccessRules: function getAccessRules() { - debug("getAccessRules"); - - return new Promise((resolve, reject) => { - this._readAccessRules(() => resolve(this.rules)); - }); - }, - - _readAccessRules: Task.async(function*(done) { - try { - yield this._openChannel(this.PKCS_AID); - - let odf = yield this._readODF(); - let dodf = yield this._readDODF(odf); - - let acmf = yield this._readACMF(dodf); - let refreshTag = acmf[this.REFRESH_TAG_PATH[0]] - [this.REFRESH_TAG_PATH[1]]; - - // Update cached rules based on refreshTag. - if (SEUtils.arraysEqual(this.refreshTag, refreshTag)) { - debug("_readAccessRules: refresh tag equals to the one saved."); - yield this._closeChannel(); - return done(); - } - - this.refreshTag = refreshTag; - debug("_readAccessRules: refresh tag saved: " + this.refreshTag); - - let acrf = yield this._readACRules(acmf); - let accf = yield this._readACConditions(acrf); - this.rules = yield this._parseRules(acrf, accf); - - DEBUG && debug("_readAccessRules: " + JSON.stringify(this.rules, 0, 2)); - - yield this._closeChannel(); - done(); - } catch (error) { - debug("_readAccessRules: " + error); - this.rules = []; - yield this._closeChannel(); - done(); - } - }), - - _openChannel: function _openChannel(aid) { - if (this.channel !== null) { - debug("_openChannel: Channel already opened, rejecting."); - return Promise.reject(); - } - - return new Promise((resolve, reject) => { - UiccConnector.openChannel(aid, { - notifyOpenChannelSuccess: (channel, openResponse) => { - debug("_openChannel/notifyOpenChannelSuccess: Channel " + channel + - " opened, open response: " + openResponse); - this.channel = channel; - resolve(); - }, - notifyError: (error) => { - debug("_openChannel/notifyError: failed to open channel, error: " + - error); - reject(error); - } - }); - }); - }, - - _closeChannel: function _closeChannel() { - if (this.channel === null) { - debug("_closeChannel: Channel not opened, rejecting."); - return Promise.reject(); - } - - return new Promise((resolve, reject) => { - UiccConnector.closeChannel(this.channel, { - notifyCloseChannelSuccess: () => { - debug("_closeChannel/notifyCloseChannelSuccess: chanel " + - this.channel + " closed"); - this.channel = null; - resolve(); - }, - notifyError: (error) => { - debug("_closeChannel/notifyError: error closing channel, error" + - error); - reject(error); - } - }); - }); - }, - - _exchangeAPDU: function _exchangeAPDU(bytes) { - DEBUG && debug("apdu " + JSON.stringify(bytes)); - - let apdu = this._bytesToAPDU(bytes); - return new Promise((resolve, reject) => { - UiccConnector.exchangeAPDU(this.channel, apdu.cla, - apdu.ins, apdu.p1, apdu.p2, apdu.data, apdu.le, - { - notifyExchangeAPDUResponse: (sw1, sw2, data) => { - debug("APDU response is " + sw1.toString(16) + sw2.toString(16) + - " data: " + data); - - // 90 00 is "success" - if (sw1 !== 0x90 && sw2 !== 0x00) { - debug("rejecting APDU response"); - reject(new Error("Response " + sw1 + "," + sw2)); - return; - } - - resolve(this._parseTLV(data)); - }, - - notifyError: (error) => { - debug("_exchangeAPDU/notifyError " + error); - reject(error); - } - } - ); - }); - }, - - _readBinaryFile: function _readBinaryFile(selectResponse) { - DEBUG && debug("Select response: " + JSON.stringify(selectResponse)); - // 0x80 tag parameter - get the elementary file (EF) length - // without structural information. - let fileLength = selectResponse[GP.TAG_FCP][0x80]; - - // If file is empty, no need to attempt to read it. - if (fileLength[0] === 0 && fileLength[1] === 0) { - return Promise.resolve(null); - } - - // TODO READ BINARY with filelength not supported - // let readApdu = this.READ_BINARY.concat(fileLength); - return this._exchangeAPDU(this.READ_BINARY); - }, - - _selectAndRead: function _selectAndRead(df) { - return this._exchangeAPDU(this.SELECT_BY_DF.concat(df.length & 0xFF, df)) - .then((resp) => this._readBinaryFile(resp)); - }, - - _readODF: function _readODF() { - debug("_readODF"); - return this._selectAndRead(GP.ODF_DF); - }, - - _readDODF: function _readDODF(odfFile) { - debug("_readDODF, ODF file: " + odfFile); - - // Data Object Directory File (DODF) is used as an entry point to the - // Access Control data. It is specified in PKCS#15 section 6.7.6. - // DODF is referenced by the ODF file, which looks as follows: - // A7 06 - // 30 04 - // 04 02 XY WZ - // where [0xXY, 0xWZ] is a DF of DODF file. - let DODF_DF = odfFile[GP.TAG_EF_ODF][GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - return this._selectAndRead(DODF_DF); - }, - - _readACMF: function _readACMF(dodfFile) { - debug("_readACMF, DODF file: " + dodfFile); - - // ACMF file DF is referenced in DODF file, which looks like this: - // - // A1 29 - // 30 00 - // 30 0F - // 0C 0D 47 50 20 53 45 20 41 63 63 20 43 74 6C - // A1 14 - // 30 12 - // 06 0A 2A 86 48 86 FC 6B 81 48 01 01 <-- GPD registered OID - // 30 04 - // 04 02 AB CD <-- ACMF DF - // A1 2B - // 30 00 - // 30 0F - // 0C 0D 53 41 54 53 41 20 47 54 4F 20 31 2E 31 - // A1 16 - // 30 14 - // 06 0C 2B 06 01 04 01 2A 02 6E 03 01 01 01 <-- some other OID - // 30 04 - // 04 02 XY WZ <-- some other file's DF - // - // DODF file consists of DataTypes with oidDO entries. Entry with OID - // equal to "1.2.840.114283.200.1.1" ("2A 86 48 86 FC 6B 81 48 01 01") - // contains DF of the ACMF. In the file above, it means that ACMF DF - // equals to [0xAB, 0xCD], and not [0xXY, 0xWZ]. - // - // Algorithm used to encode OID to an byte array: - // http://www.snmpsharpnet.com/?p=153 - - let gpdOid = [0x2A, // 1.2 - 0x86, 0x48, // 840 - 0x86, 0xFC, 0x6B, // 114283 - 0x81, 0x48, // 129 - 0x01, // 1 - 0x01]; // 1 - - let records = SEUtils.ensureIsArray(dodfFile[GP.TAG_EXTERNALDO]); - - // Look for the OID registered for GPD SE. - let gpdRecords = records.filter((record) => { - let oid = record[GP.TAG_EXTERNALDO][GP.TAG_SEQUENCE][GP.TAG_OID]; - return SEUtils.arraysEqual(oid, gpdOid); - }); - - // [1] 7.1.5: "There shall be only one ACMF file per Secure Element. - // If a Secure Element contains several ACMF files, then the security shall - // be considered compromised and the Access Control enforcer shall forbid - // access to all (...) apps." - if (gpdRecords.length !== 1) { - return Promise.reject(new Error(gpdRecords.length + " ACMF files found")); - } - - let ACMain_DF = gpdRecords[0][GP.TAG_EXTERNALDO][GP.TAG_SEQUENCE] - [GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - return this._selectAndRead(ACMain_DF); - }, - - _readACRules: function _readACRules(acMainFile) { - debug("_readACRules, ACMain file: " + acMainFile); - - // ACMF looks like this: - // - // 30 10 - // 04 08 XX XX XX XX XX XX XX XX - // 30 04 - // 04 02 XY WZ - // - // where [XY, WZ] is a DF of ACRF, and XX XX XX XX XX XX XX XX is a refresh - // tag. - - let ACRules_DF = acMainFile[GP.TAG_SEQUENCE][GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - return this._selectAndRead(ACRules_DF); - }, - - _readACConditions: function _readACConditions(acRulesFile) { - debug("_readACCondition, ACRules file: " + acRulesFile); - - let acRules = SEUtils.ensureIsArray(acRulesFile[GP.TAG_SEQUENCE]); - if (acRules.length === 0) { - debug("No rules found in ACRules file."); - return Promise.reject(new Error("No rules found in ACRules file")); - } - - // We first read all the condition files referenced in the ACRules file, - // because ACRules file might reference one ACCondition file more than - // once. Since reading it isn't exactly fast, we optimize here. - let acReadQueue = Promise.resolve({}); - - acRules.forEach((ruleEntry) => { - let df = ruleEntry[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - - // Promise chain read condition entries: - let readAcCondition = (acConditionFiles) => { - if (acConditionFiles[df] !== undefined) { - debug("Skipping previously read acCondition df: " + df); - return acConditionFiles; - } - - return this._selectAndRead(df) - .then((acConditionFileContents) => { - acConditionFiles[df] = acConditionFileContents; - return acConditionFiles; - }); - } - - acReadQueue = acReadQueue.then(readAcCondition); - }); - - return acReadQueue; - }, - - _parseRules: function _parseRules(acRulesFile, acConditionFiles) { - DEBUG && debug("_parseRules: acConditionFiles " + JSON.stringify(acConditionFiles)); - let rules = []; - - let acRules = SEUtils.ensureIsArray(acRulesFile[GP.TAG_SEQUENCE]); - acRules.forEach((ruleEntry) => { - DEBUG && debug("Parsing one rule: " + JSON.stringify(ruleEntry)); - let rule = {}; - - // 0xA0 and 0x82 tags as per GPD spec sections C.1 - C.3. 0xA0 means - // that rule describes access to one SE applet only (and its AID is - // given). 0x82 means that rule describes acccess to all SE applets. - let oneApplet = ruleEntry[GP.TAG_GPD_AID]; - let allApplets = ruleEntry[GP.TAG_GPD_ALL]; - - if (oneApplet) { - rule.applet = oneApplet[GP.TAG_OCTETSTRING]; - } else if (allApplets) { - rule.applet = Ci.nsIAccessRulesManager.ALL_APPLET; - } else { - throw Error("Unknown applet definition"); - } - - let df = ruleEntry[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]; - let condition = acConditionFiles[df]; - if (condition === null) { - rule.application = Ci.nsIAccessRulesManager.DENY_ALL; - } else if (condition[GP.TAG_SEQUENCE]) { - if (!Array.isArray(condition[GP.TAG_SEQUENCE]) && - !condition[GP.TAG_SEQUENCE][GP.TAG_OCTETSTRING]) { - rule.application = Ci.nsIAccessRulesManager.ALLOW_ALL; - } else { - rule.application = SEUtils.ensureIsArray(condition[GP.TAG_SEQUENCE]) - .map((conditionEntry) => { - return conditionEntry[GP.TAG_OCTETSTRING]; - }); - } - } else { - throw Error("Unknown application definition"); - } - - DEBUG && debug("Rule parsed, adding to the list: " + JSON.stringify(rule)); - rules.push(rule); - }); - - DEBUG && debug("All rules parsed, we have those in total: " + JSON.stringify(rules)); - return rules; - }, - - _parseTLV: function _parseTLV(bytes) { - let containerTags = [ - GP.TAG_SEQUENCE, - GP.TAG_FCP, - GP.TAG_GPD_AID, - GP.TAG_EXTERNALDO, - GP.TAG_INDIRECT, - GP.TAG_EF_ODF - ]; - return SEUtils.parseTLV(bytes, containerTags); - }, - - // TODO consider removing if better format for storing - // APDU consts will be introduced - _bytesToAPDU: function _bytesToAPDU(arr) { - let apdu = { - cla: arr[0] & 0xFF, - ins: arr[1] & 0xFF, - p1: arr[2] & 0xFF, - p2: arr[3] & 0xFF, - p3: arr[4] & 0xFF, - le: 0 - }; - - let data = (apdu.p3 > 0) ? (arr.slice(5)) : []; - apdu.data = (data.length) ? SEUtils.byteArrayToHexString(data) : null; - return apdu; - }, - - classID: Components.ID("{3e046b4b-9e66-439a-97e0-98a69f39f55f}"), - contractID: "@mozilla.org/secureelement/access-control/rules-manager;1", - QueryInterface: XPCOMUtils.generateQI([Ci.nsIAccessRulesManager]) -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([GPAccessRulesManager]); diff --git a/dom/secureelement/gonk/GPAccessRulesManager.manifest b/dom/secureelement/gonk/GPAccessRulesManager.manifest deleted file mode 100644 index 2d7ea038b..000000000 --- a/dom/secureelement/gonk/GPAccessRulesManager.manifest +++ /dev/null @@ -1,2 +0,0 @@ -component {3e046b4b-9e66-439a-97e0-98a69f39f55f} GPAccessRulesManager.js -contract @mozilla.org/secureelement/access-control/rules-manager;1 {3e046b4b-9e66-439a-97e0-98a69f39f55f} diff --git a/dom/secureelement/gonk/SecureElement.js b/dom/secureelement/gonk/SecureElement.js deleted file mode 100644 index 144c6d8d6..000000000 --- a/dom/secureelement/gonk/SecureElement.js +++ /dev/null @@ -1,514 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -/* Copyright © 2014, Deutsche Telekom, Inc. */ - -"use strict"; - -/* globals dump, Components, XPCOMUtils, SE, Services, UiccConnector, - SEUtils, ppmm, gMap, UUIDGenerator */ - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyGetter(this, "SE", () => { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -// set to true in se_consts.js to see debug messages -var DEBUG = SE.DEBUG_SE; -function debug(s) { - if (DEBUG) { - dump("-*- SecureElement: " + s + "\n"); - } -} - -const SE_IPC_SECUREELEMENT_MSG_NAMES = [ - "SE:GetSEReaders", - "SE:OpenChannel", - "SE:CloseChannel", - "SE:TransmitAPDU" -]; - -const SECUREELEMENTMANAGER_CONTRACTID = - "@mozilla.org/secureelement/parent-manager;1"; -const SECUREELEMENTMANAGER_CID = - Components.ID("{48f4e650-28d2-11e4-8c21-0800200c9a66}"); -const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageBroadcaster"); - -XPCOMUtils.defineLazyServiceGetter(this, "UUIDGenerator", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "UiccConnector", () => { - let uiccClass = Cc["@mozilla.org/secureelement/connector/uicc;1"]; - return uiccClass ? uiccClass.getService(Ci.nsISecureElementConnector) : null; -}); - -function getConnector(type) { - switch (type) { - case SE.TYPE_UICC: - return UiccConnector; - case SE.TYPE_ESE: - default: - debug("Unsupported SEConnector : " + type); - return null; - } -} - -/** - * 'gMap' is a nested dictionary object that manages all the information - * pertaining to channels for a given application (appId). It manages the - * relationship between given application and its opened channels. - */ -XPCOMUtils.defineLazyGetter(this, "gMap", function() { - return { - // example structure of AppInfoMap - // { - // "appId1": { - // target: target1, - // channels: { - // "channelToken1": { - // seType: "uicc", - // aid: "aid1", - // channelNumber: 1 - // }, - // "channelToken2": { ... } - // } - // }, - // "appId2": { ... } - // } - appInfoMap: {}, - - registerSecureElementTarget: function(appId, target) { - if (this.isAppIdRegistered(appId)) { - debug("AppId: " + appId + "already registered"); - return; - } - - this.appInfoMap[appId] = { - target: target, - channels: {} - }; - - debug("Registered a new SE target " + appId); - }, - - unregisterSecureElementTarget: function(target) { - let appId = Object.keys(this.appInfoMap).find((id) => { - return this.appInfoMap[id].target === target; - }); - - if (!appId) { - return; - } - - debug("Unregistered SE Target for AppId: " + appId); - delete this.appInfoMap[appId]; - }, - - isAppIdRegistered: function(appId) { - return this.appInfoMap[appId] !== undefined; - }, - - getChannelCountByAppIdType: function(appId, type) { - return Object.keys(this.appInfoMap[appId].channels) - .reduce((cnt, ch) => ch.type === type ? ++cnt : cnt, 0); - }, - - // Add channel to the appId. Upon successfully adding the entry - // this function will return the 'token' - addChannel: function(appId, type, aid, channelNumber) { - let token = UUIDGenerator.generateUUID().toString(); - this.appInfoMap[appId].channels[token] = { - seType: type, - aid: aid, - channelNumber: channelNumber - }; - return token; - }, - - removeChannel: function(appId, channelToken) { - if (this.appInfoMap[appId].channels[channelToken]) { - debug("Deleting channel with token : " + channelToken); - delete this.appInfoMap[appId].channels[channelToken]; - } - }, - - getChannel: function(appId, channelToken) { - if (!this.appInfoMap[appId].channels[channelToken]) { - return null; - } - - return this.appInfoMap[appId].channels[channelToken]; - }, - - getChannelsByTarget: function(target) { - let appId = Object.keys(this.appInfoMap).find((id) => { - return this.appInfoMap[id].target === target; - }); - - if (!appId) { - return []; - } - - return Object.keys(this.appInfoMap[appId].channels) - .map(token => this.appInfoMap[appId].channels[token]); - }, - - getTargets: function() { - return Object.keys(this.appInfoMap) - .map(appId => this.appInfoMap[appId].target); - }, - }; -}); - -/** - * 'SecureElementManager' is the main object that handles IPC messages from - * child process. It interacts with other objects such as 'gMap' & 'Connector - * instances (UiccConnector, eSEConnector)' to perform various - * SE-related (open, close, transmit) operations. - * @TODO: Bug 1118097 Support slot based SE/reader names - * @TODO: Bug 1118101 Introduce SE type specific permissions - */ -function SecureElementManager() { - this._registerMessageListeners(); - this._registerSEListeners(); - Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - this._acEnforcer = - Cc["@mozilla.org/secureelement/access-control/ace;1"] - .getService(Ci.nsIAccessControlEnforcer); -} - -SecureElementManager.prototype = { - QueryInterface: XPCOMUtils.generateQI([ - Ci.nsIMessageListener, - Ci.nsISEListener, - Ci.nsIObserver]), - classID: SECUREELEMENTMANAGER_CID, - classInfo: XPCOMUtils.generateCI({ - classID: SECUREELEMENTMANAGER_CID, - classDescription: "SecureElementManager", - interfaces: [Ci.nsIMessageListener, - Ci.nsISEListener, - Ci.nsIObserver] - }), - - // Stores information about supported SE types and their presence. - // key: secure element type, value: (Boolean) is present/accessible - _sePresence: {}, - - _acEnforcer: null, - - _shutdown: function() { - this._acEnforcer = null; - this.secureelement = null; - Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - this._unregisterMessageListeners(); - this._unregisterSEListeners(); - }, - - _registerMessageListeners: function() { - ppmm.addMessageListener("child-process-shutdown", this); - for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) { - ppmm.addMessageListener(msgname, this); - } - }, - - _unregisterMessageListeners: function() { - ppmm.removeMessageListener("child-process-shutdown", this); - for (let msgname of SE_IPC_SECUREELEMENT_MSG_NAMES) { - ppmm.removeMessageListener(msgname, this); - } - ppmm = null; - }, - - _registerSEListeners: function() { - let connector = getConnector(SE.TYPE_UICC); - if (!connector) { - return; - } - - this._sePresence[SE.TYPE_UICC] = false; - connector.registerListener(this); - }, - - _unregisterSEListeners: function() { - Object.keys(this._sePresence).forEach((type) => { - let connector = getConnector(type); - if (connector) { - connector.unregisterListener(this); - } - }); - - this._sePresence = {}; - }, - - notifySEPresenceChanged: function(type, isPresent) { - // we need to notify all targets, even those without open channels, - // app could've stored the reader without actually using it - debug("notifying DOM about SE state change"); - this._sePresence[type] = isPresent; - gMap.getTargets().forEach(target => { - let result = { type: type, isPresent: isPresent }; - target.sendAsyncMessage("SE:ReaderPresenceChanged", { result: result }); - }); - }, - - _canOpenChannel: function(appId, type) { - let opened = gMap.getChannelCountByAppIdType(appId, type); - let limit = SE.MAX_CHANNELS_ALLOWED_PER_SESSION; - // UICC basic channel is not accessible see comment in se_consts.js - limit = type === SE.TYPE_UICC ? limit - 1 : limit; - return opened < limit; - }, - - _handleOpenChannel: function(msg, callback) { - if (!this._canOpenChannel(msg.appId, msg.type)) { - debug("Max channels per session exceed"); - callback({ error: SE.ERROR_GENERIC }); - return; - } - - let connector = getConnector(msg.type); - if (!connector) { - debug("No SE connector available"); - callback({ error: SE.ERROR_NOTPRESENT }); - return; - } - - this._acEnforcer.isAccessAllowed(msg.appId, msg.type, msg.aid) - .then((allowed) => { - if (!allowed) { - callback({ error: SE.ERROR_SECURITY }); - return; - } - connector.openChannel(SEUtils.byteArrayToHexString(msg.aid), { - - notifyOpenChannelSuccess: (channelNumber, openResponse) => { - // Add the new 'channel' to the map upon success - let channelToken = - gMap.addChannel(msg.appId, msg.type, msg.aid, channelNumber); - if (channelToken) { - callback({ - error: SE.ERROR_NONE, - channelToken: channelToken, - isBasicChannel: (channelNumber === SE.BASIC_CHANNEL), - openResponse: SEUtils.hexStringToByteArray(openResponse) - }); - } else { - callback({ error: SE.ERROR_GENERIC }); - } - }, - - notifyError: (reason) => { - debug("Failed to open the channel to AID : " + - SEUtils.byteArrayToHexString(msg.aid) + - ", Rejected with Reason : " + reason); - callback({ error: SE.ERROR_GENERIC, reason: reason, response: [] }); - } - }); - }) - .catch((error) => { - debug("Failed to get info from accessControlEnforcer " + error); - callback({ error: SE.ERROR_SECURITY }); - }); - }, - - _handleTransmit: function(msg, callback) { - let channel = gMap.getChannel(msg.appId, msg.channelToken); - if (!channel) { - debug("Invalid token:" + msg.channelToken + ", appId: " + msg.appId); - callback({ error: SE.ERROR_GENERIC }); - return; - } - - let connector = getConnector(channel.seType); - if (!connector) { - debug("No SE connector available"); - callback({ error: SE.ERROR_NOTPRESENT }); - return; - } - - // Bug 1137533 - ACE GPAccessRulesManager APDU filters - connector.exchangeAPDU(channel.channelNumber, msg.apdu.cla, msg.apdu.ins, - msg.apdu.p1, msg.apdu.p2, - SEUtils.byteArrayToHexString(msg.apdu.data), - msg.apdu.le, { - notifyExchangeAPDUResponse: (sw1, sw2, response) => { - callback({ - error: SE.ERROR_NONE, - sw1: sw1, - sw2: sw2, - response: SEUtils.hexStringToByteArray(response) - }); - }, - - notifyError: (reason) => { - debug("Transmit failed, rejected with Reason : " + reason); - callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason }); - } - }); - }, - - _handleCloseChannel: function(msg, callback) { - let channel = gMap.getChannel(msg.appId, msg.channelToken); - if (!channel) { - debug("Invalid token:" + msg.channelToken + ", appId:" + msg.appId); - callback({ error: SE.ERROR_GENERIC }); - return; - } - - let connector = getConnector(channel.seType); - if (!connector) { - debug("No SE connector available"); - callback({ error: SE.ERROR_NOTPRESENT }); - return; - } - - connector.closeChannel(channel.channelNumber, { - notifyCloseChannelSuccess: () => { - gMap.removeChannel(msg.appId, msg.channelToken); - callback({ error: SE.ERROR_NONE }); - }, - - notifyError: (reason) => { - debug("Failed to close channel with token: " + msg.channelToken + - ", reason: "+ reason); - callback({ error: SE.ERROR_BADSTATE, reason: reason }); - } - }); - }, - - _handleGetSEReadersRequest: function(msg, target, callback) { - gMap.registerSecureElementTarget(msg.appId, target); - let readers = Object.keys(this._sePresence).map(type => { - return { type: type, isPresent: this._sePresence[type] }; - }); - callback({ readers: readers, error: SE.ERROR_NONE }); - }, - - _handleChildProcessShutdown: function(target) { - let channels = gMap.getChannelsByTarget(target); - - let createCb = (seType, channelNumber) => { - return { - notifyCloseChannelSuccess: () => { - debug("closed " + seType + ", channel " + channelNumber); - }, - - notifyError: (reason) => { - debug("Failed to close " + seType + " channel " + - channelNumber + ", reason: " + reason); - } - }; - }; - - channels.forEach((channel) => { - let connector = getConnector(channel.seType); - if (!connector) { - return; - } - - connector.closeChannel(channel.channelNumber, - createCb(channel.seType, channel.channelNumber)); - }); - - gMap.unregisterSecureElementTarget(target); - }, - - _sendSEResponse: function(msg, result) { - let promiseStatus = (result.error === SE.ERROR_NONE) ? "Resolved" : "Rejected"; - result.resolverId = msg.data.resolverId; - msg.target.sendAsyncMessage(msg.name + promiseStatus, {result: result}); - }, - - _isValidMessage: function(msg) { - let appIdValid = gMap.isAppIdRegistered(msg.data.appId); - return msg.name === "SE:GetSEReaders" ? true : appIdValid; - }, - - /** - * nsIMessageListener interface methods. - */ - - receiveMessage: function(msg) { - DEBUG && debug("Received '" + msg.name + "' message from content process" + - ": " + JSON.stringify(msg.data)); - - if (msg.name === "child-process-shutdown") { - this._handleChildProcessShutdown(msg.target); - return null; - } - - if (SE_IPC_SECUREELEMENT_MSG_NAMES.indexOf(msg.name) !== -1) { - if (!msg.target.assertPermission("secureelement-manage")) { - debug("SecureElement message " + msg.name + " from a content process " + - "with no 'secureelement-manage' privileges."); - return null; - } - } else { - debug("Ignoring unknown message type: " + msg.name); - return null; - } - - let callback = (result) => this._sendSEResponse(msg, result); - if (!this._isValidMessage(msg)) { - debug("Message not valid"); - callback({ error: SE.ERROR_GENERIC }); - return null; - } - - switch (msg.name) { - case "SE:GetSEReaders": - this._handleGetSEReadersRequest(msg.data, msg.target, callback); - break; - case "SE:OpenChannel": - this._handleOpenChannel(msg.data, callback); - break; - case "SE:CloseChannel": - this._handleCloseChannel(msg.data, callback); - break; - case "SE:TransmitAPDU": - this._handleTransmit(msg.data, callback); - break; - } - return null; - }, - - /** - * nsIObserver interface methods. - */ - - observe: function(subject, topic, data) { - if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) { - this._shutdown(); - } - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SecureElementManager]); diff --git a/dom/secureelement/gonk/SecureElement.manifest b/dom/secureelement/gonk/SecureElement.manifest deleted file mode 100644 index a76fcfc11..000000000 --- a/dom/secureelement/gonk/SecureElement.manifest +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# 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. - -# SecureElementManager -component {48f4e650-28d2-11e4-8c21-0800200c9a66} SecureElement.js -contract @mozilla.org/secureelement/parent-manager;1 {48f4e650-28d2-11e4-8c21-0800200c9a66} -category profile-after-change SecureElementManager @mozilla.org/secureelement/parent-manager;1 diff --git a/dom/secureelement/gonk/UiccConnector.js b/dom/secureelement/gonk/UiccConnector.js deleted file mode 100644 index 517303de2..000000000 --- a/dom/secureelement/gonk/UiccConnector.js +++ /dev/null @@ -1,360 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -/* Copyright © 2014, Deutsche Telekom, Inc. */ - -"use strict"; - -/* globals Components, XPCOMUtils, SE, dump, libcutils, Services, - iccService, SEUtils */ - -const { interfaces: Ci, utils: Cu, results: Cr } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyGetter(this, "SE", function() { - let obj = {}; - Cu.import("resource://gre/modules/se_consts.js", obj); - return obj; -}); - -// set to true in se_consts.js to see debug messages -var DEBUG = SE.DEBUG_CONNECTOR; -function debug(s) { - if (DEBUG) { - dump("-*- UiccConnector: " + s + "\n"); - } -} - -XPCOMUtils.defineLazyModuleGetter(this, "SEUtils", - "resource://gre/modules/SEUtils.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "iccService", - "@mozilla.org/icc/iccservice;1", - "nsIIccService"); - -const UICCCONNECTOR_CONTRACTID = - "@mozilla.org/secureelement/connector/uicc;1"; -const UICCCONNECTOR_CID = - Components.ID("{8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4}"); -const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; - -// TODO: Bug 1118099 - Add multi-sim support. -// In the Multi-sim, there is more than one client. -// For now, use default clientID as 0. Ideally, SE parent process would like to -// know which clients (uicc slot) are connected to CLF over SWP interface. -const PREFERRED_UICC_CLIENTID = - libcutils.property_get("ro.moz.se.def_client_id", "0"); - -/** - * 'UiccConnector' object is a wrapper over iccService's channel management - * related interfaces that implements nsISecureElementConnector interface. - */ -function UiccConnector() { - this._init(); -} - -UiccConnector.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsISecureElementConnector, - Ci.nsIIccListener]), - classID: UICCCONNECTOR_CID, - classInfo: XPCOMUtils.generateCI({ - classID: UICCCONNECTOR_CID, - contractID: UICCCONNECTOR_CONTRACTID, - classDescription: "UiccConnector", - interfaces: [Ci.nsISecureElementConnector, - Ci.nsIIccListener, - Ci.nsIObserver] - }), - - _SEListeners: [], - _isPresent: false, - - _init: function() { - Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.registerListener(this); - - // Update the state in order to avoid race condition. - // By this time, 'notifyCardStateChanged (with proper card state)' - // may have occurred already before this module initialization. - this._updatePresenceState(); - }, - - _shutdown: function() { - Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.unregisterListener(this); - }, - - _updatePresenceState: function() { - let uiccNotReadyStates = [ - Ci.nsIIcc.CARD_STATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_ILLEGAL, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS, - Ci.nsIIcc.CARD_STATE_PERMANENT_BLOCKED, - Ci.nsIIcc.CARD_STATE_UNDETECTED - ]; - - let cardState = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID).cardState; - let uiccPresent = cardState !== null && - uiccNotReadyStates.indexOf(cardState) == -1; - - if (this._isPresent === uiccPresent) { - return; - } - - debug("Uicc presence changed " + this._isPresent + " -> " + uiccPresent); - this._isPresent = uiccPresent; - this._SEListeners.forEach((listener) => { - listener.notifySEPresenceChanged(SE.TYPE_UICC, this._isPresent); - }); - }, - - // See GP Spec, 11.1.4 Class Byte Coding - _setChannelToCLAByte: function(cla, channel) { - if (channel < SE.LOGICAL_CHANNEL_NUMBER_LIMIT) { - // b7 = 0 indicates the first interindustry class byte coding - cla = (cla & 0x9C) & 0xFF | channel; - } else if (channel < SE.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT) { - // b7 = 1 indicates the further interindustry class byte coding - cla = (cla & 0xB0) & 0xFF | 0x40 | (channel - SE.LOGICAL_CHANNEL_NUMBER_LIMIT); - } else { - debug("Channel number must be within [0..19]"); - return SE.ERROR_GENERIC; - } - return cla; - }, - - _doGetOpenResponse: function(channel, length, callback) { - // Le value is set. It means that this is a request for all available - // response bytes. - let cla = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE, channel); - this.exchangeAPDU(channel, cla, SE.INS_GET_RESPONSE, 0x00, 0x00, - null, length, { - notifyExchangeAPDUResponse: function(sw1, sw2, response) { - debug("GET Response : " + response); - if (callback) { - callback({ - error: SE.ERROR_NONE, - sw1: sw1, - sw2: sw2, - response: response - }); - } - }, - - notifyError: function(reason) { - debug("Failed to get open response: " + - ", Rejected with Reason : " + reason); - if (callback) { - callback({ error: SE.ERROR_INVALIDAPPLICATION, reason: reason }); - } - } - }); - }, - - _doIccExchangeAPDU: function(channel, cla, ins, p1, p2, p3, - data, appendResp, callback) { - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.iccExchangeAPDU(channel, cla & 0xFC, ins, p1, p2, p3, data, { - notifyExchangeAPDUResponse: (sw1, sw2, response) => { - debug("sw1 : " + sw1 + ", sw2 : " + sw2 + ", response : " + response); - - // According to ETSI TS 102 221 , Section 7.2.2.3.1, - // Enforce 'Procedure bytes' checks before notifying the callback. - // Note that 'Procedure bytes'are special cases. - // There is no need to handle '0x60' procedure byte as it implies - // no-action from SE stack perspective. This procedure byte is not - // notified to application layer. - if (sw1 === 0x6C) { - // Use the previous command header with length as second procedure - // byte (SW2) as received and repeat the procedure. - - // Recursive! and Pass empty response '' as args, since '0x6C' - // procedure does not have to deal with appended responses. - this._doIccExchangeAPDU(channel, cla, ins, p1, p2, - sw2, data, "", callback); - } else if (sw1 === 0x61) { - // Since the terminal waited for a second procedure byte and - // received it (sw2), send a GET RESPONSE command header to the UICC - // with a maximum length of 'XX', where 'XX' is the value of the - // second procedure byte (SW2). - - let claWithChannel = this._setChannelToCLAByte(SE.CLA_GET_RESPONSE, - channel); - - // Recursive, with GET RESPONSE bytes and '0x61' procedure IS interested - // in appended responses. Pass appended response and note that p3=sw2. - this._doIccExchangeAPDU(channel, claWithChannel, SE.INS_GET_RESPONSE, - 0x00, 0x00, sw2, null, - (response ? response + appendResp : appendResp), - callback); - } else if (callback) { - callback.notifyExchangeAPDUResponse(sw1, sw2, response); - } - }, - - notifyError: (reason) => { - debug("Failed to trasmit C-APDU over the channel # : " + channel + - ", Rejected with Reason : " + reason); - if (callback) { - callback.notifyError(reason); - } - } - }); - }, - - /** - * nsISecureElementConnector interface methods. - */ - - /** - * Opens a channel on a default clientId - */ - openChannel: function(aid, callback) { - if (!this._isPresent) { - callback.notifyError(SE.ERROR_NOTPRESENT); - return; - } - - // TODO: Bug 1118106: Handle Resource management / leaks by persisting - // the newly opened channel in some persistent storage so that when this - // module gets restarted (say after opening a channel) in the event of - // some erroneous conditions such as gecko restart /, crash it can read - // the persistent storage to check if there are any held resources - // (opened channels) and close them. - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.iccOpenChannel(aid, { - notifyOpenChannelSuccess: (channel) => { - this._doGetOpenResponse(channel, 0x00, function(result) { - if (callback) { - callback.notifyOpenChannelSuccess(channel, result.response); - } - }); - }, - - notifyError: (reason) => { - debug("Failed to open the channel to AID : " + aid + - ", Rejected with Reason : " + reason); - if (callback) { - callback.notifyError(reason); - } - } - }); - }, - - /** - * Transmit the C-APDU (command) on default clientId. - */ - exchangeAPDU: function(channel, cla, ins, p1, p2, data, le, callback) { - if (!this._isPresent) { - callback.notifyError(SE.ERROR_NOTPRESENT); - return; - } - - if (data && data.length % 2 !== 0) { - callback.notifyError("Data should be a hex string with length % 2 === 0"); - return; - } - - cla = this._setChannelToCLAByte(cla, channel); - let lc = data ? data.length / 2 : 0; - let p3 = lc || le; - - if (lc && (le !== -1)) { - data += SEUtils.byteArrayToHexString([le]); - } - - // Pass empty response '' as args as we are not interested in appended - // responses yet! - debug("exchangeAPDU on Channel # " + channel); - this._doIccExchangeAPDU(channel, cla, ins, p1, p2, p3, data, "", - callback); - }, - - /** - * Closes the channel on default clientId. - */ - closeChannel: function(channel, callback) { - if (!this._isPresent) { - callback.notifyError(SE.ERROR_NOTPRESENT); - return; - } - - let icc = iccService.getIccByServiceId(PREFERRED_UICC_CLIENTID); - icc.iccCloseChannel(channel, { - notifyCloseChannelSuccess: function() { - debug("closeChannel successfully closed the channel # : " + channel); - if (callback) { - callback.notifyCloseChannelSuccess(); - } - }, - - notifyError: function(reason) { - debug("Failed to close the channel # : " + channel + - ", Rejected with Reason : " + reason); - if (callback) { - callback.notifyError(reason); - } - } - }); - }, - - registerListener: function(listener) { - if (this._SEListeners.indexOf(listener) !== -1) { - throw Cr.NS_ERROR_UNEXPECTED; - } - - this._SEListeners.push(listener); - // immediately notify listener about the current state - listener.notifySEPresenceChanged(SE.TYPE_UICC, this._isPresent); - }, - - unregisterListener: function(listener) { - let idx = this._SEListeners.indexOf(listener); - if (idx !== -1) { - this._SEListeners.splice(idx, 1); - } - }, - - /** - * nsIIccListener interface methods. - */ - notifyStkCommand: function() {}, - - notifyStkSessionEnd: function() {}, - - notifyIccInfoChanged: function() {}, - - notifyCardStateChanged: function() { - debug("Card state changed, updating UICC presence."); - this._updatePresenceState(); - }, - - /** - * nsIObserver interface methods. - */ - - observe: function(subject, topic, data) { - if (topic === NS_XPCOM_SHUTDOWN_OBSERVER_ID) { - this._shutdown(); - } - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([UiccConnector]); diff --git a/dom/secureelement/gonk/UiccConnector.manifest b/dom/secureelement/gonk/UiccConnector.manifest deleted file mode 100644 index 5ac8b3b7b..000000000 --- a/dom/secureelement/gonk/UiccConnector.manifest +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# 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. - -# UiccConnector -component {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4} UiccConnector.js -contract @mozilla.org/secureelement/connector/uicc;1 {8e040e5d-c8c3-4c1b-ac82-c00d25d8c4a4} diff --git a/dom/secureelement/gonk/gp_consts.js b/dom/secureelement/gonk/gp_consts.js deleted file mode 100644 index 7c3bc7165..000000000 --- a/dom/secureelement/gonk/gp_consts.js +++ /dev/null @@ -1,62 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -/* Object Directory File (ODF) is an elementary file which contain - pointers to other EFs. It is specified in PKCS#15 section 6.7. */ -this.ODF_DF = [0x50, 0x31]; - -/* ISO 7816-4: secure messaging */ -this.CLA_SM = 0x00; - -/* ISO 7816-4, 5.4.1 table 11 */ -this.INS_SF = 0xA4; // select file -this.INS_GR = 0xC0; // get response -this.INS_RB = 0xB0; // read binary - -/* ISO 7816-4: select file, see 6.11.3, table 58 & 59 */ -this.P1_SF_DF = 0x00; // select DF -this.P2_SF_FCP = 0x04; // return FCP - -/* ISO 7816-4: read binary, 6.1.3. P1 and P2 describe offset of the first byte - to be read. We always read the whole files at the moment. */ -this.P1_RB = 0x00; -this.P2_RB = 0x00; - -/* ISO 7816-4: get response, 7.1.3 table 74, P1-P2 '0000' (other values RFU) */ -this.P1_GR = 0x00; -this.P2_GR = 0x00; - -/* ISO 7816-4: 5.1.5 File Control Information, Table 1. For FCP and FMD. */ -this.TAG_PROPRIETARY = 0x00; -this.TAG_NON_TLV = 0x53; -this.TAG_BER_TLV = 0x73; - -/* ASN.1 tags */ -this.TAG_SEQUENCE = 0x30; -this.TAG_OCTETSTRING = 0x04; -this.TAG_OID = 0x06; // Object Identifier - -/* ISO 7816-4: 5.1.5 File Control Information, Templates. */ -this.TAG_FCP = 0x62; // File control parameters template -this.TAG_FMD = 0x64; // File management data template -this.TAG_FCI = 0x6F; // File control information template - -/* EF_DIR tags */ -this.TAG_APPLTEMPLATE = 0x61; -this.TAG_APPLIDENTIFIER = 0x4F; -this.TAG_APPLLABEL = 0x50; -this.TAG_APPLPATH = 0x51; - -this.TAG_GPD_ALL = 0x82; // EF-ACRules - GPD spec. "all applets" - -/* Generic TLVs that are parsed */ -this.TAG_GPD_AID = 0xA0; // AID in the EF-ACRules - GPD spec, "one applet" -this.TAG_EXTERNALDO = 0xA1; // External data objects - PKCS#15 -this.TAG_INDIRECT = 0xA5; // Indirect value. -this.TAG_EF_ODF = 0xA7; // Elemenetary File Object Directory File - -// Allow this file to be imported via Components.utils.import(). -this.EXPORTED_SYMBOLS = Object.keys(this); diff --git a/dom/secureelement/gonk/nsIAccessControlEnforcer.idl b/dom/secureelement/gonk/nsIAccessControlEnforcer.idl deleted file mode 100644 index 7ad1a97f6..000000000 --- a/dom/secureelement/gonk/nsIAccessControlEnforcer.idl +++ /dev/null @@ -1,32 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -#include "nsISupports.idl" - -interface nsIVariant; - -[scriptable, uuid(4994a960-26d9-4d71-82dd-4505bd97bf2a)] -interface nsIAccessControlEnforcer : nsISupports -{ - /** - * Determines whether application identified by its ID should be allowed - * to access Secure Element's applet identified by its AID. Decision - * is made according to the GPD specification. - * - * @param localId - * ID of an application accessing SE - * @param seType - * Type of the SE. - * @param aid - * AID of a SE applet - * @return Promise which is resolved to true if access should be allowed, - * false otherwise, and rejected if the application contains - * no developer certificate. - */ - jsval isAccessAllowed(in unsigned long localId, - in DOMString seType, - in DOMString aid); -}; diff --git a/dom/secureelement/gonk/nsIAccessRulesManager.idl b/dom/secureelement/gonk/nsIAccessRulesManager.idl deleted file mode 100644 index 173f57c90..000000000 --- a/dom/secureelement/gonk/nsIAccessRulesManager.idl +++ /dev/null @@ -1,50 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* Copyright © 2015, Deutsche Telekom, Inc. */ - -#include "nsISupports.idl" - -[scriptable, uuid(7baedd2a-3189-4b03-b2a3-34016043b5e2)] -interface nsIAccessRulesManager : nsISupports -{ - /* Wildcard: rule allows all applications to access an SE applet */ - const unsigned short ALLOW_ALL = 1; - /* Wildcard: rule denies all applications to access an SE applet */ - const unsigned short DENY_ALL = 2; - /* Wildcard: rule allows application(s) access to all SE applets */ - const unsigned short ALL_APPLET = 3; - - /** - * Initiates Access Rules Manager, this should perform the initial - * reading of rules from access rule source - * @return Promise which is resolved if init is successful or rejected - * otherwise - */ - jsval init(); - - /** - * Retrieves all access rules. - * - * Rules are stored in an array. Each rule contains the following properties: - * - applet - describes an SE applet referenced by this rule. Might equal - * to an applet AID (as a byte array), or to a wildcard "all" - * meaning all applets. - * - application - describes an application referenced by this rule. Might - * be an array of developer certificate hashes (each as - * a byte array) in which case it lists all applications - * allowed access. Alternatively, might equal to wildcard - * "allowed-all" or "denied-all". - * - * Example rule format: - * [{ applet: ALL_APPLET, - * application: [[0x01, 0x02, ..., 0x20], - * [0x20, 0x19, ...., 0x01]], - * { applet: [0x00, 0x01, ..., 0x05], - * application: ALLOW_ALL}}] - * - * @return Promise which resolves with Array containing parsed access rules - */ - jsval getAccessRules(); -}; diff --git a/dom/secureelement/gonk/nsISecureElementConnector.idl b/dom/secureelement/gonk/nsISecureElementConnector.idl deleted file mode 100644 index 92cc1eb2b..000000000 --- a/dom/secureelement/gonk/nsISecureElementConnector.idl +++ /dev/null @@ -1,124 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(1ff3f35a-1b6f-4e65-a89e-a363b8604cd7)] -interface nsISEChannelCallback : nsISupports -{ - /** - * Callback function to notify on successfully opening a logical channel. - * - * @param channel - * The Channel Number/Handle that is successfully opened. - * @param openResponse - * Response from SE for OpenChannel operation. - */ - void notifyOpenChannelSuccess(in long channel, in DOMString openResponse); - - /** - * Callback function to notify on successfully closing the logical channel. - * - */ - void notifyCloseChannelSuccess(); - - /** - * Callback function to notify the status of 'seExchangeAPDU' command. - * - * @param sw1 - * Response's First Status Byte - * @param sw2 - * Response's Second Status Byte - * @param data - * Response's data - */ - void notifyExchangeAPDUResponse(in octet sw1, - in octet sw2, - in DOMString data); - - /** - * Callback function to notify error - * - * @param error - * Error describing the reason for failure. - */ - void notifyError(in DOMString error); -}; - -[scriptable, uuid(417f59ee-f582-45b9-9a4e-e9dcefecb4f7)] -interface nsISEListener : nsISupports -{ - void notifySEPresenceChanged(in DOMString seType, in boolean isPresent); -}; - -[scriptable, uuid(3cef313a-1d01-432d-9cd2-6610a80911f3)] -interface nsISecureElementConnector : nsISupports -{ - /** - * Open a logical communication channel with the specific secure element type - * - * @param aid - * Application Identifier of the Card Applet on the secure element. - * @param callback - * callback to notify the result of the operation. - */ - void openChannel(in DOMString aid, - in nsISEChannelCallback callback); - - /** - * Exchanges APDU channel with the specific secure element type - * - * @param channel - * Channel on which C-APDU to be transmitted. - * @param cla - Class Byte. - * @param ins - Instruction Byte - * @param p1 - Reference parameter first byte - * @param p2 - Reference parameter second byte - * Refer to 3G TS 31.101 , 10.2 'Command APDU Structure' for all the cases. - * @param data - Sequence of C-APDU data octets - * @param le [optional] - * le is the length of expected response. If the response is not expected, - it should be explicitly set to -1. - * @param callback - * callback to notify the result of the operation. - */ - void exchangeAPDU(in long channel, - in octet cla, - in octet ins, - in octet p1, - in octet p2, - in DOMString data, - in short le, - in nsISEChannelCallback callback); - - /** - * Closes the logical communication channel to the specific secure element type - * - * @param channel - * Channel to be closed. - * @param callback - * callback to notify the result of the operation. - */ - void closeChannel(in long channel, - in nsISEChannelCallback callback); - - /** - * Register a Secure Element listener - * - * @param listener - */ - void registerListener(in nsISEListener listener); - - /** - * Unregister a Secure Element listener - * - * @param listener - */ - void unregisterListener(in nsISEListener listener); -}; diff --git a/dom/secureelement/gonk/se_consts.js b/dom/secureelement/gonk/se_consts.js deleted file mode 100644 index 13489b7ae..000000000 --- a/dom/secureelement/gonk/se_consts.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -/* Copyright © 2014, Deutsche Telekom, Inc. */ - -// Set to true to debug SecureElement (SE) stack -this.DEBUG_ALL = false; - -// Set individually to debug specific layers -this.DEBUG_CONNECTOR = DEBUG_ALL || false; -this.DEBUG_ACE = DEBUG_ALL || false ; -this.DEBUG_SE = DEBUG_ALL || false ; - -// Maximun logical channels per session. -// For 'uicc' SE type this value is 3, as opening a basic channel' : 0 -// is not allowed for security reasons. In such scenarios, possible -// supplementary logical channels available are : [1, 2, or 3]. -// However,Other SE types may support upto max 4 (including '0'). -this.MAX_CHANNELS_ALLOWED_PER_SESSION = 4; - -this.BASIC_CHANNEL = 0; - -// According GPCardSpec 2.2 -this.MAX_APDU_LEN = 255; // including APDU header - -// CLA (1 byte) + INS (1 byte) + P1 (1 byte) + P2 (1 byte) -this.APDU_HEADER_LEN = 4; - -this.LOGICAL_CHANNEL_NUMBER_LIMIT = 4; -this.SUPPLEMENTARY_LOGICAL_CHANNEL_NUMBER_LIMIT = 20; - -this.MIN_AID_LEN = 5; -this.MAX_AID_LEN = 16; - -this.CLA_GET_RESPONSE = 0x00; - -this.INS_SELECT = 0xA4; -this.INS_MANAGE_CHANNEL = 0x70; -this.INS_GET_RESPONSE = 0xC0; - -// Match the following errors with SecureElement.webidl's SEError enum values -this.ERROR_NONE = ""; -this.ERROR_SECURITY = "SESecurityError"; -this.ERROR_IO = "SEIoError"; -this.ERROR_BADSTATE = "SEBadStateError"; -this.ERROR_INVALIDCHANNEL = "SEInvalidChannelError"; -this.ERROR_INVALIDAPPLICATION = "SEInvalidApplicationError"; -this.ERROR_GENERIC = "SEGenericError"; -this.ERROR_NOTPRESENT = "SENotPresentError"; -this.ERROR_ILLEGALPARAMETER = "SEIllegalParameterError"; - -this.TYPE_UICC = "uicc"; -this.TYPE_ESE = "eSE"; - -// Allow this file to be imported via Components.utils.import(). -this.EXPORTED_SYMBOLS = Object.keys(this); diff --git a/dom/secureelement/moz.build b/dom/secureelement/moz.build index a2c87b014..973000512 100644 --- a/dom/secureelement/moz.build +++ b/dom/secureelement/moz.build @@ -11,30 +11,6 @@ if CONFIG['MOZ_SECUREELEMENT']: 'DOMSecureElement.manifest', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['MOZ_SECUREELEMENT']: - EXTRA_COMPONENTS += [ - 'gonk/ACEService.js', - 'gonk/ACEService.manifest', - 'gonk/GPAccessRulesManager.js', - 'gonk/GPAccessRulesManager.manifest', - 'gonk/SecureElement.js', - 'gonk/SecureElement.manifest', - ] - XPIDL_MODULE = 'dom_secureelement' - XPIDL_SOURCES += [ - 'gonk/nsIAccessControlEnforcer.idl', - 'gonk/nsIAccessRulesManager.idl', - 'gonk/nsISecureElementConnector.idl', - ] - EXTRA_JS_MODULES += [ - 'gonk/gp_consts.js', - 'gonk/se_consts.js', - 'SEUtils.jsm' - ] - XPCSHELL_TESTS_MANIFESTS += [ - 'tests/unit/xpcshell.ini' - ] - include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' diff --git a/dom/system/gonk/AudioChannelManager.cpp b/dom/system/gonk/AudioChannelManager.cpp deleted file mode 100644 index 977715a29..000000000 --- a/dom/system/gonk/AudioChannelManager.cpp +++ /dev/null @@ -1,181 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIDocument.h" -#include "nsIDOMClassInfo.h" -#include "nsIDOMEvent.h" -#include "nsIDOMEventListener.h" -#include "nsPIDOMWindow.h" -#include "nsIDocShell.h" -#include "nsIPermissionManager.h" -#include "nsIInterfaceRequestorUtils.h" -#include "AudioChannelManager.h" -#include "mozilla/dom/AudioChannelManagerBinding.h" -#include "mozilla/dom/nsBrowserElement.h" -#include "mozilla/Services.h" - -namespace mozilla { -namespace dom { -namespace system { - -NS_IMPL_QUERY_INTERFACE_INHERITED(AudioChannelManager, DOMEventTargetHelper, - nsIDOMEventListener) -NS_IMPL_ADDREF_INHERITED(AudioChannelManager, DOMEventTargetHelper) -NS_IMPL_RELEASE_INHERITED(AudioChannelManager, DOMEventTargetHelper) - -AudioChannelManager::AudioChannelManager() - : mVolumeChannel(-1) -{ - hal::RegisterSwitchObserver(hal::SWITCH_HEADPHONES, this); -} - -AudioChannelManager::~AudioChannelManager() -{ - hal::UnregisterSwitchObserver(hal::SWITCH_HEADPHONES, this); - - nsCOMPtr target = do_QueryInterface(GetOwner()); - NS_ENSURE_TRUE_VOID(target); - - target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, - /* useCapture = */ true); -} - -void -AudioChannelManager::Init(nsPIDOMWindowInner* aWindow) -{ - BindToOwner(aWindow); - - nsCOMPtr target = do_QueryInterface(GetOwner()); - NS_ENSURE_TRUE_VOID(target); - - target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), - this, - /* useCapture = */ true, - /* wantsUntrusted = */ false); -} - -JSObject* -AudioChannelManager::WrapObject(JSContext* aCx, JS::Handle aGivenProto) -{ - return AudioChannelManagerBinding::Wrap(aCx, this, aGivenProto); -} - -void -AudioChannelManager::Notify(const hal::SwitchEvent& aEvent) -{ - mState = Some(aEvent.status()); - - DispatchTrustedEvent(NS_LITERAL_STRING("headphoneschange")); -} - -bool -AudioChannelManager::SetVolumeControlChannel(const nsAString& aChannel) -{ - if (aChannel.EqualsASCII("publicnotification")) { - return false; - } - - AudioChannel newChannel = AudioChannelService::GetAudioChannel(aChannel); - - // Only normal channel doesn't need permission. - if (newChannel != AudioChannel::Normal) { - nsCOMPtr permissionManager = - services::GetPermissionManager(); - if (!permissionManager) { - return false; - } - uint32_t perm = nsIPermissionManager::UNKNOWN_ACTION; - permissionManager->TestPermissionFromWindow(GetOwner(), - nsCString(NS_LITERAL_CSTRING("audio-channel-") + - NS_ConvertUTF16toUTF8(aChannel)).get(), &perm); - if (perm != nsIPermissionManager::ALLOW_ACTION) { - return false; - } - } - - if (mVolumeChannel == (int32_t)newChannel) { - return true; - } - - mVolumeChannel = (int32_t)newChannel; - - NotifyVolumeControlChannelChanged(); - return true; -} - -bool -AudioChannelManager::GetVolumeControlChannel(nsAString & aChannel) -{ - if (mVolumeChannel >= 0) { - AudioChannelService::GetAudioChannelString( - static_cast(mVolumeChannel), - aChannel); - } else { - aChannel.AssignASCII(""); - } - - return true; -} - -void -AudioChannelManager::NotifyVolumeControlChannelChanged() -{ - nsCOMPtr docshell = do_GetInterface(GetOwner()); - NS_ENSURE_TRUE_VOID(docshell); - - bool isActive = false; - docshell->GetIsActive(&isActive); - - RefPtr service = AudioChannelService::GetOrCreate(); - if (!service) { - return; - } - - if (isActive) { - service->SetDefaultVolumeControlChannel(mVolumeChannel, isActive); - } else { - service->SetDefaultVolumeControlChannel(-1, isActive); - } -} - -NS_IMETHODIMP -AudioChannelManager::HandleEvent(nsIDOMEvent* aEvent) -{ - nsAutoString type; - aEvent->GetType(type); - - if (type.EqualsLiteral("visibilitychange")) { - NotifyVolumeControlChannelChanged(); - } - return NS_OK; -} - -void -AudioChannelManager::GetAllowedAudioChannels( - nsTArray>& aAudioChannels, - ErrorResult& aRv) -{ - MOZ_ASSERT(aAudioChannels.IsEmpty()); - - // Only main process is supported. - if (XRE_GetProcessType() != GeckoProcessType_Default) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - nsCOMPtr window = GetOwner(); - if (NS_WARN_IF(!window)) { - aRv.Throw(NS_ERROR_FAILURE); - return; - } - - nsBrowserElement::GenerateAllowedAudioChannels(window, nullptr, nullptr, - aAudioChannels, aRv); - NS_WARNING_ASSERTION(!aRv.Failed(), "GenerateAllowedAudioChannels failed"); -} - -} // namespace system -} // namespace dom -} // namespace mozilla diff --git a/dom/system/gonk/AudioChannelManager.h b/dom/system/gonk/AudioChannelManager.h deleted file mode 100644 index a460651e7..000000000 --- a/dom/system/gonk/AudioChannelManager.h +++ /dev/null @@ -1,87 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_dom_system_AudioChannelManager_h -#define mozilla_dom_system_AudioChannelManager_h - -#include "mozilla/dom/BrowserElementAudioChannel.h" -#include "mozilla/DOMEventTargetHelper.h" -#include "mozilla/Hal.h" -#include "mozilla/HalTypes.h" -#include "mozilla/Maybe.h" -#include "AudioChannelService.h" - -namespace mozilla { -namespace hal { -class SwitchEvent; -typedef Observer SwitchObserver; -} // namespace hal - -namespace dom { -namespace system { - -class AudioChannelManager final - : public DOMEventTargetHelper - , public hal::SwitchObserver - , public nsIDOMEventListener -{ -public: - AudioChannelManager(); - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIDOMEVENTLISTENER - - void Notify(const hal::SwitchEvent& aEvent); - - void Init(nsPIDOMWindowInner* aWindow); - - /** - * WebIDL Interface - */ - - nsPIDOMWindowInner* GetParentObject() const - { - return GetOwner(); - } - - virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - - bool Headphones() - { - // Bug 929139 - Remove the assert check for SWITCH_STATE_UNKNOWN. - // If any devices (ex: emulator) didn't have the corresponding sys node for - // headset switch state then GonkSwitch will report the unknown state. - // So it is possible to get unknown state here. - if (mState.isNothing()) { - mState = Some(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES)); - } - return mState.value() != hal::SWITCH_STATE_OFF && - mState.value() != hal::SWITCH_STATE_UNKNOWN; - } - - bool SetVolumeControlChannel(const nsAString& aChannel); - - bool GetVolumeControlChannel(nsAString& aChannel); - - IMPL_EVENT_HANDLER(headphoneschange) - - void GetAllowedAudioChannels( - nsTArray>& aAudioChannels, - mozilla::ErrorResult& aRv); - -protected: - virtual ~AudioChannelManager(); - -private: - void NotifyVolumeControlChannelChanged(); - - Maybe mState; - int32_t mVolumeChannel; -}; - -} // namespace system -} // namespace dom -} // namespace mozilla - -#endif // mozilla_dom_system_AudioChannelManager_h diff --git a/dom/system/gonk/AudioManager.cpp b/dom/system/gonk/AudioManager.cpp deleted file mode 100644 index 88dff13f7..000000000 --- a/dom/system/gonk/AudioManager.cpp +++ /dev/null @@ -1,1412 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include -#include -#include - -#include "AudioChannelService.h" -#include "AudioManager.h" - -#include "nsIObserverService.h" -#include "nsISettingsService.h" -#include "nsPrintfCString.h" - -#include "mozilla/Hal.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/MozPromise.h" -#include "mozilla/dom/ScriptSettings.h" -#include "base/message_loop.h" - -#include "BluetoothCommon.h" -#include "BluetoothHfpManagerBase.h" - -#include "nsJSUtils.h" -#include "nsThreadUtils.h" -#include "nsServiceManagerUtils.h" -#include "nsComponentManagerUtils.h" -#include "nsContentUtils.h" -#include "nsXULAppAPI.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -using namespace mozilla::dom; -using namespace mozilla::dom::gonk; -using namespace android; -using namespace mozilla; -using namespace mozilla::dom::bluetooth; - -#undef LOG -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AudioManager" , ## args) - -#define HEADPHONES_STATUS_HEADSET u"headset" -#define HEADPHONES_STATUS_HEADPHONE u"headphone" -#define HEADPHONES_STATUS_OFF u"off" -#define HEADPHONES_STATUS_UNKNOWN u"unknown" -#define HEADPHONES_STATUS_CHANGED "headphones-status-changed" -#define MOZ_SETTINGS_CHANGE_ID "mozsettings-changed" -#define AUDIO_CHANNEL_PROCESS_CHANGED "audio-channel-process-changed" -#define AUDIO_POLICY_SERVICE_NAME "media.audio_policy" -#define SETTINGS_SERVICE "@mozilla.org/settingsService;1" - -// Refer AudioService.java from Android -static const uint32_t sMaxStreamVolumeTbl[AUDIO_STREAM_CNT] = { - 5, // voice call - 15, // system - 15, // ring - 15, // music - 15, // alarm - 15, // notification - 15, // BT SCO - 15, // enforced audible - 15, // DTMF - 15, // TTS -#if ANDROID_VERSION < 19 - 15, // FM -#endif -}; - -static const uint32_t sDefaultStreamVolumeTbl[AUDIO_STREAM_CNT] = { - 3, // voice call - 8, // system - 8, // ring - 8, // music - 8, // alarm - 8, // notification - 8, // BT SCO - 15, // enforced audible // XXX Handle as fixed maximum audio setting - 8, // DTMF - 8, // TTS -#if ANDROID_VERSION < 19 - 8, // FM -#endif -}; - -static const int32_t sStreamVolumeAliasTbl[AUDIO_STREAM_CNT] = { - AUDIO_STREAM_VOICE_CALL, // voice call - AUDIO_STREAM_NOTIFICATION, // system - AUDIO_STREAM_NOTIFICATION, // ring - AUDIO_STREAM_MUSIC, // music - AUDIO_STREAM_ALARM, // alarm - AUDIO_STREAM_NOTIFICATION, // notification - AUDIO_STREAM_BLUETOOTH_SCO, // BT SCO - AUDIO_STREAM_ENFORCED_AUDIBLE,// enforced audible - AUDIO_STREAM_DTMF, // DTMF - AUDIO_STREAM_TTS, // TTS -#if ANDROID_VERSION < 19 - AUDIO_STREAM_MUSIC, // FM -#endif -}; - -static const uint32_t sChannelStreamTbl[NUMBER_OF_AUDIO_CHANNELS] = { - AUDIO_STREAM_MUSIC, // AudioChannel::Normal - AUDIO_STREAM_MUSIC, // AudioChannel::Content - AUDIO_STREAM_NOTIFICATION, // AudioChannel::Notification - AUDIO_STREAM_ALARM, // AudioChannel::Alarm - AUDIO_STREAM_VOICE_CALL, // AudioChannel::Telephony - AUDIO_STREAM_RING, // AudioChannel::Ringer - AUDIO_STREAM_ENFORCED_AUDIBLE,// AudioChannel::Publicnotification - AUDIO_STREAM_SYSTEM, // AudioChannel::System -}; - - -struct AudioDeviceInfo { - /** The string the value maps to */ - const char* tag; - /** The enum value that maps to this string */ - uint32_t value; -}; - -// Mappings audio output devices to strings. -static const AudioDeviceInfo kAudioDeviceInfos[] = { - { "earpiece", AUDIO_DEVICE_OUT_EARPIECE }, - { "speaker", AUDIO_DEVICE_OUT_SPEAKER }, - { "wired_headset", AUDIO_DEVICE_OUT_WIRED_HEADSET }, - { "wired_headphone", AUDIO_DEVICE_OUT_WIRED_HEADPHONE }, - { "bt_scoheadset", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET }, - { "bt_a2dp", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP }, -}; - -static const int kBtSampleRate = 8000; - -typedef MozPromise VolumeInitPromise; - -namespace mozilla { -namespace dom { -namespace gonk { - -/** - * We have five sound volume settings from UX spec, - * You can see more informations in Bug1068219. - * (1) Media : music, video, FM ... - * (2) Notification : ringer, notification ... - * (3) Alarm : alarm - * (4) Telephony : GSM call, WebRTC call - * (5) Bluetooth SCO : SCO call - **/ -struct VolumeData { - const char* mChannelName; - int32_t mStreamType; -}; - -static const VolumeData gVolumeData[] = { - {"audio.volume.content", AUDIO_STREAM_MUSIC}, - {"audio.volume.notification", AUDIO_STREAM_NOTIFICATION}, - {"audio.volume.alarm", AUDIO_STREAM_ALARM}, - {"audio.volume.telephony", AUDIO_STREAM_VOICE_CALL}, - {"audio.volume.bt_sco", AUDIO_STREAM_BLUETOOTH_SCO} -}; - -class RunnableCallTask : public Runnable -{ -public: - explicit RunnableCallTask(nsIRunnable* aRunnable) - : mRunnable(aRunnable) {} - - NS_IMETHOD Run() override - { - return mRunnable->Run(); - } -protected: - nsCOMPtr mRunnable; -}; - -nsCOMPtr -GetSettingServiceLock() -{ - nsresult rv; - nsCOMPtr service = do_GetService(SETTINGS_SERVICE, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - - nsCOMPtr lock; - rv = service->CreateLock(nullptr, getter_AddRefs(lock)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return nullptr; - } - return lock.forget(); -} - -#if ANDROID_VERSION >= 21 -class GonkAudioPortCallback : public AudioSystem::AudioPortCallback -{ -public: - virtual void onAudioPortListUpdate() - { - nsCOMPtr runnable = - NS_NewRunnableFunction([]() { - MOZ_ASSERT(NS_IsMainThread()); - RefPtr audioManager = AudioManager::GetInstance(); - NS_ENSURE_TRUE(audioManager.get(), ); - audioManager->UpdateCachedActiveDevicesForStreams(); - audioManager->MaybeUpdateVolumeSettingToDatabase(); - }); - NS_DispatchToMainThread(runnable); - } - virtual void onAudioPatchListUpdate() { } - virtual void onServiceDied() { } -}; -#endif - -void -AudioManager::HandleAudioFlingerDied() -{ - //Disable volume change notification - mIsVolumeInited = false; - - uint32_t attempt; - for (attempt = 0; attempt < 50; attempt++) { - if (defaultServiceManager()->checkService(String16(AUDIO_POLICY_SERVICE_NAME)) != 0) { - break; - } - LOG("AudioPolicyService is dead! attempt=%d", attempt); - usleep(1000 * 200); - } - - MOZ_RELEASE_ASSERT(attempt < 50); - - // Indicate to audio HAL that we start the reconfiguration phase after a media - // server crash - AudioSystem::setParameters(0, String8("restarting=true")); - - // Restore device connection states - SetAllDeviceConnectionStates(); - - // Restore call state -#if ANDROID_VERSION < 17 - AudioSystem::setPhoneState(mPhoneState); -#else - AudioSystem::setPhoneState(static_cast(mPhoneState)); -#endif - - // Restore master volume - AudioSystem::setMasterVolume(1.0); - - // Restore stream volumes - for (uint32_t streamType = 0; streamType < AUDIO_STREAM_CNT; ++streamType) { - mStreamStates[streamType]->InitStreamVolume(); - mStreamStates[streamType]->RestoreVolumeIndexToAllDevices(); - } - - // Indicate the end of reconfiguration phase to audio HAL - AudioSystem::setParameters(0, String8("restarting=true")); - - // Enable volume change notification - mIsVolumeInited = true; - mAudioOutDevicesUpdated = 0; - MaybeUpdateVolumeSettingToDatabase(true); -} - -class VolumeInitCallback final : public nsISettingsServiceCallback -{ -public: - NS_DECL_ISUPPORTS - - VolumeInitCallback() - : mInitCounter(0) - { - mPromise = mPromiseHolder.Ensure(__func__); - } - - RefPtr GetPromise() const - { - return mPromise; - } - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle aResult) - { - RefPtr audioManager = AudioManager::GetInstance(); - MOZ_ASSERT(audioManager); - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - NS_ConvertASCIItoUTF16 volumeType(gVolumeData[idx].mChannelName); - if (StringBeginsWith(aName, volumeType)) { - uint32_t device = GetDeviceFromSettingName(aName); - MOZ_ASSERT(device != AUDIO_DEVICE_NONE); - if (aResult.isInt32()) { - int32_t stream = gVolumeData[idx].mStreamType; - uint32_t volIndex = aResult.toInt32(); - nsresult rv = audioManager->ValidateVolumeIndex(stream, volIndex); - if (NS_WARN_IF(NS_FAILED(rv))) { - mPromiseHolder.Reject("Error : invalid volume index.", __func__); - return rv; - } - audioManager->SetStreamVolumeForDevice(stream, volIndex, device); - } - - if (++mInitCounter == MOZ_ARRAY_LENGTH(kAudioDeviceInfos) * MOZ_ARRAY_LENGTH(gVolumeData)) { - mPromiseHolder.Resolve(true, __func__); - } - return NS_OK; - } - } - mPromiseHolder.Reject("Error : unexpected audio init event.", __func__); - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) - { - mPromiseHolder.Reject(NS_ConvertUTF16toUTF8(aName).get(), __func__); - return NS_OK; - } - -protected: - ~VolumeInitCallback() {} - - uint32_t GetDeviceFromSettingName(const nsAString& aName) const - { - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx) { - NS_ConvertASCIItoUTF16 device(kAudioDeviceInfos[idx].tag); - if (StringEndsWith(aName, device)) { - return kAudioDeviceInfos[idx].value; - } - } - return AUDIO_DEVICE_NONE; - } - - RefPtr mPromise; - MozPromiseHolder mPromiseHolder; - uint32_t mInitCounter; -}; - -NS_IMPL_ISUPPORTS(VolumeInitCallback, nsISettingsServiceCallback) - -static void -BinderDeadCallback(status_t aErr) -{ - if (aErr != DEAD_OBJECT) { - return; - } - - nsCOMPtr runnable = - NS_NewRunnableFunction([]() { - MOZ_ASSERT(NS_IsMainThread()); - RefPtr audioManager = AudioManager::GetInstance(); - NS_ENSURE_TRUE(audioManager.get(), ); - audioManager->HandleAudioFlingerDied(); - }); - - NS_DispatchToMainThread(runnable); -} - -bool -AudioManager::IsFmOutConnected() -{ - return mConnectedDevices.Get(AUDIO_DEVICE_OUT_FM, nullptr); -} - -NS_IMPL_ISUPPORTS(AudioManager, nsIAudioManager, nsIObserver) - -void -AudioManager::AudioOutDeviceUpdated(uint32_t aDevice) -{ - MOZ_ASSERT(audio_is_output_device(aDevice)); - mAudioOutDevicesUpdated |= aDevice; -} - -void -AudioManager::UpdateHeadsetConnectionState(hal::SwitchState aState) -{ - bool headphoneConnected = mConnectedDevices.Get(AUDIO_DEVICE_OUT_WIRED_HEADPHONE, - nullptr); - bool headsetConnected = mConnectedDevices.Get(AUDIO_DEVICE_OUT_WIRED_HEADSET, - nullptr); - if (aState == hal::SWITCH_STATE_HEADSET) { - UpdateDeviceConnectionState(true, - AUDIO_DEVICE_OUT_WIRED_HEADSET, - NS_LITERAL_CSTRING("")); - } else if (aState == hal::SWITCH_STATE_HEADPHONE) { - UpdateDeviceConnectionState(true, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE, - NS_LITERAL_CSTRING("")); - } else if (aState == hal::SWITCH_STATE_OFF) { - if (headsetConnected) { - UpdateDeviceConnectionState(false, - AUDIO_DEVICE_OUT_WIRED_HEADSET, - NS_LITERAL_CSTRING("")); - } - if (headphoneConnected) { - UpdateDeviceConnectionState(false, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE, - NS_LITERAL_CSTRING("")); - } - } -} - -void -AudioManager::UpdateDeviceConnectionState(bool aIsConnected, uint32_t aDevice, const nsCString& aDeviceName) -{ -#if ANDROID_VERSION >= 15 - bool isConnected = mConnectedDevices.Get(aDevice, nullptr); - if (isConnected && !aIsConnected) { - AudioSystem::setDeviceConnectionState(static_cast(aDevice), - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - aDeviceName.get()); - mConnectedDevices.Remove(aDevice); - } else if(!isConnected && aIsConnected) { - AudioSystem::setDeviceConnectionState(static_cast(aDevice), - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - aDeviceName.get()); - mConnectedDevices.Put(aDevice, aDeviceName); - } -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(); -#endif -#else - NS_NOTREACHED("Doesn't support audio routing on GB version"); -#endif -} - -void -AudioManager::SetAllDeviceConnectionStates() -{ - for (auto iter = mConnectedDevices.Iter(); !iter.Done(); iter.Next()) { - const uint32_t& device = iter.Key(); - nsCString& deviceAddress = iter.Data(); - AudioSystem::setDeviceConnectionState(static_cast(device), - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - deviceAddress.get()); - } -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(true); -#endif -} - -void -AudioManager::HandleBluetoothStatusChanged(nsISupports* aSubject, - const char* aTopic, - const nsCString aAddress) -{ -#ifdef MOZ_B2G_BT - bool isConnected = false; - if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { - BluetoothHfpManagerBase* hfp = - static_cast(aSubject); - isConnected = hfp->IsScoConnected(); - } else { - BluetoothProfileManagerBase* profile = - static_cast(aSubject); - isConnected = profile->IsConnected(); - } - - if (!strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID)) { - if (isConnected) { - String8 cmd; - cmd.appendFormat("bt_samplerate=%d", kBtSampleRate); - AudioSystem::setParameters(0, cmd); - SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_BT_SCO); - } else { - int32_t force; - GetForceForUse(nsIAudioManager::USE_COMMUNICATION, &force); - if (force == nsIAudioManager::FORCE_BT_SCO) { - SetForceForUse(nsIAudioManager::USE_COMMUNICATION, nsIAudioManager::FORCE_NONE); - } - } - } else if (!strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID)) { - if (!isConnected && mA2dpSwitchDone) { - RefPtr self = this; - nsCOMPtr runnable = - NS_NewRunnableFunction([self, isConnected, aAddress]() { - if (self->mA2dpSwitchDone) { - return; - } - self->UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, - aAddress); - - String8 cmd("bluetooth_enabled=false"); - AudioSystem::setParameters(0, cmd); - cmd.setTo("A2dpSuspended=true"); - AudioSystem::setParameters(0, cmd); - self->mA2dpSwitchDone = true; - }); - MessageLoop::current()->PostDelayedTask( - MakeAndAddRef(runnable), 1000); - - mA2dpSwitchDone = false; - } else { - UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, - aAddress); - String8 cmd("bluetooth_enabled=true"); - AudioSystem::setParameters(0, cmd); - cmd.setTo("A2dpSuspended=false"); - AudioSystem::setParameters(0, cmd); - mA2dpSwitchDone = true; -#if ANDROID_VERSION >= 17 - if (AudioSystem::getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) == AUDIO_POLICY_FORCE_NO_BT_A2DP) { - SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE); - } -#endif - } - mBluetoothA2dpEnabled = isConnected; - } else if (!strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID)) { - UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, - aAddress); - UpdateDeviceConnectionState(isConnected, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, - aAddress); - } else if (!strcmp(aTopic, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID)) { - String8 cmd; - BluetoothHfpManagerBase* hfp = - static_cast(aSubject); - if (hfp->IsNrecEnabled()) { - cmd.setTo("bt_headset_name=;bt_headset_nrec=on"); - AudioSystem::setParameters(0, cmd); - } else { - cmd.setTo("bt_headset_name=;bt_headset_nrec=off"); - AudioSystem::setParameters(0, cmd); - } - } -#endif -} - -void -AudioManager::HandleAudioChannelProcessChanged() -{ - // Note: If the user answers a VoIP call (e.g. WebRTC calls) during the - // telephony call (GSM/CDMA calls) the audio manager won't set the - // PHONE_STATE_IN_COMMUNICATION audio state. Once the telephony call finishes - // the RIL plumbing sets the PHONE_STATE_NORMAL audio state. This seems to be - // an issue for the VoIP call but it is not. Once the RIL plumbing sets the - // the PHONE_STATE_NORMAL audio state the AudioManager::mPhoneAudioAgent - // member will call the NotifyStoppedPlaying() method causing that this function will - // be called again and therefore the audio manager sets the - // PHONE_STATE_IN_COMMUNICATION audio state. - - if ((mPhoneState == PHONE_STATE_IN_CALL) || - (mPhoneState == PHONE_STATE_RINGTONE)) { - return; - } - - RefPtr service = AudioChannelService::GetOrCreate(); - bool telephonyChannelIsActive = service && service->TelephonyChannelIsActive(); - telephonyChannelIsActive ? SetPhoneState(PHONE_STATE_IN_COMMUNICATION) : - SetPhoneState(PHONE_STATE_NORMAL); -} - -nsresult -AudioManager::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if ((strcmp(aTopic, BLUETOOTH_SCO_STATUS_CHANGED_ID) == 0) || - (strcmp(aTopic, BLUETOOTH_HFP_STATUS_CHANGED_ID) == 0) || - (strcmp(aTopic, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID) == 0) || - (strcmp(aTopic, BLUETOOTH_A2DP_STATUS_CHANGED_ID) == 0)) { - nsCString address = NS_ConvertUTF16toUTF8(nsDependentString(aData)); - if (address.IsEmpty()) { - NS_WARNING(nsPrintfCString("Invalid address of %s", aTopic).get()); - return NS_ERROR_FAILURE; - } - - HandleBluetoothStatusChanged(aSubject, aTopic, address); - return NS_OK; - } - - else if (!strcmp(aTopic, AUDIO_CHANNEL_PROCESS_CHANGED)) { - HandleAudioChannelProcessChanged(); - return NS_OK; - } - - // To process the volume control on each volume categories according to - // change of settings - else if (!strcmp(aTopic, MOZ_SETTINGS_CHANGE_ID)) { - RootedDictionary setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return NS_OK; - } - if (!StringBeginsWith(setting.mKey, NS_LITERAL_STRING("audio.volume."))) { - return NS_OK; - } - if (!setting.mValue.isNumber()) { - return NS_OK; - } - - uint32_t volIndex = setting.mValue.toNumber(); - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - if (setting.mKey.EqualsASCII(gVolumeData[idx].mChannelName)) { - SetStreamVolumeIndex(gVolumeData[idx].mStreamType, volIndex); - return NS_OK; - } - } - } - - NS_WARNING("Unexpected topic in AudioManager"); - return NS_ERROR_FAILURE; -} - -static void -NotifyHeadphonesStatus(hal::SwitchState aState) -{ - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - if (aState == hal::SWITCH_STATE_HEADSET) { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_HEADSET); - } else if (aState == hal::SWITCH_STATE_HEADPHONE) { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_HEADPHONE); - } else if (aState == hal::SWITCH_STATE_OFF) { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_OFF); - } else { - obs->NotifyObservers(nullptr, HEADPHONES_STATUS_CHANGED, HEADPHONES_STATUS_UNKNOWN); - } - } -} - -class HeadphoneSwitchObserver : public hal::SwitchObserver -{ -public: - void Notify(const hal::SwitchEvent& aEvent) { - RefPtr audioManager = AudioManager::GetInstance(); - MOZ_ASSERT(audioManager); - audioManager->HandleHeadphoneSwitchEvent(aEvent); - } -}; - -void -AudioManager::HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent) -{ - NotifyHeadphonesStatus(aEvent.status()); - // When user pulled out the headset, a delay of routing here can avoid the leakage of audio from speaker. - if (aEvent.status() == hal::SWITCH_STATE_OFF && mSwitchDone) { - - RefPtr self = this; - nsCOMPtr runnable = - NS_NewRunnableFunction([self]() { - if (self->mSwitchDone) { - return; - } - self->UpdateHeadsetConnectionState(hal::SWITCH_STATE_OFF); - self->mSwitchDone = true; - }); - MessageLoop::current()->PostDelayedTask( - MakeAndAddRef(runnable), 1000); - mSwitchDone = false; - } else if (aEvent.status() != hal::SWITCH_STATE_OFF) { - UpdateHeadsetConnectionState(aEvent.status()); - mSwitchDone = true; - } - // Handle the coexistence of a2dp / headset device, latest one wins. -#if ANDROID_VERSION >= 17 - int32_t forceUse = 0; - GetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, &forceUse); - if (aEvent.status() != hal::SWITCH_STATE_OFF && mBluetoothA2dpEnabled) { - SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NO_BT_A2DP); - } else if (forceUse == AUDIO_POLICY_FORCE_NO_BT_A2DP) { - SetForceForUse(AUDIO_POLICY_FORCE_FOR_MEDIA, AUDIO_POLICY_FORCE_NONE); - } -#endif -} - -AudioManager::AudioManager() - : mPhoneState(PHONE_STATE_CURRENT) - , mIsVolumeInited(false) - , mAudioOutDevicesUpdated(0) - , mSwitchDone(true) -#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 - , mBluetoothA2dpEnabled(false) -#endif -#ifdef MOZ_B2G_BT - , mA2dpSwitchDone(true) -#endif - , mObserver(new HeadphoneSwitchObserver()) -{ - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx) { - mAudioDeviceTableIdMaps.Put(kAudioDeviceInfos[idx].value, idx); - } - - AudioSystem::setErrorCallback(BinderDeadCallback); -#if ANDROID_VERSION >= 21 - android::sp callback = new GonkAudioPortCallback(); - AudioSystem::setAudioPortCallback(callback); -#endif - - // Create VolumeStreamStates - for (uint32_t loop = 0; loop < AUDIO_STREAM_CNT; ++loop) { - VolumeStreamState* streamState = - new VolumeStreamState(*this, static_cast(loop)); - mStreamStates.AppendElement(streamState); - } - // Initialize stream volumes with default values - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - uint32_t volIndex = sDefaultStreamVolumeTbl[streamType]; - SetStreamVolumeForDevice(streamType, volIndex, AUDIO_DEVICE_OUT_DEFAULT); - } - UpdateCachedActiveDevicesForStreams(); - - RegisterSwitchObserver(hal::SWITCH_HEADPHONES, mObserver); - // Initialize headhone/heaset status - UpdateHeadsetConnectionState(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES)); - NotifyHeadphonesStatus(hal::GetCurrentSwitchState(hal::SWITCH_HEADPHONES)); - - // Get the initial volume index from settings DB during boot up. - InitVolumeFromDatabase(); - - // Gecko only control stream volume not master so set to default value - // directly. - AudioSystem::setMasterVolume(1.0); - - nsCOMPtr obs = services::GetObserverService(); - NS_ENSURE_TRUE_VOID(obs); - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_SCO_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth sco status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth a2dp status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth hfp status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID, false))) { - NS_WARNING("Failed to add bluetooth hfp NREC status changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, MOZ_SETTINGS_CHANGE_ID, false))) { - NS_WARNING("Failed to add mozsettings-changed observer!"); - } - if (NS_FAILED(obs->AddObserver(this, AUDIO_CHANNEL_PROCESS_CHANGED, false))) { - NS_WARNING("Failed to add audio-channel-process-changed observer!"); - } - -} - -AudioManager::~AudioManager() { - AudioSystem::setErrorCallback(nullptr); -#if ANDROID_VERSION >= 21 - AudioSystem::setAudioPortCallback(nullptr); -#endif - hal::UnregisterSwitchObserver(hal::SWITCH_HEADPHONES, mObserver); - - nsCOMPtr obs = services::GetObserverService(); - NS_ENSURE_TRUE_VOID(obs); - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_SCO_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth sco status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_A2DP_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth a2dp status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_HFP_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth hfp status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, BLUETOOTH_HFP_NREC_STATUS_CHANGED_ID))) { - NS_WARNING("Failed to remove bluetooth hfp NREC status changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, MOZ_SETTINGS_CHANGE_ID))) { - NS_WARNING("Failed to remove mozsettings-changed observer!"); - } - if (NS_FAILED(obs->RemoveObserver(this, AUDIO_CHANNEL_PROCESS_CHANGED))) { - NS_WARNING("Failed to remove audio-channel-process-changed!"); - } -} - -static StaticRefPtr sAudioManager; - -already_AddRefed -AudioManager::GetInstance() -{ - // Avoid createing AudioManager from content process. - if (!XRE_IsParentProcess()) { - MOZ_CRASH("Non-chrome processes should not get here."); - } - - // Avoid createing multiple AudioManager instance inside main process. - if (!sAudioManager) { - sAudioManager = new AudioManager(); - ClearOnShutdown(&sAudioManager); - } - - RefPtr audioMgr = sAudioManager.get(); - return audioMgr.forget(); -} - -NS_IMETHODIMP -AudioManager::GetMicrophoneMuted(bool* aMicrophoneMuted) -{ - - if (AudioSystem::isMicrophoneMuted(aMicrophoneMuted)) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -NS_IMETHODIMP -AudioManager::SetMicrophoneMuted(bool aMicrophoneMuted) -{ - if (!AudioSystem::muteMicrophone(aMicrophoneMuted)) { - return NS_OK; - } - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -AudioManager::GetPhoneState(int32_t* aState) -{ - *aState = mPhoneState; - return NS_OK; -} - -NS_IMETHODIMP -AudioManager::SetPhoneState(int32_t aState) -{ - if (mPhoneState == aState) { - return NS_OK; - } - - nsCOMPtr obs = services::GetObserverService(); - if (obs) { - nsString state; - state.AppendInt(aState); - obs->NotifyObservers(nullptr, "phone-state-changed", state.get()); - } - -#if ANDROID_VERSION < 17 - if (AudioSystem::setPhoneState(aState)) { -#else - if (AudioSystem::setPhoneState(static_cast(aState))) { -#endif - return NS_ERROR_FAILURE; - } - -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(); -#endif - mPhoneState = aState; - return NS_OK; -} - -NS_IMETHODIMP -AudioManager::SetForceForUse(int32_t aUsage, int32_t aForce) -{ -#if ANDROID_VERSION >= 15 - status_t status = AudioSystem::setForceUse( - (audio_policy_force_use_t)aUsage, - (audio_policy_forced_cfg_t)aForce); -#if ANDROID_VERSION < 21 - // Manually call it, since AudioPortCallback is not supported. - // Current volumes might be changed by updating active devices in android - // AudioPolicyManager. - MaybeUpdateVolumeSettingToDatabase(); -#endif - return status ? NS_ERROR_FAILURE : NS_OK; -#else - NS_NOTREACHED("Doesn't support force routing on GB version"); - return NS_ERROR_UNEXPECTED; -#endif -} - -NS_IMETHODIMP -AudioManager::GetForceForUse(int32_t aUsage, int32_t* aForce) { -#if ANDROID_VERSION >= 15 - *aForce = AudioSystem::getForceUse((audio_policy_force_use_t)aUsage); - return NS_OK; -#else - NS_NOTREACHED("Doesn't support force routing on GB version"); - return NS_ERROR_UNEXPECTED; -#endif -} - -NS_IMETHODIMP -AudioManager::SetAudioChannelVolume(uint32_t aChannel, uint32_t aIndex) -{ - if (aChannel >= NUMBER_OF_AUDIO_CHANNELS) { - return NS_ERROR_INVALID_ARG; - } - - return SetStreamVolumeIndex(sChannelStreamTbl[aChannel], aIndex); -} - -NS_IMETHODIMP -AudioManager::GetAudioChannelVolume(uint32_t aChannel, uint32_t* aIndex) -{ - if (aChannel >= NUMBER_OF_AUDIO_CHANNELS) { - return NS_ERROR_INVALID_ARG; - } - - if (!aIndex) { - return NS_ERROR_NULL_POINTER; - } - - return GetStreamVolumeIndex(sChannelStreamTbl[aChannel], aIndex); -} - -NS_IMETHODIMP -AudioManager::GetMaxAudioChannelVolume(uint32_t aChannel, uint32_t* aMaxIndex) -{ - if (aChannel >= NUMBER_OF_AUDIO_CHANNELS) { - return NS_ERROR_INVALID_ARG; - } - - if (!aMaxIndex) { - return NS_ERROR_NULL_POINTER; - } - - *aMaxIndex = mStreamStates[sChannelStreamTbl[aChannel]]->GetMaxIndex(); - return NS_OK; -} - -nsresult -AudioManager::ValidateVolumeIndex(int32_t aStream, uint32_t aIndex) const -{ - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - uint32_t maxIndex = mStreamStates[aStream]->GetMaxIndex(); - if (aIndex > maxIndex) { - return NS_ERROR_FAILURE; - } - return NS_OK; -} - -nsresult -AudioManager::SetStreamVolumeForDevice(int32_t aStream, - uint32_t aIndex, - uint32_t aDevice) -{ - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - int32_t streamAlias = sStreamVolumeAliasTbl[aStream]; - VolumeStreamState* streamState = mStreamStates[streamAlias].get(); - return streamState->SetVolumeIndexToAliasStreams(aIndex, aDevice); -} - -nsresult -AudioManager::SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex) -{ - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - int32_t streamAlias = sStreamVolumeAliasTbl[aStream]; - - nsresult rv; - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - if (streamAlias == sStreamVolumeAliasTbl[streamType]) { - rv = mStreamStates[streamType]->SetVolumeIndexToActiveDevices(aIndex); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - } - - // AUDIO_STREAM_FM is not used on recent gonk. - // AUDIO_STREAM_MUSIC is used for FM radio volume control. -#if ANDROID_VERSION < 19 - if (streamAlias == AUDIO_STREAM_MUSIC && IsFmOutConnected()) { - rv = mStreamStates[AUDIO_STREAM_FM]-> - SetVolumeIndex(aIndex, AUDIO_DEVICE_OUT_FM); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } -#endif - - MaybeUpdateVolumeSettingToDatabase(); - return NS_OK; -} - -nsresult -AudioManager::GetStreamVolumeIndex(int32_t aStream, uint32_t *aIndex) -{ - if (!aIndex) { - return NS_ERROR_INVALID_ARG; - } - - if (aStream <= AUDIO_STREAM_DEFAULT || aStream >= AUDIO_STREAM_MAX) { - return NS_ERROR_INVALID_ARG; - } - - *aIndex = mStreamStates[aStream]->GetVolumeIndex(); - return NS_OK; -} - -nsAutoCString -AudioManager::AppendDeviceToVolumeSetting(const char* aName, uint32_t aDevice) -{ - nsAutoCString topic; - topic.Assign(aName); - topic.Append("."); - uint32_t index = 0; - DebugOnly exist = mAudioDeviceTableIdMaps.Get(aDevice, &index); - MOZ_ASSERT(exist); - topic.Append(kAudioDeviceInfos[index].tag); - return topic; -} - -void -AudioManager::InitVolumeFromDatabase() -{ - nsresult rv; - nsCOMPtr service = do_GetService(SETTINGS_SERVICE, &rv); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - nsCOMPtr lock; - rv = service->CreateLock(nullptr, getter_AddRefs(lock)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - - RefPtr callback = new VolumeInitCallback(); - MOZ_ASSERT(callback); - callback->GetPromise()->Then(AbstractThread::MainThread(), __func__, this, - &AudioManager::InitDeviceVolumeSucceeded, - &AudioManager::InitDeviceVolumeFailed); - - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - for (uint32_t idx2 = 0; idx2 < MOZ_ARRAY_LENGTH(kAudioDeviceInfos); ++idx2) { - lock->Get(AppendDeviceToVolumeSetting(gVolumeData[idx].mChannelName, - kAudioDeviceInfos[idx2].value).get(), - callback); - } - } -} - -void -AudioManager::InitDeviceVolumeSucceeded() -{ - mIsVolumeInited = true; - MaybeUpdateVolumeSettingToDatabase(true); -} - -void -AudioManager::InitDeviceVolumeFailed(const char* aError) -{ - // Default volume of AUDIO_DEVICE_OUT_DEFAULT is already set. - mIsVolumeInited = true; - MaybeUpdateVolumeSettingToDatabase(true); - NS_WARNING(aError); -} - -void -AudioManager::MaybeUpdateVolumeSettingToDatabase(bool aForce) -{ - if (!mIsVolumeInited) { - return; - } - - nsCOMPtr lock = GetSettingServiceLock(); - if (NS_WARN_IF(!lock)) { - return; - } - - // Send events to update the Gaia volumes - JS::Rooted value(RootingCx()); - uint32_t volume = 0; - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - int32_t streamType = gVolumeData[idx].mStreamType; - VolumeStreamState* streamState = mStreamStates[streamType].get(); - if(!aForce && !streamState->IsDevicesChanged()) { - continue; - } - // Get volume index of active device. - volume = streamState->GetVolumeIndex(); - value.setInt32(volume); - lock->Set(gVolumeData[idx].mChannelName, value, nullptr, nullptr); - } - - // For reducing the code dependency, Gaia doesn't need to know the - // device volume, it only need to care about different volume categories. - // However, we need to send the setting volume to the permanent database, - // so that we can store the volume setting even if the phone reboots. - - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - int32_t streamType = gVolumeData[idx].mStreamType; - VolumeStreamState* streamState = mStreamStates[streamType].get(); - - if(!streamState->IsVolumeIndexesChanged()) { - continue; - } - - uint32_t remainingDevices = mAudioOutDevicesUpdated; - for (uint32_t i = 0; remainingDevices != 0; i++) { - uint32_t device = (1 << i); - if ((device & remainingDevices) == 0) { - continue; - } - remainingDevices &= ~device; - if (!mAudioDeviceTableIdMaps.Get(device, nullptr)) { - continue; - } - volume = streamState->GetVolumeIndex(device); - value.setInt32(volume); - lock->Set(AppendDeviceToVolumeSetting(gVolumeData[idx].mChannelName, - device).get(), - value, nullptr, nullptr); - } - } - - // Clear changed flags - for (uint32_t idx = 0; idx < MOZ_ARRAY_LENGTH(gVolumeData); ++idx) { - int32_t streamType = gVolumeData[idx].mStreamType; - mStreamStates[streamType]->ClearDevicesChanged(); - mStreamStates[streamType]->ClearVolumeIndexesChanged(); - } - // Clear mAudioOutDevicesUpdated - mAudioOutDevicesUpdated = 0; -} - -void -AudioManager::UpdateCachedActiveDevicesForStreams() -{ - // This function updates cached active devices for streams. - // It is used for optimization of GetDevicesForStream() since L. - // AudioManager could know when active devices - // are changed in AudioPolicyManager by onAudioPortListUpdate(). - // Except it, AudioManager normally do not need to ask AuidoPolicyManager - // about current active devices of streams and could use cached values. - // Before L, onAudioPortListUpdate() does not exist and GetDevicesForStream() - // does not use the cache. Therefore this function do nothing. -#if ANDROID_VERSION >= 21 - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - // Update cached active devices of stream - mStreamStates[streamType]->IsDevicesChanged(false /* aFromCache */); - } -#endif -} - -uint32_t -AudioManager::GetDevicesForStream(int32_t aStream, bool aFromCache) -{ -#if ANDROID_VERSION >= 21 - // Since Lollipop, devices update could be notified by AudioPortCallback. - // Cached values can be used if there is no update. - if (aFromCache) { - return mStreamStates[aStream]->GetLastDevices(); - } -#endif - -#if ANDROID_VERSION >= 17 - audio_devices_t devices = - AudioSystem::getDevicesForStream(static_cast(aStream)); - - return static_cast(devices); -#else - // Per audio out device volume is not supported. - // Use AUDIO_DEVICE_OUT_SPEAKER just to store audio volume to DB. - return AUDIO_DEVICE_OUT_SPEAKER; -#endif -} - -uint32_t -AudioManager::GetDeviceForStream(int32_t aStream) -{ - uint32_t devices = - GetDevicesForStream(static_cast(aStream)); - uint32_t device = SelectDeviceFromDevices(devices); - return device; -} - -/* static */ uint32_t -AudioManager::SelectDeviceFromDevices(uint32_t aOutDevices) -{ - uint32_t device = aOutDevices; - - // See android AudioService.getDeviceForStream(). - // AudioPolicyManager expects it. - // See also android AudioPolicyManager::getDeviceForVolume(). - if ((device & (device - 1)) != 0) { - // Multiple device selection. - if ((device & AUDIO_DEVICE_OUT_SPEAKER) != 0) { - device = AUDIO_DEVICE_OUT_SPEAKER; -#if ANDROID_VERSION >= 21 - } else if ((device & AUDIO_DEVICE_OUT_HDMI_ARC) != 0) { - device = AUDIO_DEVICE_OUT_HDMI_ARC; - } else if ((device & AUDIO_DEVICE_OUT_SPDIF) != 0) { - device = AUDIO_DEVICE_OUT_SPDIF; - } else if ((device & AUDIO_DEVICE_OUT_AUX_LINE) != 0) { - device = AUDIO_DEVICE_OUT_AUX_LINE; -#endif - } else { - device &= AUDIO_DEVICE_OUT_ALL_A2DP; - } - } - MOZ_ASSERT(audio_is_output_device(device)); - return device; -} -AudioManager::VolumeStreamState::VolumeStreamState(AudioManager& aManager, - int32_t aStreamType) - : mManager(aManager) - , mStreamType(aStreamType) - , mLastDevices(0) - , mIsDevicesChanged(true) - , mIsVolumeIndexesChanged(true) -{ - InitStreamVolume(); -} - -bool -AudioManager::VolumeStreamState::IsDevicesChanged(bool aFromCache) -{ - uint32_t devices = mManager.GetDevicesForStream(mStreamType, aFromCache); - if (devices != mLastDevices) { - mLastDevices = devices; - mIsDevicesChanged = true; - } - return mIsDevicesChanged; -} - -void -AudioManager::VolumeStreamState::ClearDevicesChanged() -{ - mIsDevicesChanged = false; -} - -bool -AudioManager::VolumeStreamState::IsVolumeIndexesChanged() -{ - return mIsVolumeIndexesChanged; -} - -void -AudioManager::VolumeStreamState::ClearVolumeIndexesChanged() -{ - mIsVolumeIndexesChanged = false; -} - -void -AudioManager::VolumeStreamState::InitStreamVolume() -{ - AudioSystem::initStreamVolume(static_cast(mStreamType), - 0, - GetMaxIndex()); -} - -uint32_t -AudioManager::VolumeStreamState::GetMaxIndex() -{ - return sMaxStreamVolumeTbl[mStreamType]; -} - -uint32_t -AudioManager::VolumeStreamState::GetDefaultIndex() -{ - return sDefaultStreamVolumeTbl[mStreamType]; -} - -uint32_t -AudioManager::VolumeStreamState::GetVolumeIndex() -{ - uint32_t device = mManager.GetDeviceForStream(mStreamType); - return GetVolumeIndex(device); -} - -uint32_t -AudioManager::VolumeStreamState::GetVolumeIndex(uint32_t aDevice) -{ - uint32_t index = 0; - bool ret = mVolumeIndexes.Get(aDevice, &index); - if (!ret) { - index = mVolumeIndexes.Get(AUDIO_DEVICE_OUT_DEFAULT); - } - return index; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndexToActiveDevices(uint32_t aIndex) -{ - uint32_t device = mManager.GetDeviceForStream(mStreamType); - - // Update volume index for device - uint32_t oldVolumeIndex = 0; - bool exist = mVolumeIndexes.Get(device, &oldVolumeIndex); - if (exist && aIndex == oldVolumeIndex) { - // No update - return NS_OK; - } - - // AudioPolicyManager::setStreamVolumeIndex() set volumes of all active - // devices for stream. - nsresult rv; - rv = SetVolumeIndexToConsistentDeviceIfNeeded(aIndex, device); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - return NS_OK; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndexToAliasStreams(uint32_t aIndex, - uint32_t aDevice) -{ - uint32_t oldVolumeIndex = 0; - bool exist = mVolumeIndexes.Get(aDevice, &oldVolumeIndex); - if (exist && aIndex == oldVolumeIndex) { - // No update - return NS_OK; - } - - nsresult rv = SetVolumeIndexToConsistentDeviceIfNeeded(aIndex, aDevice); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - for (int32_t streamType = 0; streamType < AUDIO_STREAM_MAX; streamType++) { - if ((streamType != mStreamType) && - sStreamVolumeAliasTbl[streamType] == mStreamType) { - // Rescaling of index is not necessary. - rv = mManager.mStreamStates[streamType]-> - SetVolumeIndexToAliasStreams(aIndex, aDevice); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } - } - - return NS_OK; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndexToConsistentDeviceIfNeeded(uint32_t aIndex, uint32_t aDevice) -{ - nsresult rv; - if (aDevice == AUDIO_DEVICE_OUT_SPEAKER || aDevice == AUDIO_DEVICE_OUT_EARPIECE) { - // Set AUDIO_DEVICE_OUT_SPEAKER and AUDIO_DEVICE_OUT_EARPIECE to same volume. - rv = SetVolumeIndex(aIndex, AUDIO_DEVICE_OUT_SPEAKER); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - rv = SetVolumeIndex(aIndex, AUDIO_DEVICE_OUT_EARPIECE); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - } else { - // No alias device - rv = SetVolumeIndex(aIndex, aDevice); - } - return rv; -} - -nsresult -AudioManager::VolumeStreamState::SetVolumeIndex(uint32_t aIndex, - uint32_t aDevice, - bool aUpdateCache) -{ - status_t rv; -#if ANDROID_VERSION >= 17 - if (aUpdateCache) { - mVolumeIndexes.Put(aDevice, aIndex); - mIsVolumeIndexesChanged = true; - mManager.AudioOutDeviceUpdated(aDevice); - } - - rv = AudioSystem::setStreamVolumeIndex( - static_cast(mStreamType), - aIndex, - aDevice); - return rv ? NS_ERROR_FAILURE : NS_OK; -#else - if (aUpdateCache) { - // Per audio out device volume is not supported. - // Use AUDIO_DEVICE_OUT_SPEAKER just to store audio volume to DB. - mVolumeIndexes.Put(AUDIO_DEVICE_OUT_SPEAKER, aIndex); - mIsVolumeIndexesChanged = true; - mManager.AudioOutDeviceUpdated(AUDIO_DEVICE_OUT_SPEAKER); - } - rv = AudioSystem::setStreamVolumeIndex( - static_cast(mStreamType), - aIndex); - return rv ? NS_ERROR_FAILURE : NS_OK; -#endif -} - -void -AudioManager::VolumeStreamState::RestoreVolumeIndexToAllDevices() -{ - for (auto iter = mVolumeIndexes.Iter(); !iter.Done(); iter.Next()) { - const uint32_t& key = iter.Key(); - uint32_t& index = iter.Data(); - SetVolumeIndex(key, index, /* aUpdateCache */ false); - } -} - -} /* namespace gonk */ -} /* namespace dom */ -} /* namespace mozilla */ diff --git a/dom/system/gonk/AudioManager.h b/dom/system/gonk/AudioManager.h deleted file mode 100644 index f56eaad6c..000000000 --- a/dom/system/gonk/AudioManager.h +++ /dev/null @@ -1,180 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef mozilla_dom_system_b2g_audiomanager_h__ -#define mozilla_dom_system_b2g_audiomanager_h__ - -#include "mozilla/HalTypes.h" -#include "mozilla/Observer.h" -#include "mozilla/UniquePtr.h" -#include "nsAutoPtr.h" -#include "nsDataHashtable.h" -#include "nsIAudioManager.h" -#include "nsIObserver.h" -#include "android_audio/AudioSystem.h" - -// {b2b51423-502d-4d77-89b3-7786b562b084} -#define NS_AUDIOMANAGER_CID {0x94f6fd70, 0x7615, 0x4af9, \ - {0x89, 0x10, 0xf9, 0x3c, 0x55, 0xe6, 0x62, 0xec}} -#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1" - -class nsISettingsServiceLock; - -namespace mozilla { -namespace hal { -class SwitchEvent; -typedef Observer SwitchObserver; -} // namespace hal - -namespace dom { -namespace gonk { - -class VolumeInitCallback; - -class AudioManager final : public nsIAudioManager - , public nsIObserver -{ -public: - static already_AddRefed GetInstance(); - - NS_DECL_ISUPPORTS - NS_DECL_NSIAUDIOMANAGER - NS_DECL_NSIOBSERVER - - // Validate whether the volume index is within the range - nsresult ValidateVolumeIndex(int32_t aStream, uint32_t aIndex) const; - - // Called when android AudioFlinger in mediaserver is died - void HandleAudioFlingerDied(); - - void HandleHeadphoneSwitchEvent(const hal::SwitchEvent& aEvent); - - class VolumeStreamState { - public: - explicit VolumeStreamState(AudioManager& aManager, int32_t aStreamType); - int32_t GetStreamType() - { - return mStreamType; - } - bool IsDevicesChanged(bool aFromCache = true); - void ClearDevicesChanged(); - uint32_t GetLastDevices() - { - return mLastDevices; - } - bool IsVolumeIndexesChanged(); - void ClearVolumeIndexesChanged(); - void InitStreamVolume(); - uint32_t GetMaxIndex(); - uint32_t GetDefaultIndex(); - uint32_t GetVolumeIndex(); - uint32_t GetVolumeIndex(uint32_t aDevice); - void ClearCurrentVolumeUpdated(); - // Set volume index to all active devices. - // Active devices are chosen by android AudioPolicyManager. - nsresult SetVolumeIndexToActiveDevices(uint32_t aIndex); - // Set volume index to all alias streams for device. Alias streams have same volume. - nsresult SetVolumeIndexToAliasStreams(uint32_t aIndex, uint32_t aDevice); - nsresult SetVolumeIndexToConsistentDeviceIfNeeded(uint32_t aIndex, uint32_t aDevice); - nsresult SetVolumeIndex(uint32_t aIndex, uint32_t aDevice, bool aUpdateCache = true); - // Restore volume index to all devices. Called when AudioFlinger is restarted. - void RestoreVolumeIndexToAllDevices(); - private: - AudioManager& mManager; - const int32_t mStreamType; - uint32_t mLastDevices; - bool mIsDevicesChanged; - bool mIsVolumeIndexesChanged; - nsDataHashtable mVolumeIndexes; - }; - -protected: - int32_t mPhoneState; - - bool mIsVolumeInited; - - // A bitwise variable for volume update of audio output devices, - // clear it after store the value into database. - uint32_t mAudioOutDevicesUpdated; - - // Connected devices that are controlled by setDeviceConnectionState() - nsDataHashtable mConnectedDevices; - - nsDataHashtable mAudioDeviceTableIdMaps; - - bool mSwitchDone; - -#if defined(MOZ_B2G_BT) || ANDROID_VERSION >= 17 - bool mBluetoothA2dpEnabled; -#endif -#ifdef MOZ_B2G_BT - bool mA2dpSwitchDone; -#endif - nsTArray > mStreamStates; - uint32_t mLastChannelVolume[AUDIO_STREAM_CNT]; - - bool IsFmOutConnected(); - - nsresult SetStreamVolumeForDevice(int32_t aStream, - uint32_t aIndex, - uint32_t aDevice); - nsresult SetStreamVolumeIndex(int32_t aStream, uint32_t aIndex); - nsresult GetStreamVolumeIndex(int32_t aStream, uint32_t* aIndex); - - void UpdateCachedActiveDevicesForStreams(); - uint32_t GetDevicesForStream(int32_t aStream, bool aFromCache = true); - uint32_t GetDeviceForStream(int32_t aStream); - // Choose one device as representative of active devices. - static uint32_t SelectDeviceFromDevices(uint32_t aOutDevices); - -private: - nsAutoPtr mObserver; - - void HandleBluetoothStatusChanged(nsISupports* aSubject, - const char* aTopic, - const nsCString aAddress); - void HandleAudioChannelProcessChanged(); - - // Append the audio output device to the volume setting string. - nsAutoCString AppendDeviceToVolumeSetting(const char* aName, - uint32_t aDevice); - - // We store the volume setting in the database, these are related functions. - void InitVolumeFromDatabase(); - void MaybeUpdateVolumeSettingToDatabase(bool aForce = false); - - // Promise functions. - void InitDeviceVolumeSucceeded(); - void InitDeviceVolumeFailed(const char* aError); - - void AudioOutDeviceUpdated(uint32_t aDevice); - - void UpdateHeadsetConnectionState(hal::SwitchState aState); - void UpdateDeviceConnectionState(bool aIsConnected, uint32_t aDevice, const nsCString& aDeviceName); - void SetAllDeviceConnectionStates(); - - AudioManager(); - ~AudioManager(); - - friend class VolumeInitCallback; - friend class VolumeStreamState; - friend class GonkAudioPortCallback; -}; - -} /* namespace gonk */ -} /* namespace dom */ -} /* namespace mozilla */ - -#endif // mozilla_dom_system_b2g_audiomanager_h__ diff --git a/dom/system/gonk/AutoMounter.cpp b/dom/system/gonk/AutoMounter.cpp deleted file mode 100644 index 52c4554fb..000000000 --- a/dom/system/gonk/AutoMounter.cpp +++ /dev/null @@ -1,1496 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "AutoMounter.h" -#include "nsVolumeService.h" -#include "AutoMounterSetting.h" -#include "base/message_loop.h" -#include "base/task.h" -#include "mozilla/AutoRestore.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Hal.h" -#include "mozilla/StaticPtr.h" -#include "MozMtpServer.h" -#include "MozMtpStorage.h" -#include "nsCharSeparatedTokenizer.h" -#include "nsMemory.h" -#include "nsString.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" -#include "OpenFileFinder.h" -#include "Volume.h" -#include "VolumeManager.h" -#include "nsIStatusReporter.h" - -USING_MTP_NAMESPACE - -/************************************************************************** -* -* The following "switch" files are available for monitoring usb -* connections: -* -* /sys/devices/virtual/switch/usb_connected/state -* /sys/devices/virtual/switch/usb_configuration/state -* -* Under gingerbread, only the usb_configuration seems to be available. -* Starting with honeycomb, usb_connected was also added. -* -* When a cable insertion/removal occurs, then a uevent similar to the -* following will be generted: -* -* change@/devices/virtual/switch/usb_configuration -* ACTION=change -* DEVPATH=/devices/virtual/switch/usb_configuration -* SUBSYSTEM=switch -* SWITCH_NAME=usb_configuration -* SWITCH_STATE=0 -* SEQNUM=5038 -* -* SWITCH_STATE will be 0 after a removal and 1 after an insertion -* -**************************************************************************/ - -#define USB_CONFIGURATION_SWITCH_NAME NS_LITERAL_STRING("usb_configuration") - -#define GB_SYS_UMS_ENABLE "/sys/devices/virtual/usb_composite/usb_mass_storage/enable" -#define GB_SYS_USB_CONFIGURED "/sys/devices/virtual/switch/usb_configuration/state" - -#define ICS_SYS_USB_FUNCTIONS "/sys/devices/virtual/android_usb/android0/functions" -#define ICS_SYS_UMS_DIRECTORY "/sys/devices/virtual/android_usb/android0/f_mass_storage" -#define ICS_SYS_MTP_DIRECTORY "/sys/devices/virtual/android_usb/android0/f_mtp" -#define ICS_SYS_USB_STATE "/sys/devices/virtual/android_usb/android0/state" - -#undef USE_DEBUG // MozMtpDatabase.h also defines USE_DEBUG -#define USE_DEBUG 0 - -#undef LOG -#undef LOGW -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AutoMounter", ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "AutoMounter", ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "AutoMounter", ## args) - -#undef DBG -#if USE_DEBUG -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "AutoMounter" , ## args) -#else -#define DBG(args...) -#endif - -namespace mozilla { -namespace system { - -#define SYS_USB_CONFIG "sys.usb.config" -#define PERSIST_SYS_USB_CONFIG "persist.sys.usb.config" - -#define USB_FUNC_ADB "adb" -#define USB_FUNC_MTP "mtp" -#define USB_FUNC_NONE "none" -#define USB_FUNC_RNDIS "rndis" -#define USB_FUNC_UMS "mass_storage" -#define USB_FUNC_DEFAULT "default" - -class AutoMounter; - -static void SetAutoMounterStatus(int32_t aStatus); - -/***************************************************************************/ - -inline const char* SwitchStateStr(const hal::SwitchEvent& aEvent) -{ - return aEvent.status() == hal::SWITCH_STATE_ON ? "plugged" : "unplugged"; -} - -/***************************************************************************/ - -static bool -IsUsbCablePluggedIn() -{ -#if 0 - // Use this code when bug 745078 gets fixed (or use whatever the - // appropriate method is) - return GetCurrentSwitchEvent(SWITCH_USB) == hal::SWITCH_STATE_ON; -#else - // Until then, just go read the file directly - if (access(ICS_SYS_USB_STATE, F_OK) == 0) { - char usbState[20]; - if (ReadSysFile(ICS_SYS_USB_STATE, usbState, sizeof(usbState))) { - DBG("IsUsbCablePluggedIn: state = '%s'", usbState); - return strcmp(usbState, "CONFIGURED") == 0 || - strcmp(usbState, "CONNECTED") == 0; - } - ERR("Error reading file '%s': %s", ICS_SYS_USB_STATE, strerror(errno)); - return false; - } - bool configured; - if (ReadSysFile(GB_SYS_USB_CONFIGURED, &configured)) { - return configured; - } - ERR("Error reading file '%s': %s", GB_SYS_USB_CONFIGURED, strerror(errno)); - return false; -#endif -} - -static bool -IsUsbConfigured() -{ - if (access(ICS_SYS_USB_STATE, F_OK) == 0) { - char usbState[20]; - if (ReadSysFile(ICS_SYS_USB_STATE, usbState, sizeof(usbState))) { - DBG("IsUsbConfigured: state = '%s'", usbState); - return strcmp(usbState, "CONFIGURED") == 0; - } - ERR("Error reading file '%s': %s", ICS_SYS_USB_STATE, strerror(errno)); - return false; - } - bool configured; - if (ReadSysFile(GB_SYS_USB_CONFIGURED, &configured)) { - return configured; - } - ERR("Error reading file '%s': %s", GB_SYS_USB_CONFIGURED, strerror(errno)); - return false; -} - -/***************************************************************************/ - -// The AutoVolumeManagerStateObserver allows the AutoMounter to know when -// the volume manager changes state (i.e. it has finished initialization) -class AutoVolumeManagerStateObserver : public VolumeManager::StateObserver -{ -public: - virtual void Notify(const VolumeManager::StateChangedEvent& aEvent); -}; - -// The AutoVolumeEventObserver allows the AutoMounter to know about card -// insertion and removal, as well as state changes in the volume. -class AutoVolumeEventObserver : public Volume::EventObserver -{ -public: - virtual void Notify(Volume* const& aEvent); -}; - -class AutoMounterResponseCallback : public VolumeResponseCallback -{ -public: - AutoMounterResponseCallback() - : mErrorCount(0) - { - } - -protected: - virtual void ResponseReceived(const VolumeCommand* aCommand); - -private: - const static int kMaxErrorCount = 3; // Max number of errors before we give up - - int mErrorCount; -}; - -/***************************************************************************/ - -class AutoMounter -{ -public: - NS_INLINE_DECL_REFCOUNTING(AutoMounter) - - typedef nsTArray> VolumeArray; - - AutoMounter() - : mState(STATE_IDLE), - mResponseCallback(new AutoMounterResponseCallback), - mMode(AUTOMOUNTER_DISABLE) - { - VolumeManager::RegisterStateObserver(&mVolumeManagerStateObserver); - Volume::RegisterVolumeObserver(&mVolumeEventObserver, "AutoMounter"); - - // It's possible that the VolumeManager is already in the READY state, - // so we call CheckVolumeSettings here to cover that case. Otherwise, - // we'll pick it up when the VolumeManage state changes to VOLUMES_READY. - CheckVolumeSettings(); - - DBG("Calling UpdateState from constructor"); - UpdateState(); - } - - void CheckVolumeSettings() - { - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - DBG("CheckVolumeSettings: VolumeManager is NOT READY yet"); - return; - } - DBG("CheckVolumeSettings: VolumeManager is READY"); - - // The VolumeManager knows about all of the volumes from vold. We now - // know the names of all of the volumes, so we can find out what the - // initial sharing settings are set to. - - VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - VolumeManager::VolumeArray::index_type i; - for (i = 0; i < numVolumes; i++) { - RefPtr vol = VolumeManager::GetVolume(i); - if (vol) { - // We need to pick up the intial value of the - // ums.volume.NAME.enabled setting. - AutoMounterSetting::CheckVolumeSettings(vol->Name()); - - // Note: eventually CheckVolumeSettings will call - // AutoMounter::SetSharingMode, which will in turn call - // UpdateState if needed. - } - } - } - - void UpdateState(); - void GetStatus(bool& umsAvail, bool& umsConfigured, bool& umsEnabled, bool& mtpAvail, - bool& mtpConfigured, bool& mtpEnabled, bool& rndisConfigured); - - nsresult Dump(nsACString& desc); - - void ConfigureUsbFunction(const char* aUsbFunc); - - bool StartMtpServer(); - void StopMtpServer(); - - void StartUmsSharing(); - void StopUmsSharing(); - - - const char* ModeStr(int32_t aMode) - { - switch (aMode) { - case AUTOMOUNTER_DISABLE: return "Disable"; - case AUTOMOUNTER_ENABLE_UMS: return "Enable-UMS"; - case AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED: return "DisableWhenUnplugged"; - case AUTOMOUNTER_ENABLE_MTP: return "Enable-MTP"; - } - return "??? Unknown ???"; - } - - bool IsModeEnabled(int32_t aMode) - { - return aMode == AUTOMOUNTER_ENABLE_MTP || - aMode == AUTOMOUNTER_ENABLE_UMS; - } - - void SetMode(int32_t aMode) - { - if ((aMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && - (mMode == AUTOMOUNTER_DISABLE)) { - // If it's already disabled, then leave it as disabled. - // AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED implies "enabled until unplugged" - aMode = AUTOMOUNTER_DISABLE; - } - - if (aMode == AUTOMOUNTER_DISABLE && - mMode == AUTOMOUNTER_ENABLE_UMS && IsUsbCablePluggedIn()) { - // On many devices (esp non-Samsung), we can't force the disable, so we - // need to defer until the USB cable is actually unplugged. - // See bug 777043. - // - // Otherwise our attempt to disable it will fail, and we'll wind up in a bad - // state where the AutoMounter thinks that Sharing has been turned off, but - // the files are actually still being Shared because the attempt to unshare - // failed. - LOG("Attempting to disable UMS. Deferring until USB cable is unplugged."); - aMode = AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED; - } - - if (aMode != mMode) { - LOG("Changing mode from '%s' to '%s'", ModeStr(mMode), ModeStr(aMode)); - mMode = aMode; - DBG("Calling UpdateState due to mode set to %d", mMode); - UpdateState(); - } - } - - void SetSharingMode(const nsACString& aVolumeName, bool aAllowSharing) - { - RefPtr vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - if (vol->IsSharingEnabled() == aAllowSharing) { - return; - } - vol->SetUnmountRequested(false); - vol->SetMountRequested(false); - vol->SetSharingEnabled(aAllowSharing); - DBG("Calling UpdateState due to volume %s sharing set to %d", - vol->NameStr(), (int)aAllowSharing); - UpdateState(); - } - - void FormatVolume(const nsACString& aVolumeName) - { - RefPtr vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - if (vol->IsFormatRequested()) { - return; - } - vol->SetUnmountRequested(false); - vol->SetMountRequested(false); - vol->SetFormatRequested(true); - DBG("Calling UpdateState due to volume %s formatting set to %d", - vol->NameStr(), (int)vol->IsFormatRequested()); - UpdateState(); - } - - void MountVolume(const nsACString& aVolumeName) - { - RefPtr vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - vol->SetUnmountRequested(false); - if (vol->IsMountRequested() || vol->mState == nsIVolume::STATE_MOUNTED) { - return; - } - vol->SetMountRequested(true); - DBG("Calling UpdateState due to volume %s mounting set to %d", - vol->NameStr(), (int)vol->IsMountRequested()); - UpdateState(); - } - - void UnmountVolume(const nsACString& aVolumeName) - { - RefPtr vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol) { - return; - } - if (vol->IsUnmountRequested()) { - return; - } - vol->SetMountRequested(false); - vol->SetUnmountRequested(true); - DBG("Calling UpdateState due to volume %s unmounting set to %d", - vol->NameStr(), (int)vol->IsUnmountRequested()); - UpdateState(); - } - -protected: - ~AutoMounter() - { - Volume::UnregisterVolumeObserver(&mVolumeEventObserver, "AutoMounter"); - VolumeManager::UnregisterStateObserver(&mVolumeManagerStateObserver); - } - -private: - - enum STATE - { - // IDLE - Nothing is being shared - STATE_IDLE, - - // We've detected that conditions are right to enable mtp. So we've - // set sys.usb.config to include mtp, and we're waiting for the USB - // subsystem to be "configured". Once mtp shows up in - // then we know - // that its been configured and we can open /dev/mtp_usb - STATE_MTP_CONFIGURING, - - // mtp has been configured (i.e. mtp now shows up in - // /sys/devices/virtual/android_usb/android0/functions so we can start - // the mtp server. - STATE_MTP_STARTED, - - // The mtp server has reported sessionStarted. We'll leave this state - // when we receive sessionEnded. - STATE_MTP_CONNECTED, - - // We've added mass_storage (aka UMS) to sys.usb.config and we're waiting for - // mass_storage to appear in /sys/devices/virtual/android_usb/android0/functions - STATE_UMS_CONFIGURING, - - // mass_storage has been configured and we can start sharing once the user - // enables it. - STATE_UMS_CONFIGURED, - - // USB Tethering is enabled - STATE_RNDIS_CONFIGURED, - }; - - const char *StateStr(STATE aState) - { - switch (aState) { - case STATE_IDLE: return "IDLE"; - case STATE_MTP_CONFIGURING: return "MTP_CONFIGURING"; - case STATE_MTP_CONNECTED: return "MTP_CONNECTED"; - case STATE_MTP_STARTED: return "MTP_STARTED"; - case STATE_UMS_CONFIGURING: return "UMS_CONFIGURING"; - case STATE_UMS_CONFIGURED: return "UMS_CONFIGURED"; - case STATE_RNDIS_CONFIGURED: return "RNDIS_CONFIGURED"; - } - return "STATE_???"; - } - - void SetState(STATE aState) - { - const char *oldStateStr = StateStr(mState); - mState = aState; - const char *newStateStr = StateStr(mState); - LOG("AutoMounter state changed from %s to %s", oldStateStr, newStateStr); - } - - STATE mState; - - AutoVolumeEventObserver mVolumeEventObserver; - AutoVolumeManagerStateObserver mVolumeManagerStateObserver; - RefPtr mResponseCallback; - int32_t mMode; - MozMtpStorage::Array mMozMtpStorage; -}; - -static StaticRefPtr sAutoMounter; -static StaticRefPtr sMozMtpServer; - -// The following is for status reporter -enum STATE_REPORTER_STATE -{ - REPORTER_UNREGISTERED, - REPORTER_REGISTERED -}; - -static int status_reporter_progress = REPORTER_UNREGISTERED; -nsresult getState(nsACString &desc) -{ - sAutoMounter->Dump(desc); - return NS_OK; -} -NS_STATUS_REPORTER_IMPLEMENT(AutoMounter, "AutoMounter", getState); - -/***************************************************************************/ - -void -AutoVolumeManagerStateObserver::Notify(const VolumeManager::StateChangedEvent &) -{ - LOG("VolumeManager state changed event: %s", VolumeManager::StateStr()); - - if (!sAutoMounter) { - return; - } - - // In the event that the VolumeManager just entered the VOLUMES_READY state, - // we call CheckVolumeSettings here (it's possible that this method never - // gets called if the VolumeManager was already in the VOLUMES_READY state - // by the time the AutoMounter was constructed). - sAutoMounter->CheckVolumeSettings(); - - DBG("Calling UpdateState due to VolumeManagerStateObserver"); - sAutoMounter->UpdateState(); -} - -void -AutoVolumeEventObserver::Notify(Volume * const &) -{ - if (!sAutoMounter) { - return; - } - DBG("Calling UpdateState due to VolumeEventStateObserver"); - sAutoMounter->UpdateState(); -} - -void -AutoMounterResponseCallback::ResponseReceived(const VolumeCommand* aCommand) -{ - - if (WasSuccessful()) { - DBG("Calling UpdateState due to Volume::OnSuccess"); - mErrorCount = 0; - sAutoMounter->UpdateState(); - return; - } - ERR("Command '%s' failed: %d '%s'", - aCommand->CmdStr(), ResponseCode(), ResponseStr().get()); - - if (++mErrorCount < kMaxErrorCount) { - DBG("Calling UpdateState due to VolumeResponseCallback::OnError"); - sAutoMounter->UpdateState(); - } -} - -static bool -IsUsbFunctionEnabled(const char* aConfig, const char* aUsbFunc) -{ - nsAutoCString config(aConfig); - nsCCharSeparatedTokenizer tokenizer(config, ','); - - while (tokenizer.hasMoreTokens()) { - nsAutoCString token(tokenizer.nextToken()); - if (token.Equals(aUsbFunc)) { - DBG("IsUsbFunctionEnabled('%s', '%s'): returning true", aConfig, aUsbFunc); - return true; - } - } - DBG("IsUsbFunctionEnabled('%s', '%s'): returning false", aConfig, aUsbFunc); - return false; -} - -static void -SetUsbFunction(const char* aUsbFunc) -{ - char oldSysUsbConfig[PROPERTY_VALUE_MAX]; - property_get(SYS_USB_CONFIG, oldSysUsbConfig, ""); - - if (strcmp(oldSysUsbConfig, USB_FUNC_NONE) == 0) { - // It's quite possible that sys.usb.config may have the value "none". We - // convert that to an empty string here, and at the end we convert the - // empty string back to "none". - oldSysUsbConfig[0] = '\0'; - } - - if (IsUsbFunctionEnabled(oldSysUsbConfig, aUsbFunc)) { - // The function is already configured. Nothing else to do. - DBG("SetUsbFunction('%s') - already set - nothing to do", aUsbFunc); - return; - } - - char newSysUsbConfig[PROPERTY_VALUE_MAX]; - - if (strcmp(aUsbFunc, USB_FUNC_MTP) == 0) { - // We're enabling MTP. For this we'll wind up using mtp, or mtp,adb - strlcpy(newSysUsbConfig, USB_FUNC_MTP, sizeof(newSysUsbConfig)); - } else if (strcmp(aUsbFunc, USB_FUNC_UMS) == 0) { - // We're enabling UMS. For this we make the assumption that the persisted - // property has mass_storage enabled. - property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, ""); - } else if (strcmp(aUsbFunc, USB_FUNC_DEFAULT) == 0) { - // Set the property as PERSIST_SYS_USB_CONFIG - property_get(PERSIST_SYS_USB_CONFIG, newSysUsbConfig, ""); - } else { - printf_stderr("AutoMounter::SetUsbFunction Unrecognized aUsbFunc '%s'\n", aUsbFunc); - MOZ_ASSERT(0); - return; - } - - // Make sure the new value that we write into sys.usb.config keeps the adb - // (or non-adb) of the current string. - - if (IsUsbFunctionEnabled(oldSysUsbConfig, USB_FUNC_ADB)) { - // ADB was turned on - keep it on. - if (!IsUsbFunctionEnabled(newSysUsbConfig, USB_FUNC_ADB)) { - // Add adb to the new string - strlcat(newSysUsbConfig, ",", sizeof(newSysUsbConfig)); - strlcat(newSysUsbConfig, USB_FUNC_ADB, sizeof(newSysUsbConfig)); - } - } else { - // ADB was turned off - keep it off - if (IsUsbFunctionEnabled(newSysUsbConfig, USB_FUNC_ADB)) { - // Remove ADB from the new string. - if (strcmp(newSysUsbConfig, USB_FUNC_ADB) == 0) { - newSysUsbConfig[0] = '\0'; - } else { - nsAutoCString withoutAdb(newSysUsbConfig); - withoutAdb.ReplaceSubstring( "," USB_FUNC_ADB, ""); - strlcpy(newSysUsbConfig, withoutAdb.get(), sizeof(newSysUsbConfig)); - } - } - } - - // If the persisted function didn't have mass_storage (this happens on - // the nexus 4/5, then we can get to here and have oldSysUsbConfig equal - // to newSysUsbConfig. So we need to check for that. - - if (strcmp(oldSysUsbConfig, newSysUsbConfig) == 0) { - DBG("SetUsbFunction('%s') %s is already set to '%s' - nothing to do", - aUsbFunc, SYS_USB_CONFIG, newSysUsbConfig); - return; - } - - if (newSysUsbConfig[0] == '\0') { - // Convert the empty string back to the string "none" - strlcpy(newSysUsbConfig, USB_FUNC_NONE, sizeof(newSysUsbConfig)); - } - LOG("SetUsbFunction(%s) %s from '%s' to '%s'", aUsbFunc, SYS_USB_CONFIG, - oldSysUsbConfig, newSysUsbConfig); - property_set(SYS_USB_CONFIG, newSysUsbConfig); -} - -bool -AutoMounter::StartMtpServer() -{ - if (sMozMtpServer) { - // Mtp Server is already running - nothing to do - return true; - } - LOG("Starting MtpServer"); - - // For debugging, Change the #if 0 to #if 1, and then attach gdb during - // the 5 second interval below. Otherwise, configuring MTP will cause adb - // (and thus gdb) to get bounced. -#if 0 - LOG("Sleeping"); - PRTime now = PR_Now(); - PRTime stopTime = now + 5000000; - while (PR_Now() < stopTime) { - LOG("Sleeping..."); - sleep(1); - } - LOG("Sleep done"); -#endif - - sMozMtpServer = new MozMtpServer(); - if (!sMozMtpServer->Init()) { - sMozMtpServer = nullptr; - return false; - } - - VolumeArray::index_type volIndex; - VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = VolumeManager::GetVolume(volIndex); - RefPtr storage = new MozMtpStorage(vol, sMozMtpServer); - mMozMtpStorage.AppendElement(storage); - } - - sMozMtpServer->Run(); - return true; -} - -void -AutoMounter::StopMtpServer() -{ - LOG("Stopping MtpServer"); - - mMozMtpStorage.Clear(); - sMozMtpServer = nullptr; -} - -/***************************************************************************/ - -void -AutoMounter::UpdateState() -{ - static bool inUpdateState = false; - if (inUpdateState) { - // When UpdateState calls SetISharing, this causes a volume state - // change to occur, which would normally cause UpdateState to be called - // again. We want the volume state change to go out (so that device - // storage will see the change in sharing state), but since we're - // already in UpdateState we just want to prevent recursion from screwing - // things up. - return; - } - AutoRestore inUpdateStateDetector(inUpdateState); - inUpdateState = true; - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // If the following preconditions are met: - // - UMS is available (i.e. compiled into the kernel) - // - UMS is enabled - // - AutoMounter is enabled - // - USB cable is plugged in - // then we will try to unmount and share - // otherwise we will try to unshare and mount. - - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - // The volume manager isn't in a ready state, so there - // isn't anything else that we can do. - LOG("UpdateState: VolumeManager not ready yet"); - return; - } - - if (mResponseCallback->IsPending()) { - // We only deal with one outstanding volume command at a time, - // so we need to wait for it to finish. - return; - } - - // Calling setprop sys.usb.config mtp,adb (or adding mass_storage) will - // cause /sys/devices/virtual/android_usb/android0/state to go: - // CONFIGURED -> DISCONNECTED -> CONNECTED -> CONFIGURED - // - // Since IsUsbCablePluggedIn returns state == CONFIGURED, it will look - // like a cable pull and replugin. - bool umsAvail, umsConfigured, umsEnabled; - bool mtpAvail, mtpConfigured, mtpEnabled; - bool rndisConfigured; - bool usbCablePluggedIn = IsUsbCablePluggedIn(); - GetStatus(umsAvail, umsConfigured, umsEnabled, mtpAvail, - mtpConfigured, mtpEnabled, rndisConfigured); - bool enabled = mtpEnabled || umsEnabled; - - if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) { - // DISABLE_WHEN_UNPLUGGED implies already enabled. - enabled = usbCablePluggedIn; - if (!usbCablePluggedIn) { - mMode = AUTOMOUNTER_DISABLE; - mtpEnabled = false; - umsEnabled = false; - } - } - - DBG("UpdateState: ums:A%dC%dE%d mtp:A%dC%dE%d rndis:%d mode:%d usb:%d mState:%s", - umsAvail, umsConfigured, umsEnabled, - mtpAvail, mtpConfigured, mtpEnabled, rndisConfigured, - mMode, usbCablePluggedIn, StateStr(mState)); - - switch (mState) { - - case STATE_IDLE: - if (!usbCablePluggedIn) { - // Stay in the IDLE state. We'll get a CONNECTED or CONFIGURED - // UEvent when the usb cable is plugged in. - break; - } - if (rndisConfigured) { - // USB Tethering uses RNDIS. We'll just wait until its turned off. - SetState(STATE_RNDIS_CONFIGURED); - break; - } - if (mtpEnabled) { - if (mtpConfigured) { - // The USB layer has already been configured. Now we can go ahead - // and start the MTP server. This particular codepath will not - // normally be taken, but it could happen if you stop and restart - // b2g while sys.usb.config is set to enable mtp. - if (StartMtpServer()) { - SetState(STATE_MTP_STARTED); - } else { - if (umsAvail) { - // Unable to start MTP. Go back to UMS. - LOG("UpdateState: StartMtpServer failed, switch to UMS"); - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - } else { - LOG("UpdateState: StartMtpServer failed, keep idle state"); - SetUsbFunction(USB_FUNC_DEFAULT); - } - } - } else { - // We need to configure USB to use mtp. Wait for it to be configured - // before we start the MTP server. - SetUsbFunction(USB_FUNC_MTP); - SetState(STATE_MTP_CONFIGURING); - } - } else if (umsConfigured) { - // UMS is already configured. - SetState(STATE_UMS_CONFIGURED); - } else if (umsAvail) { - // We do this whether or not UMS is enabled. With UMS, it's the - // sharing of the volume which is significant. What is important - // is that we don't leave it in MTP mode when MTP isn't enabled. - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - } - break; - - case STATE_MTP_CONFIGURING: - // While configuring, the USB configuration state will change from - // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED - // so we don't check for cable unplugged here. - if (mtpEnabled && mtpConfigured) { - // The USB layer has been configured. Now we can go ahead and start - // the MTP server. - if (StartMtpServer()) { - SetState(STATE_MTP_STARTED); - } else { - // Unable to start MTP. Go back to UMS. - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - } - break; - } - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - break; - - case STATE_MTP_STARTED: - if (usbCablePluggedIn && mtpConfigured && mtpEnabled) { - // Everything is still good. Leave the MTP server running - break; - } - DBG("STATE_MTP_STARTED: About to StopMtpServer " - "mtpConfigured = %d mtpEnabled = %d usbCablePluggedIn: %d", - mtpConfigured, mtpEnabled, usbCablePluggedIn); - StopMtpServer(); - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - if (umsAvail) { - // Switch back to UMS - SetUsbFunction(USB_FUNC_UMS); - SetState(STATE_UMS_CONFIGURING); - break; - } - - // if ums/rndis is not available and mtp is disable, - // restore the usb function as PERSIST_SYS_USB_CONFIG. - SetUsbFunction(USB_FUNC_DEFAULT); - SetState(STATE_IDLE); - break; - - case STATE_UMS_CONFIGURING: - if (mtpEnabled) { - // MTP was enabled. Start reconfiguring. - SetState(STATE_MTP_CONFIGURING); - SetUsbFunction(USB_FUNC_MTP); - break; - } - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - // While configuring, the USB configuration state will change from - // CONFIGURED -> CONNECTED -> DISCONNECTED -> CONNECTED -> CONFIGURED - // so we don't check for cable unplugged here. However, having said - // that, we'll often sit in this state while the cable is unplugged, - // since we might not get any events until the cable gets plugged back - // in. This is why we need to check for mtpEnabled once we get the - // configured event. - if (umsConfigured) { - SetState(STATE_UMS_CONFIGURED); - } - break; - - case STATE_UMS_CONFIGURED: - if (usbCablePluggedIn) { - if (mtpEnabled) { - // MTP was enabled. Start reconfiguring. - SetState(STATE_MTP_CONFIGURING); - SetUsbFunction(USB_FUNC_MTP); - break; - } - if (umsConfigured && umsEnabled) { - // This is the normal state when UMS is enabled. - break; - } - } - if (rndisConfigured) { - SetState(STATE_RNDIS_CONFIGURED); - break; - } - SetState(STATE_IDLE); - break; - - case STATE_RNDIS_CONFIGURED: - if (usbCablePluggedIn && rndisConfigured) { - // Normal state when RNDIS is enabled. - break; - } - SetState(STATE_IDLE); - break; - - default: - SetState(STATE_IDLE); - break; - } - - bool tryToShare = umsEnabled && usbCablePluggedIn; - LOG("UpdateState: ums:A%dC%dE%d mtp:A%dC%dE%d mode:%d usb:%d tryToShare:%d state:%s", - umsAvail, umsConfigured, umsEnabled, - mtpAvail, mtpConfigured, mtpEnabled, - mMode, usbCablePluggedIn, tryToShare, StateStr(mState)); - - bool filesOpen = false; - static unsigned filesOpenDelayCount = 0; - VolumeArray::index_type volIndex; - VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = VolumeManager::GetVolume(volIndex); - Volume::STATE volState = vol->State(); - - if (vol->State() == nsIVolume::STATE_MOUNTED) { - LOG("UpdateState: Volume %s is %s and %s @ %s gen %d locked %d sharing %s", - vol->NameStr(), vol->StateStr(), - vol->MediaPresent() ? "inserted" : "missing", - vol->MountPoint().get(), vol->MountGeneration(), - (int)vol->IsMountLocked(), - vol->CanBeShared() ? (vol->IsSharingEnabled() ? - (vol->IsSharing() ? "en-y" : "en-n") : "dis") : "x"); - if (vol->IsSharing() && !usbCablePluggedIn) { - // We call SetIsSharing(true) below to indicate intent to share. This - // causes a state change which notifys apps, and they'll close any - // open files, which will initiate the change away from the mounted - // state and into the sharing state. Normally, when the volume - // transitions back to the mounted state, then vol->mIsSharing gets set - // to false. However, if the user pulls the USB cable before we - // actually start sharing, then the volume never actually leaves - // the mounted state (and hence never transitions from - // sharing -> mounted), and mIsSharing never gets set back to false. - // So we clear mIsSharing here. - vol->SetIsSharing(false); - } - } else { - LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(), - vol->MediaPresent() ? "inserted" : "missing"); - } - if (!vol->MediaPresent()) { - // No media - nothing we can do - continue; - } - - if (vol->State() == nsIVolume::STATE_CHECKMNT) { - // vold reports the volume is "Mounted". Need to check if the volume is - // accessible by statfs(). Once it can be accessed, set the volume as - // STATE_MOUNTED, otherwise, post a delay task of UpdateState to check it - // again. - struct statfs fsbuf; - int rc = MOZ_TEMP_FAILURE_RETRY(statfs(vol->MountPoint().get(), &fsbuf)); - if (rc == -1) { - // statfs() failed. Stay in STATE_CHECKMNT. Any failures here - // are probably non-recoverable, so we need to wait until - // something else changes the state back to IDLE/UNMOUNTED, etc. - ERR("statfs failed for '%s': errno = %d (%s)", vol->NameStr(), errno, strerror(errno)); - continue; - } - static int delay = 250; - if (fsbuf.f_blocks == 0) { - if (delay <= 4000) { - LOG("UpdateState: Volume '%s' is inaccessible, checking again in %d msec", vol->NameStr(), delay); - MessageLoopForIO::current()-> - PostDelayedTask(NewRunnableMethod(this, &AutoMounter::UpdateState), - delay); - delay *= 2; - } else { - LOG("UpdateState: Volume '%s' is inaccessible, giving up", vol->NameStr()); - } - continue; - } else { - delay = 250; - vol->SetState(nsIVolume::STATE_MOUNTED); - } - } - - if ((tryToShare && vol->IsSharingEnabled()) || - vol->IsFormatRequested() || - vol->IsUnmountRequested()) { - switch (volState) { - // We're going to try to unmount the volume - case nsIVolume::STATE_MOUNTED: { - if (vol->IsMountLocked()) { - // The volume is currently locked, so leave it in the mounted - // state. - LOGW("UpdateState: Mounted volume %s is locked, not sharing or formatting", - vol->NameStr()); - break; - } - - // Mark the volume as if we've started sharing/formatting/unmmounting. - // This will cause apps which watch device storage notifications to see - // the volume go into the different state, and prompt them to close any - // open files that they might have. - if (tryToShare && vol->IsSharingEnabled()) { - vol->SetIsSharing(true); - } else if (vol->IsFormatRequested()){ - vol->SetIsFormatting(true); - } else if (vol->IsUnmountRequested()){ - vol->SetIsUnmounting(true); - } - - // Check to see if there are any open files on the volume and - // don't initiate the unmount while there are open files. - OpenFileFinder::Info fileInfo; - OpenFileFinder fileFinder(vol->MountPoint()); - if (fileFinder.First(&fileInfo)) { - LOGW("The following files are open under '%s'", - vol->MountPoint().get()); - do { - LOGW(" PID: %d file: '%s' app: '%s' comm: '%s' exe: '%s'\n", - fileInfo.mPid, - fileInfo.mFileName.get(), - fileInfo.mAppName.get(), - fileInfo.mComm.get(), - fileInfo.mExe.get()); - } while (fileFinder.Next(&fileInfo)); - LOGW("UpdateState: Mounted volume %s has open files, not sharing or formatting", - vol->NameStr()); - - // Check again in a few seconds to see if the files are closed. - // Since we're trying to share the volume, this implies that we're - // plugged into the PC via USB and this in turn implies that the - // battery is charging, so we don't need to be too concerned about - // wasting battery here. - // - // If we just detected that there were files open, then we use - // a short timer. We will have told the apps that we're trying - // trying to share, and they'll be closing their files. This makes - // the sharing more responsive. If after a few seconds, the apps - // haven't closed their files, then we back off. - - int delay = 1000; - if (filesOpenDelayCount > 10) { - delay = 5000; - } - MessageLoopForIO::current()-> - PostDelayedTask(NewRunnableMethod(this, &AutoMounter::UpdateState), - delay); - filesOpen = true; - break; - } - - // Volume is mounted, we need to unmount before - // we can share. - LOG("UpdateState: Unmounting %s", vol->NameStr()); - vol->StartUnmount(mResponseCallback); - return; // UpdateState will be called again when the Unmount command completes - } - case nsIVolume::STATE_IDLE: - case nsIVolume::STATE_MOUNT_FAIL: { - LOG("UpdateState: Volume %s is %s", vol->NameStr(), vol->StateStr()); - if (vol->IsFormatting() && !vol->IsFormatRequested()) { - vol->SetFormatRequested(false); - if (!(tryToShare && vol->IsSharingEnabled()) && volState == nsIVolume::STATE_IDLE) { - LOG("UpdateState: Mounting %s", vol->NameStr()); - vol->StartMount(mResponseCallback); - break; - } - } - - // If there are format and share requests in the same time, - // we should do format first then share. - if (vol->IsFormatRequested()) { - // Volume is unmounted. We can go ahead and format. - LOG("UpdateState: Formatting %s", vol->NameStr()); - vol->StartFormat(mResponseCallback); - } else if (tryToShare && vol->IsSharingEnabled() && volState == nsIVolume::STATE_IDLE) { - // Volume is unmounted. We can go ahead and share. - LOG("UpdateState: Sharing %s", vol->NameStr()); - vol->StartShare(mResponseCallback); - } - return; // UpdateState will be called again when the Share/Format command completes - } - default: { - // Not in a state that we can do anything about. - break; - } - } - } else { - // We're going to try and unshare and remount the volumes - switch (volState) { - case nsIVolume::STATE_SHARED: { - // Volume is shared. We can go ahead and unshare. - LOG("UpdateState: Unsharing %s", vol->NameStr()); - vol->StartUnshare(mResponseCallback); - return; // UpdateState will be called again when the Unshare command completes - } - case nsIVolume::STATE_IDLE: { - if (!vol->IsUnmountRequested()) { - // Volume is unmounted and mount-requested, try to mount. - - LOG("UpdateState: Mounting %s", vol->NameStr()); - vol->StartMount(mResponseCallback); - } - return; // UpdateState will be called again when Mount command completes - } - default: { - // Not in a state that we can do anything about. - break; - } - } - } - } - - int32_t status = AUTOMOUNTER_STATUS_DISABLED; - if (filesOpen) { - filesOpenDelayCount++; - status = AUTOMOUNTER_STATUS_FILES_OPEN; - } else if (enabled) { - filesOpenDelayCount = 0; - status = AUTOMOUNTER_STATUS_ENABLED; - } - SetAutoMounterStatus(status); -} - -/***************************************************************************/ - -void AutoMounter::GetStatus(bool& umsAvail, bool& umsConfigured, bool& umsEnabled, - bool& mtpAvail, bool& mtpConfigured, bool& mtpEnabled, - bool& rndisConfigured) -{ - umsAvail = false; - umsConfigured = false; - umsEnabled = false; - mtpAvail = false; - mtpConfigured = false; - mtpEnabled = false; - rndisConfigured = false; - - if (access(ICS_SYS_USB_FUNCTIONS, F_OK) != 0) { - return; - } - - char functionsStr[60]; - if (!ReadSysFile(ICS_SYS_USB_FUNCTIONS, functionsStr, sizeof(functionsStr))) { - ERR("Error reading file '%s': %s", ICS_SYS_USB_FUNCTIONS, strerror(errno)); - functionsStr[0] = '\0'; - } - DBG("GetStatus: USB functions: '%s'", functionsStr); - - bool usbConfigured = IsUsbConfigured(); - - // On the Nexus 4/5, it advertises that the UMS usb function is available, - // but we have a further requirement that mass_storage be in the - // persist.sys.usb.config property. - char persistSysUsbConfig[PROPERTY_VALUE_MAX]; - property_get(PERSIST_SYS_USB_CONFIG, persistSysUsbConfig, ""); - if (IsUsbFunctionEnabled(persistSysUsbConfig, USB_FUNC_UMS)) { - umsAvail = (access(ICS_SYS_UMS_DIRECTORY, F_OK) == 0); - } - if (umsAvail) { - umsConfigured = usbConfigured && strstr(functionsStr, USB_FUNC_UMS) != nullptr; - umsEnabled = (mMode == AUTOMOUNTER_ENABLE_UMS) || - ((mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && umsConfigured); - } else { - umsConfigured = false; - umsEnabled = false; - } - - mtpAvail = (access(ICS_SYS_MTP_DIRECTORY, F_OK) == 0); - if (mtpAvail) { - mtpConfigured = usbConfigured && strstr(functionsStr, USB_FUNC_MTP) != nullptr; - mtpEnabled = (mMode == AUTOMOUNTER_ENABLE_MTP) || - ((mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && mtpConfigured); - } else { - mtpConfigured = false; - mtpEnabled = false; - } - - rndisConfigured = strstr(functionsStr, USB_FUNC_RNDIS) != nullptr; -} - - -nsresult AutoMounter::Dump(nsACString& desc) -{ - DBG("GetState!"); - bool umsAvail, umsConfigured, umsEnabled; - bool mtpAvail, mtpConfigured, mtpEnabled; - bool rndisConfigured; - GetStatus(umsAvail, umsConfigured, umsEnabled, mtpAvail, - mtpConfigured, mtpEnabled, rndisConfigured); - if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) { - // DISABLE_WHEN_UNPLUGGED implies already enabled. - if (!IsUsbCablePluggedIn()) { - mMode = AUTOMOUNTER_DISABLE; - mtpEnabled = false; - umsEnabled = false; - } - } - - // Automounter information - desc += "Current Mode:"; - desc += ModeStr(mMode); - desc += "|"; - - - desc += "Current State:"; - desc += StateStr(mState); - desc += "|"; - - desc += "UMS Status:"; - if (umsAvail) { - desc += "Available"; - } else { - desc += "UnAvailable"; - } - desc += ","; - if (umsConfigured) { - desc += "Configured"; - } else { - desc += "Un-Configured"; - } - desc += ","; - if (umsEnabled) { - desc += "Enabled"; - } else { - desc += "Disabled"; - } - desc += "|"; - - - desc += "MTP Status:"; - if (mtpAvail) { - desc += "Available"; - } else { - desc += "UnAvailable"; - } - desc += ","; - if (mtpConfigured) { - desc += "Configured"; - } else { - desc += "Un-Configured"; - } - desc += ","; - if (mtpEnabled) { - desc += "Enabled"; - } else { - desc += "Disabled"; - } - - - // Volume information - VolumeArray::index_type volIndex; - VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = VolumeManager::GetVolume(volIndex); - - desc += "|"; - desc += vol->NameStr(); - desc += ":"; - desc += vol->StateStr(); - desc += "@"; - desc += vol->MountPoint().get(); - - if (!vol->MediaPresent()) { - continue; - } - - if (vol->CanBeShared()) { - desc += ",CanBeShared"; - } - if (vol->CanBeFormatted()) { - desc += ",CanBeFormatted"; - } - if (vol->CanBeMounted()) { - desc += ",CanBeMounted"; - } - if (vol->IsRemovable()) { - desc += ",Removable"; - } - if (vol->IsHotSwappable()) { - desc += ",HotSwappable"; - } - } - - return NS_OK; -} - - -static void -InitAutoMounterIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(!sAutoMounter); - - sAutoMounter = new AutoMounter(); -} - -static void -ShutdownAutoMounterIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sAutoMounter = nullptr; - ShutdownVolumeManager(); -} - -static void -SetAutoMounterModeIOThread(const int32_t& aMode) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->SetMode(aMode); -} - -static void -SetAutoMounterSharingModeIOThread(const nsCString& aVolumeName, const bool& aAllowSharing) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->SetSharingMode(aVolumeName, aAllowSharing); -} - -static void -AutoMounterFormatVolumeIOThread(const nsCString& aVolumeName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->FormatVolume(aVolumeName); -} - -static void -AutoMounterMountVolumeIOThread(const nsCString& aVolumeName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->MountVolume(aVolumeName); -} - -static void -AutoMounterUnmountVolumeIOThread(const nsCString& aVolumeName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sAutoMounter); - - sAutoMounter->UnmountVolume(aVolumeName); -} - -static void -UsbCableEventIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (!sAutoMounter) { - return; - } - DBG("Calling UpdateState due to USBCableEvent"); - sAutoMounter->UpdateState(); -} - -/************************************************************************** -* -* Public API -* -* Since the AutoMounter runs in IO Thread context, we need to switch -* to IOThread context before we can do anything. -* -**************************************************************************/ - -class UsbCableObserver final : public hal::SwitchObserver -{ - ~UsbCableObserver() - { - hal::UnregisterSwitchObserver(hal::SWITCH_USB, this); - } - -public: - NS_INLINE_DECL_REFCOUNTING(UsbCableObserver) - - UsbCableObserver() - { - hal::RegisterSwitchObserver(hal::SWITCH_USB, this); - } - - virtual void Notify(const hal::SwitchEvent& aEvent) - { - DBG("UsbCable switch device: %d state: %s\n", - aEvent.device(), SwitchStateStr(aEvent)); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(UsbCableEventIOThread)); - } -}; - -static StaticRefPtr sUsbCableObserver; -static StaticRefPtr sAutoMounterSetting; - -void -InitAutoMounter() -{ - InitVolumeManager(); - sAutoMounterSetting = new AutoMounterSetting(); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(InitAutoMounterIOThread)); - - // Switch Observers need to run on the main thread, so we need to - // start it here and have it send events to the AutoMounter running - // on the IO Thread. - sUsbCableObserver = new UsbCableObserver(); - - // Register status reporter into reporter manager - if(status_reporter_progress == REPORTER_UNREGISTERED) { - NS_RegisterStatusReporter(new NS_STATUS_REPORTER_NAME(AutoMounter)); - } - status_reporter_progress = REPORTER_REGISTERED; -} - -int32_t -GetAutoMounterStatus() -{ - if (sAutoMounterSetting) { - return sAutoMounterSetting->GetStatus(); - } - return AUTOMOUNTER_STATUS_DISABLED; -} - -//static -void -SetAutoMounterStatus(int32_t aStatus) -{ - if (sAutoMounterSetting) { - sAutoMounterSetting->SetStatus(aStatus); - } -} - -void -SetAutoMounterMode(int32_t aMode) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(SetAutoMounterModeIOThread, aMode)); -} - -void -SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(SetAutoMounterSharingModeIOThread, - aVolumeName, aAllowSharing)); -} - -void -AutoMounterFormatVolume(const nsCString& aVolumeName) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(AutoMounterFormatVolumeIOThread, - aVolumeName)); -} - -void -AutoMounterMountVolume(const nsCString& aVolumeName) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(AutoMounterMountVolumeIOThread, - aVolumeName)); -} - -void -AutoMounterUnmountVolume(const nsCString& aVolumeName) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(AutoMounterUnmountVolumeIOThread, - aVolumeName)); -} - -void -ShutdownAutoMounter() -{ - if (sAutoMounter) { - DBG("ShutdownAutoMounter: About to StopMtpServer"); - sAutoMounter->StopMtpServer(); - // Unregister status reporter into reporter manager - if(status_reporter_progress == REPORTER_REGISTERED) { - NS_UnregisterStatusReporter(new NS_STATUS_REPORTER_NAME(AutoMounter)); - } - status_reporter_progress = REPORTER_UNREGISTERED; - } - sAutoMounterSetting = nullptr; - sUsbCableObserver = nullptr; - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownAutoMounterIOThread)); -} - -} // system -} // mozilla diff --git a/dom/system/gonk/AutoMounter.h b/dom/system/gonk/AutoMounter.h deleted file mode 100644 index ea98cadf1..000000000 --- a/dom/system/gonk/AutoMounter.h +++ /dev/null @@ -1,101 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_automounter_h__ -#define mozilla_system_automounter_h__ - -#include - -class nsCString; - -namespace mozilla { -namespace system { - -// AutoMounter modes -#define AUTOMOUNTER_DISABLE 0 -#define AUTOMOUNTER_ENABLE_UMS 1 -#define AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED 2 -#define AUTOMOUNTER_ENABLE_MTP 3 - -// Automounter statuses -#define AUTOMOUNTER_STATUS_DISABLED 0 -#define AUTOMOUNTER_STATUS_ENABLED 1 -#define AUTOMOUNTER_STATUS_FILES_OPEN 2 - -/** - * Initialize the automounter. This causes some of the phone's - * directories to show up on the host when the phone is plugged - * into the host via USB. - * - * When the AutoMounter starts, it will poll the current state - * of affairs (usb cable plugged in, automounter enabled, etc) - * and try to make the state of the volumes match. - */ -void -InitAutoMounter(); - -/** - * Sets the enabled state of the automounter. - * - * This will in turn cause the automounter to re-evaluate - * whether it should mount/unmount/share/unshare volumes. - */ -void -SetAutoMounterMode(int32_t aMode); - -/** - * Reports the status of the automounter. - */ -int32_t -GetAutoMounterStatus(); - -/** - * Sets the sharing mode of an individual volume. - * - * If a volume is enabled for sharing, and the autmounter - * is in a state to share, then the volume will be shared - * with the PC. - */ -void -SetAutoMounterSharingMode(const nsCString& aVolumeName, bool aAllowSharing); - -/** - * Formats the volume with specified volume name. - * - * If the volume is ready to format, automounter - * will unmount it, format it and then mount it again. - */ -void -AutoMounterFormatVolume(const nsCString& aVolumeName); - -/** - * Mounts the volume with specified volume name. - * - * If the volume is already unmounted, automounter - * will mount it. Otherwise automounter will skip this. - */ -void -AutoMounterMountVolume(const nsCString& aVolumeName); - -/** - * Unmounts the volume with specified volume name. - * - * If the volume is already mounted, automounter - * will unmount it. Otherwise automounter will skip this. - */ -void -AutoMounterUnmountVolume(const nsCString& aVolumeName); - -/** - * Shuts down the automounter. - * - * This leaves the volumes in whatever state they're in. - */ -void -ShutdownAutoMounter(); - -} // system -} // mozilla - -#endif // mozilla_system_automounter_h__ diff --git a/dom/system/gonk/AutoMounterSetting.cpp b/dom/system/gonk/AutoMounterSetting.cpp deleted file mode 100644 index 606bcce04..000000000 --- a/dom/system/gonk/AutoMounterSetting.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "AutoMounter.h" -#include "AutoMounterSetting.h" - -#include "base/message_loop.h" -#include "jsapi.h" -#include "mozilla/Services.h" -#include "nsCOMPtr.h" -#include "nsContentUtils.h" -#include "nsDebug.h" -#include "nsIObserverService.h" -#include "nsISettingsService.h" -#include "nsJSUtils.h" -#include "nsPrintfCString.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "nsThreadUtils.h" -#include "xpcpublic.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/Attributes.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -#undef LOG -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AutoMounterSetting" , ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "AutoMounterSetting" , ## args) - -#define UMS_MODE "ums.mode" -#define UMS_STATUS "ums.status" -#define UMS_VOLUME_ENABLED_PREFIX "ums.volume." -#define UMS_VOLUME_ENABLED_SUFFIX ".enabled" -#define MOZSETTINGS_CHANGED "mozsettings-changed" - -using namespace mozilla::dom; - -namespace mozilla { -namespace system { - -class SettingsServiceCallback final : public nsISettingsServiceCallback -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - SettingsServiceCallback() {} - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle aResult) - { - if (aResult.isInt32()) { - int32_t mode = aResult.toInt32(); - SetAutoMounterMode(mode); - } - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) - { - ERR("SettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); - return NS_OK; - } - -protected: - ~SettingsServiceCallback() {} -}; - -NS_IMPL_ISUPPORTS(SettingsServiceCallback, nsISettingsServiceCallback) - -class CheckVolumeSettingsCallback final : public nsISettingsServiceCallback -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - CheckVolumeSettingsCallback(const nsACString& aVolumeName) - : mVolumeName(aVolumeName) {} - - NS_IMETHOD Handle(const nsAString& aName, JS::Handle aResult) - { - if (aResult.isBoolean()) { - bool isSharingEnabled = aResult.toBoolean(); - SetAutoMounterSharingMode(mVolumeName, isSharingEnabled); - } - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString& aName) - { - ERR("CheckVolumeSettingsCallback::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); - return NS_OK; - } - -protected: - ~CheckVolumeSettingsCallback() {} - -private: - nsCString mVolumeName; -}; - -NS_IMPL_ISUPPORTS(CheckVolumeSettingsCallback, nsISettingsServiceCallback) - -AutoMounterSetting::AutoMounterSetting() - : mStatus(AUTOMOUNTER_STATUS_DISABLED) -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Setup an observer to watch changes to the setting - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - if (!observerService) { - ERR("GetObserverService failed"); - return; - } - nsresult rv; - rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false); - if (NS_FAILED(rv)) { - ERR("AddObserver failed"); - return; - } - - // Force ums.mode to be 0 initially. We do this because settings are persisted. - // We don't want UMS to be enabled until such time as the phone is unlocked, - // and gaia/apps/system/js/storage.js takes care of detecting when the phone - // becomes unlocked and changes ums.mode appropriately. - nsCOMPtr settingsService = - do_GetService("@mozilla.org/settingsService;1"); - if (!settingsService) { - ERR("Failed to get settingsLock service!"); - return; - } - nsCOMPtr lock; - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - nsCOMPtr callback = new SettingsServiceCallback(); - JS::Rooted value(RootingCx()); - value.setInt32(AUTOMOUNTER_DISABLE); - lock->Set(UMS_MODE, value, callback, nullptr); - value.setInt32(mStatus); - lock->Set(UMS_STATUS, value, nullptr, nullptr); -} - -AutoMounterSetting::~AutoMounterSetting() -{ - nsCOMPtr observerService = - mozilla::services::GetObserverService(); - if (observerService) { - observerService->RemoveObserver(this, MOZSETTINGS_CHANGED); - } -} - -NS_IMPL_ISUPPORTS(AutoMounterSetting, nsIObserver) - -const char * -AutoMounterSetting::StatusStr(int32_t aStatus) -{ - switch (aStatus) { - case AUTOMOUNTER_STATUS_DISABLED: return "Disabled"; - case AUTOMOUNTER_STATUS_ENABLED: return "Enabled"; - case AUTOMOUNTER_STATUS_FILES_OPEN: return "FilesOpen"; - } - return "??? Unknown ???"; -} - -class CheckVolumeSettingsRunnable : public Runnable -{ -public: - CheckVolumeSettingsRunnable(const nsACString& aVolumeName) - : mVolumeName(aVolumeName) {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr settingsService = - do_GetService("@mozilla.org/settingsService;1"); - NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE); - nsCOMPtr lock; - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - nsCOMPtr callback = - new CheckVolumeSettingsCallback(mVolumeName); - nsPrintfCString setting(UMS_VOLUME_ENABLED_PREFIX "%s" UMS_VOLUME_ENABLED_SUFFIX, - mVolumeName.get()); - lock->Get(setting.get(), callback); - return NS_OK; - } - -private: - nsCString mVolumeName; -}; - -//static -void -AutoMounterSetting::CheckVolumeSettings(const nsACString& aVolumeName) -{ - NS_DispatchToMainThread(new CheckVolumeSettingsRunnable(aVolumeName)); -} - -class SetStatusRunnable : public Runnable -{ -public: - SetStatusRunnable(int32_t aStatus) : mStatus(aStatus) {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - nsCOMPtr settingsService = - do_GetService("@mozilla.org/settingsService;1"); - NS_ENSURE_TRUE(settingsService, NS_ERROR_FAILURE); - nsCOMPtr lock; - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - // lock may be null if this gets called during shutdown. - if (lock) { - JS::Rooted value(RootingCx(), - JS::Int32Value(mStatus)); - lock->Set(UMS_STATUS, value, nullptr, nullptr); - } - return NS_OK; - } - -private: - int32_t mStatus; -}; - -//static -void -AutoMounterSetting::SetStatus(int32_t aStatus) -{ - if (aStatus != mStatus) { - LOG("Changing status from '%s' to '%s'", - StatusStr(mStatus), StatusStr(aStatus)); - mStatus = aStatus; - NS_DispatchToMainThread(new SetStatusRunnable(aStatus)); - } -} - -NS_IMETHODIMP -AutoMounterSetting::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) { - return NS_OK; - } - - // Note that this function gets called for any and all settings changes, - // so we need to carefully check if we have the one we're interested in. - // - // The string that we're interested in will be a JSON string that looks like: - // {"key":"ums.autoMount","value":true} - - RootedDictionary setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return NS_OK; - } - - // Check for ums.mode changes - if (setting.mKey.EqualsASCII(UMS_MODE)) { - if (!setting.mValue.isInt32()) { - return NS_OK; - } - int32_t mode = setting.mValue.toInt32(); - SetAutoMounterMode(mode); - return NS_OK; - } - - // Check for ums.volume.NAME.enabled - if (StringBeginsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_PREFIX)) && - StringEndsWith(setting.mKey, NS_LITERAL_STRING(UMS_VOLUME_ENABLED_SUFFIX))) { - if (!setting.mValue.isBoolean()) { - return NS_OK; - } - const size_t prefixLen = sizeof(UMS_VOLUME_ENABLED_PREFIX) - 1; - const size_t suffixLen = sizeof(UMS_VOLUME_ENABLED_SUFFIX) - 1; - nsDependentSubstring volumeName = - Substring(setting.mKey, prefixLen, setting.mKey.Length() - prefixLen - suffixLen); - bool isSharingEnabled = setting.mValue.toBoolean(); - SetAutoMounterSharingMode(NS_LossyConvertUTF16toASCII(volumeName), isSharingEnabled); - return NS_OK; - } - - return NS_OK; -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/AutoMounterSetting.h b/dom/system/gonk/AutoMounterSetting.h deleted file mode 100644 index 7972de379..000000000 --- a/dom/system/gonk/AutoMounterSetting.h +++ /dev/null @@ -1,38 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_automountersetting_h__ -#define mozilla_system_automountersetting_h__ - -#include "nsIObserver.h" - -namespace mozilla { -namespace system { - -class AutoMounterSetting : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - AutoMounterSetting(); - - static void CheckVolumeSettings(const nsACString& aVolumeName); - - int32_t GetStatus() { return mStatus; } - void SetStatus(int32_t aStatus); - const char *StatusStr(int32_t aStatus); - -protected: - virtual ~AutoMounterSetting(); - -private: - int32_t mStatus; -}; - -} // namespace system -} // namespace mozilla - -#endif // mozilla_system_automountersetting_h__ - diff --git a/dom/system/gonk/DataCallInterfaceService.js b/dom/system/gonk/DataCallInterfaceService.js deleted file mode 100644 index 0f0e7101c..000000000 --- a/dom/system/gonk/DataCallInterfaceService.js +++ /dev/null @@ -1,276 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const DATACALLINTERFACE_CONTRACTID = "@mozilla.org/datacall/interface;1"; -const DATACALLINTERFACESERVICE_CONTRACTID = - "@mozilla.org/datacall/interfaceservice;1"; -const DATACALLINTERFACE_CID = - Components.ID("{ff669306-4390-462a-989b-ba37fc42153f}"); -const DATACALLINTERFACESERVICE_CID = - Components.ID("{e23e9337-592d-40b9-8cef-7bd47c28b72e}"); - -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled"; - -XPCOMUtils.defineLazyGetter(this, "RIL", function () { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -XPCOMUtils.defineLazyServiceGetter(this, "gRil", - "@mozilla.org/ril;1", - "nsIRadioInterfaceLayer"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIMobileConnectionService"); - -var DEBUG = RIL.DEBUG_RIL; - -function updateDebugFlag() { - // Read debug setting from pref - let debugPref; - try { - debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED); - } catch (e) { - debugPref = false; - } - DEBUG = debugPref || RIL.DEBUG_RIL; -} -updateDebugFlag(); - -function DataCall(aAttributes) { - for (let key in aAttributes) { - if (key === "pdpType") { - // Convert pdp type into constant int value. - this[key] = RIL.RIL_DATACALL_PDP_TYPES.indexOf(aAttributes[key]); - continue; - } - - this[key] = aAttributes[key]; - } -} -DataCall.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCall]), - - failCause: Ci.nsIDataCallInterface.DATACALL_FAIL_NONE, - suggestedRetryTime: -1, - cid: -1, - active: -1, - pdpType: -1, - ifname: null, - addreses: null, - dnses: null, - gateways: null, - pcscf: null, - mtu: -1 -}; - -function DataCallInterfaceService() { - this._dataCallInterfaces = []; - - let numClients = gRil.numRadioInterfaces; - for (let i = 0; i < numClients; i++) { - this._dataCallInterfaces.push(new DataCallInterface(i)); - } - - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this, false); -} -DataCallInterfaceService.prototype = { - classID: DATACALLINTERFACESERVICE_CID, - classInfo: XPCOMUtils.generateCI({ - classID: DATACALLINTERFACESERVICE_CID, - contractID: DATACALLINTERFACESERVICE_CONTRACTID, - classDescription: "Data Call Interface Service", - interfaces: [Ci.nsIDataCallInterfaceService, - Ci.nsIGonkDataCallInterfaceService] - }), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterfaceService, - Ci.nsIGonkDataCallInterfaceService], - Ci.nsIObserver), - - // An array of DataCallInterface instances. - _dataCallInterfaces: null, - - debug: function(aMessage) { - dump("-*- DataCallInterfaceService: " + aMessage + "\n"); - }, - - // nsIDataCallInterfaceService - - getDataCallInterface: function(aClientId) { - let dataCallInterface = this._dataCallInterfaces[aClientId]; - if (!dataCallInterface) { - throw Cr.NS_ERROR_UNEXPECTED; - } - - return dataCallInterface; - }, - - // nsIGonkDataCallInterfaceService - - notifyDataCallListChanged: function(aClientId, aCount, aDataCalls) { - let dataCallInterface = this.getDataCallInterface(aClientId); - dataCallInterface.handleDataCallListChanged(aCount, aDataCalls); - }, - - // nsIObserver - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_PREF_CHANGED: - if (aData === PREF_RIL_DEBUG_ENABLED) { - updateDebugFlag(); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this); - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - break; - } - }, -}; - -function DataCallInterface(aClientId) { - this._clientId = aClientId; - this._radioInterface = gRil.getRadioInterface(aClientId); - this._listeners = []; - - if (DEBUG) this.debug("DataCallInterface: " + aClientId); -} -DataCallInterface.prototype = { - classID: DATACALLINTERFACE_CID, - classInfo: XPCOMUtils.generateCI({classID: DATACALLINTERFACE_CID, - contractID: DATACALLINTERFACE_CONTRACTID, - classDescription: "Data Call Interface", - interfaces: [Ci.nsIDataCallInterface]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallInterface]), - - debug: function(aMessage) { - dump("-*- DataCallInterface[" + this._clientId + "]: " + aMessage + "\n"); - }, - - _clientId: -1, - - _radioInterface: null, - - _listeners: null, - - // nsIDataCallInterface - - setupDataCall: function(aApn, aUsername, aPassword, aAuthType, aPdpType, - aCallback) { - let connection = - gMobileConnectionService.getItemByServiceId(this._clientId); - let dataInfo = connection && connection.data; - let radioTechType = dataInfo.type; - let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType); - // Convert pdp type into string value. - let pdpType = RIL.RIL_DATACALL_PDP_TYPES[aPdpType]; - - this._radioInterface.sendWorkerMessage("setupDataCall", { - radioTech: radioTechnology, - apn: aApn, - user: aUsername, - passwd: aPassword, - chappap: aAuthType, - pdptype: pdpType - }, (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - let dataCall = new DataCall(aResponse); - aCallback.notifySetupDataCallSuccess(dataCall); - } - }); - }, - - deactivateDataCall: function(aCid, aReason, aCallback) { - this._radioInterface.sendWorkerMessage("deactivateDataCall", { - cid: aCid, - reason: aReason - }, (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - aCallback.notifySuccess(); - } - }); - }, - - getDataCallList: function(aCallback) { - this._radioInterface.sendWorkerMessage("getDataCallList", null, - (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - let dataCalls = aResponse.datacalls.map( - dataCall => new DataCall(dataCall)); - aCallback.notifyGetDataCallListSuccess(dataCalls.length, dataCalls); - } - }); - }, - - setDataRegistration: function(aAttach, aCallback) { - this._radioInterface.sendWorkerMessage("setDataRegistration", { - attach: aAttach - }, (aResponse) => { - if (aResponse.errorMsg) { - aCallback.notifyError(aResponse.errorMsg); - } else { - aCallback.notifySuccess(); - } - }); - }, - - handleDataCallListChanged: function(aCount, aDataCalls) { - this._notifyAllListeners("notifyDataCallListChanged", [aCount, aDataCalls]); - }, - - _notifyAllListeners: function(aMethodName, aArgs) { - let listeners = this._listeners.slice(); - for (let listener of listeners) { - if (this._listeners.indexOf(listener) == -1) { - // Listener has been unregistered in previous run. - continue; - } - - let handler = listener[aMethodName]; - try { - handler.apply(listener, aArgs); - } catch (e) { - if (DEBUG) { - this.debug("listener for " + aMethodName + " threw an exception: " + e); - } - } - } - }, - - registerListener: function(aListener) { - if (this._listeners.indexOf(aListener) >= 0) { - return; - } - - this._listeners.push(aListener); - }, - - unregisterListener: function(aListener) { - let index = this._listeners.indexOf(aListener); - if (index >= 0) { - this._listeners.splice(index, 1); - } - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallInterfaceService]); \ No newline at end of file diff --git a/dom/system/gonk/DataCallInterfaceService.manifest b/dom/system/gonk/DataCallInterfaceService.manifest deleted file mode 100644 index bf062c7e9..000000000 --- a/dom/system/gonk/DataCallInterfaceService.manifest +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -component {e23e9337-592d-40b9-8cef-7bd47c28b72e} DataCallInterfaceService.js -contract @mozilla.org/datacall/interfaceservice;1 {e23e9337-592d-40b9-8cef-7bd47c28b72e} \ No newline at end of file diff --git a/dom/system/gonk/DataCallManager.js b/dom/system/gonk/DataCallManager.js deleted file mode 100644 index 5411987cd..000000000 --- a/dom/system/gonk/DataCallManager.js +++ /dev/null @@ -1,1726 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIMobileConnectionService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gIccService", - "@mozilla.org/icc/iccservice;1", - "nsIIccService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gDataCallInterfaceService", - "@mozilla.org/datacall/interfaceservice;1", - "nsIDataCallInterfaceService"); - -XPCOMUtils.defineLazyGetter(this, "RIL", function() { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -// Ril quirk to attach data registration on demand. -var RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = - libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") == "true"; - -// Ril quirk to control the uicc/data subscription. -var RILQUIRKS_SUBSCRIPTION_CONTROL = - libcutils.property_get("ro.moz.ril.subscription_control", "false") == "true"; - -// Ril quirk to enable IPv6 protocol/roaming protocol in APN settings. -var RILQUIRKS_HAVE_IPV6 = - libcutils.property_get("ro.moz.ril.ipv6", "false") == "true"; - -const DATACALLMANAGER_CID = - Components.ID("{35b9efa2-e42c-45ce-8210-0a13e6f4aadc}"); -const DATACALLHANDLER_CID = - Components.ID("{132b650f-c4d8-4731-96c5-83785cb31dee}"); -const RILNETWORKINTERFACE_CID = - Components.ID("{9574ee84-5d0d-4814-b9e6-8b279e03dcf4}"); -const RILNETWORKINFO_CID = - Components.ID("{dd6cf2f0-f0e3-449f-a69e-7c34fdcb8d4b}"); - -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_DATA_CALL_ERROR = "data-call-error"; -const PREF_RIL_DEBUG_ENABLED = "ril.debugging.enabled"; - -const NETWORK_TYPE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_TYPE_UNKNOWN; -const NETWORK_TYPE_WIFI = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI; -const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; -const NETWORK_TYPE_MOBILE_MMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS; -const NETWORK_TYPE_MOBILE_SUPL = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL; -const NETWORK_TYPE_MOBILE_IMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS; -const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN; -const NETWORK_TYPE_MOBILE_FOTA = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA; - -const NETWORK_STATE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_STATE_UNKNOWN; -const NETWORK_STATE_CONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTING; -const NETWORK_STATE_CONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED; -const NETWORK_STATE_DISCONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTING; -const NETWORK_STATE_DISCONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED; - -const INT32_MAX = 2147483647; - -// set to true in ril_consts.js to see debug messages -var DEBUG = RIL.DEBUG_RIL; - -function updateDebugFlag() { - // Read debug setting from pref - let debugPref; - try { - debugPref = Services.prefs.getBoolPref(PREF_RIL_DEBUG_ENABLED); - } catch (e) { - debugPref = false; - } - DEBUG = debugPref || RIL.DEBUG_RIL; -} -updateDebugFlag(); - -function DataCallManager() { - this._connectionHandlers = []; - - let numRadioInterfaces = gMobileConnectionService.numItems; - for (let clientId = 0; clientId < numRadioInterfaces; clientId++) { - this._connectionHandlers.push(new DataCallHandler(clientId)); - } - - let lock = gSettingsService.createLock(); - // Read the APN data from the settings DB. - lock.get("ril.data.apnSettings", this); - // Read the data enabled setting from DB. - lock.get("ril.data.enabled", this); - lock.get("ril.data.roaming_enabled", this); - // Read the default client id for data call. - lock.get("ril.data.defaultServiceId", this); - - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false); - Services.prefs.addObserver(PREF_RIL_DEBUG_ENABLED, this, false); -} -DataCallManager.prototype = { - classID: DATACALLMANAGER_CID, - classInfo: XPCOMUtils.generateCI({classID: DATACALLMANAGER_CID, - classDescription: "Data Call Manager", - interfaces: [Ci.nsIDataCallManager]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallManager, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - _connectionHandlers: null, - - // Flag to determine the data state to start with when we boot up. It - // corresponds to the 'ril.data.enabled' setting from the UI. - _dataEnabled: false, - - // Flag to record the default client id for data call. It corresponds to - // the 'ril.data.defaultServiceId' setting from the UI. - _dataDefaultClientId: -1, - - // Flag to record the current default client id for data call. - // It differs from _dataDefaultClientId in that it is set only when - // the switch of client id process is done. - _currentDataClientId: -1, - - // Pending function to execute when we are notified that another data call has - // been disconnected. - _pendingDataCallRequest: null, - - debug: function(aMsg) { - dump("-*- DataCallManager: " + aMsg + "\n"); - }, - - get dataDefaultServiceId() { - return this._dataDefaultClientId; - }, - - getDataCallHandler: function(aClientId) { - let handler = this._connectionHandlers[aClientId] - if (!handler) { - throw Cr.NS_ERROR_UNEXPECTED; - } - - return handler; - }, - - _setDataRegistration: function(aDataCallInterface, aAttach) { - return new Promise(function(aResolve, aReject) { - let callback = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]), - notifySuccess: function() { - aResolve(); - }, - notifyError: function(aErrorMsg) { - aReject(aErrorMsg); - } - }; - - aDataCallInterface.setDataRegistration(aAttach, callback); - }); - }, - - _handleDataClientIdChange: function(aNewClientId) { - if (this._dataDefaultClientId === aNewClientId) { - return; - } - this._dataDefaultClientId = aNewClientId; - - // This is to handle boot up stage. - if (this._currentDataClientId == -1) { - this._currentDataClientId = this._dataDefaultClientId; - let connHandler = this._connectionHandlers[this._currentDataClientId]; - let dcInterface = connHandler.dataCallInterface; - if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND || - RILQUIRKS_SUBSCRIPTION_CONTROL) { - this._setDataRegistration(dcInterface, true); - } - if (this._dataEnabled) { - let settings = connHandler.dataCallSettings; - settings.oldEnabled = settings.enabled; - settings.enabled = true; - connHandler.updateRILNetworkInterface(); - } - return; - } - - let oldConnHandler = this._connectionHandlers[this._currentDataClientId]; - let oldIface = oldConnHandler.dataCallInterface; - let oldSettings = oldConnHandler.dataCallSettings; - let newConnHandler = this._connectionHandlers[this._dataDefaultClientId]; - let newIface = newConnHandler.dataCallInterface; - let newSettings = newConnHandler.dataCallSettings; - - let applyPendingDataSettings = () => { - if (DEBUG) { - this.debug("Apply pending data registration and settings."); - } - - if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND || - RILQUIRKS_SUBSCRIPTION_CONTROL) { - this._setDataRegistration(oldIface, false).then(() => { - if (this._dataEnabled) { - newSettings.oldEnabled = newSettings.enabled; - newSettings.enabled = true; - } - this._currentDataClientId = this._dataDefaultClientId; - - this._setDataRegistration(newIface, true).then(() => { - newConnHandler.updateRILNetworkInterface(); - }); - }); - return; - } - - if (this._dataEnabled) { - newSettings.oldEnabled = newSettings.enabled; - newSettings.enabled = true; - } - - this._currentDataClientId = this._dataDefaultClientId; - newConnHandler.updateRILNetworkInterface(); - }; - - if (this._dataEnabled) { - oldSettings.oldEnabled = oldSettings.enabled; - oldSettings.enabled = false; - } - - oldConnHandler.deactivateDataCallsAndWait().then(() => { - applyPendingDataSettings(); - }); - }, - - _shutdown: function() { - for (let handler of this._connectionHandlers) { - handler.shutdown(); - } - this._connectionHandlers = null; - Services.prefs.removeObserver(PREF_RIL_DEBUG_ENABLED, this); - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED); - }, - - /** - * nsISettingsServiceCallback - */ - handle: function(aName, aResult) { - switch (aName) { - case "ril.data.apnSettings": - if (DEBUG) { - this.debug("'ril.data.apnSettings' is now " + - JSON.stringify(aResult)); - } - if (!aResult) { - break; - } - for (let clientId in this._connectionHandlers) { - let handler = this._connectionHandlers[clientId]; - let apnSetting = aResult[clientId]; - if (handler && apnSetting) { - handler.updateApnSettings(apnSetting); - } - } - break; - case "ril.data.enabled": - if (DEBUG) { - this.debug("'ril.data.enabled' is now " + aResult); - } - if (this._dataEnabled === aResult) { - break; - } - this._dataEnabled = aResult; - - if (DEBUG) { - this.debug("Default id for data call: " + this._dataDefaultClientId); - } - if (this._dataDefaultClientId === -1) { - // We haven't got the default id for data from db. - break; - } - - let connHandler = this._connectionHandlers[this._dataDefaultClientId]; - let settings = connHandler.dataCallSettings; - settings.oldEnabled = settings.enabled; - settings.enabled = aResult; - connHandler.updateRILNetworkInterface(); - break; - case "ril.data.roaming_enabled": - if (DEBUG) { - this.debug("'ril.data.roaming_enabled' is now " + aResult); - this.debug("Default id for data call: " + this._dataDefaultClientId); - } - for (let clientId = 0; clientId < this._connectionHandlers.length; clientId++) { - let connHandler = this._connectionHandlers[clientId]; - let settings = connHandler.dataCallSettings; - settings.roamingEnabled = Array.isArray(aResult) ? aResult[clientId] - : aResult; - } - if (this._dataDefaultClientId === -1) { - // We haven't got the default id for data from db. - break; - } - this._connectionHandlers[this._dataDefaultClientId].updateRILNetworkInterface(); - break; - case "ril.data.defaultServiceId": - aResult = aResult || 0; - if (DEBUG) { - this.debug("'ril.data.defaultServiceId' is now " + aResult); - } - this._handleDataClientIdChange(aResult); - break; - } - }, - - handleError: function(aErrorMessage) { - if (DEBUG) { - this.debug("There was an error while reading RIL settings."); - } - }, - - /** - * nsIObserver interface methods. - */ - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_MOZSETTINGS_CHANGED: - if ("wrappedJSObject" in aSubject) { - aSubject = aSubject.wrappedJSObject; - } - this.handle(aSubject.key, aSubject.value); - break; - case TOPIC_PREF_CHANGED: - if (aData === PREF_RIL_DEBUG_ENABLED) { - updateDebugFlag(); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - this._shutdown(); - break; - } - }, -}; - -function DataCallHandler(aClientId) { - // Initial owning attributes. - this.clientId = aClientId; - this.dataCallSettings = { - oldEnabled: false, - enabled: false, - roamingEnabled: false - }; - this._dataCalls = []; - this._listeners = []; - - // This map is used to collect all the apn types and its corresponding - // RILNetworkInterface. - this.dataNetworkInterfaces = new Map(); - - this.dataCallInterface = gDataCallInterfaceService.getDataCallInterface(aClientId); - this.dataCallInterface.registerListener(this); - - let mobileConnection = gMobileConnectionService.getItemByServiceId(aClientId); - mobileConnection.registerListener(this); - - this._dataInfo = { - state: mobileConnection.data.state, - type: mobileConnection.data.type, - roaming: mobileConnection.data.roaming - } -} -DataCallHandler.prototype = { - classID: DATACALLHANDLER_CID, - classInfo: XPCOMUtils.generateCI({classID: DATACALLHANDLER_CID, - classDescription: "Data Call Handler", - interfaces: [Ci.nsIDataCallHandler]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallHandler, - Ci.nsIDataCallInterfaceListener, - Ci.nsIMobileConnectionListener]), - - clientId: 0, - dataCallInterface: null, - dataCallSettings: null, - dataNetworkInterfaces: null, - _dataCalls: null, - _dataInfo: null, - - // Apn settings to be setup after data call are cleared. - _pendingApnSettings: null, - - debug: function(aMsg) { - dump("-*- DataCallHandler[" + this.clientId + "]: " + aMsg + "\n"); - }, - - shutdown: function() { - // Shutdown all RIL network interfaces - this.dataNetworkInterfaces.forEach(function(networkInterface) { - gNetworkManager.unregisterNetworkInterface(networkInterface); - networkInterface.shutdown(); - networkInterface = null; - }); - this.dataNetworkInterfaces.clear(); - this._dataCalls = []; - this.clientId = null; - - this.dataCallInterface.unregisterListener(this); - this.dataCallInterface = null; - - let mobileConnection = - gMobileConnectionService.getItemByServiceId(this.clientId); - mobileConnection.unregisterListener(this); - }, - - /** - * Check if we get all necessary APN data. - */ - _validateApnSetting: function(aApnSetting) { - return (aApnSetting && - aApnSetting.apn && - aApnSetting.types && - aApnSetting.types.length); - }, - - _convertApnType: function(aApnType) { - switch (aApnType) { - case "default": - return NETWORK_TYPE_MOBILE; - case "mms": - return NETWORK_TYPE_MOBILE_MMS; - case "supl": - return NETWORK_TYPE_MOBILE_SUPL; - case "ims": - return NETWORK_TYPE_MOBILE_IMS; - case "dun": - return NETWORK_TYPE_MOBILE_DUN; - case "fota": - return NETWORK_TYPE_MOBILE_FOTA; - default: - return NETWORK_TYPE_UNKNOWN; - } - }, - - _compareDataCallOptions: function(aDataCall, aNewDataCall) { - return aDataCall.apnProfile.apn == aNewDataCall.apnProfile.apn && - aDataCall.apnProfile.user == aNewDataCall.apnProfile.user && - aDataCall.apnProfile.password == aNewDataCall.apnProfile.passwd && - aDataCall.apnProfile.authType == aNewDataCall.apnProfile.authType && - aDataCall.apnProfile.protocol == aNewDataCall.apnProfile.protocol && - aDataCall.apnProfile.roaming_protocol == aNewDataCall.apnProfile.roaming_protocol; - }, - - /** - * This function will do the following steps: - * 1. Clear the cached APN settings in the RIL. - * 2. Combine APN, user name, and password as the key of |byApn| object to - * refer to the corresponding APN setting. - * 3. Use APN type as the index of |byType| object to refer to the - * corresponding APN setting. - * 4. Create RilNetworkInterface for each APN setting created at step 2. - */ - _setupApnSettings: function(aNewApnSettings) { - if (!aNewApnSettings) { - return; - } - if (DEBUG) this.debug("setupApnSettings: " + JSON.stringify(aNewApnSettings)); - - // Shutdown all network interfaces and clear data calls. - this.dataNetworkInterfaces.forEach(function(networkInterface) { - gNetworkManager.unregisterNetworkInterface(networkInterface); - networkInterface.shutdown(); - networkInterface = null; - }); - this.dataNetworkInterfaces.clear(); - this._dataCalls = []; - - // Cache the APN settings by APNs and by types in the RIL. - for (let inputApnSetting of aNewApnSettings) { - if (!this._validateApnSetting(inputApnSetting)) { - continue; - } - - // Use APN type as the key of dataNetworkInterfaces to refer to the - // corresponding RILNetworkInterface. - for (let i = 0; i < inputApnSetting.types.length; i++) { - let apnType = inputApnSetting.types[i]; - let networkType = this._convertApnType(apnType); - if (networkType === NETWORK_TYPE_UNKNOWN) { - if (DEBUG) this.debug("Invalid apn type: " + apnType); - continue; - } - - if (DEBUG) this.debug("Preparing RILNetworkInterface for type: " + apnType); - // Create DataCall for RILNetworkInterface or reuse one that is shareable. - let dataCall; - for (let i = 0; i < this._dataCalls.length; i++) { - if (this._dataCalls[i].canHandleApn(inputApnSetting)) { - if (DEBUG) this.debug("Found shareable DataCall, reusing it."); - dataCall = this._dataCalls[i]; - break; - } - } - - if (!dataCall) { - if (DEBUG) this.debug("No shareable DataCall found, creating one."); - dataCall = new DataCall(this.clientId, inputApnSetting, this); - this._dataCalls.push(dataCall); - } - - try { - let networkInterface = new RILNetworkInterface(this, networkType, - inputApnSetting, - dataCall); - gNetworkManager.registerNetworkInterface(networkInterface); - this.dataNetworkInterfaces.set(networkType, networkInterface); - } catch (e) { - if (DEBUG) { - this.debug("Error setting up RILNetworkInterface for type " + - apnType + ": " + e); - } - } - } - } - }, - - /** - * Check if all data is disconnected. - */ - allDataDisconnected: function() { - for (let i = 0; i < this._dataCalls.length; i++) { - let dataCall = this._dataCalls[i]; - if (dataCall.state != NETWORK_STATE_UNKNOWN && - dataCall.state != NETWORK_STATE_DISCONNECTED) { - return false; - } - } - return true; - }, - - deactivateDataCallsAndWait: function() { - return new Promise((aResolve, aReject) => { - this.deactivateDataCalls({ - notifyDataCallsDisconnected: function() { - aResolve(); - } - }); - }); - }, - - updateApnSettings: function(aNewApnSettings) { - if (!aNewApnSettings) { - return; - } - if (this._pendingApnSettings) { - // Change of apn settings in process, just update to the newest. - this._pengingApnSettings = aNewApnSettings; - return; - } - - this._pendingApnSettings = aNewApnSettings; - this.deactivateDataCallsAndWait().then(() => { - this._setupApnSettings(this._pendingApnSettings); - this._pendingApnSettings = null; - this.updateRILNetworkInterface(); - }); - }, - - updateRILNetworkInterface: function() { - let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE); - if (!networkInterface) { - if (DEBUG) { - this.debug("No network interface for default data."); - } - return; - } - - let connection = - gMobileConnectionService.getItemByServiceId(this.clientId); - - // This check avoids data call connection if the radio is not ready - // yet after toggling off airplane mode. - let radioState = connection && connection.radioState; - if (radioState != Ci.nsIMobileConnection.MOBILE_RADIO_STATE_ENABLED) { - if (DEBUG) { - this.debug("RIL is not ready for data connection: radio's not ready"); - } - return; - } - - // We only watch at "ril.data.enabled" flag changes for connecting or - // disconnecting the data call. If the value of "ril.data.enabled" is - // true and any of the remaining flags change the setting application - // should turn this flag to false and then to true in order to reload - // the new values and reconnect the data call. - if (this.dataCallSettings.oldEnabled === this.dataCallSettings.enabled) { - if (DEBUG) { - this.debug("No changes for ril.data.enabled flag. Nothing to do."); - } - return; - } - - let dataInfo = connection && connection.data; - let isRegistered = - dataInfo && - dataInfo.state == RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED; - let haveDataConnection = - dataInfo && - dataInfo.type != RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN; - if (!isRegistered || !haveDataConnection) { - if (DEBUG) { - this.debug("RIL is not ready for data connection: Phone's not " + - "registered or doesn't have data connection."); - } - return; - } - let wifi_active = false; - if (gNetworkManager.activeNetworkInfo && - gNetworkManager.activeNetworkInfo.type == NETWORK_TYPE_WIFI) { - wifi_active = true; - } - - let defaultDataCallConnected = networkInterface.connected; - - // We have moved part of the decision making into DataCall, the rest will be - // moved after Bug 904514 - [meta] NetworkManager enhancement. - if (networkInterface.enabled && - (!this.dataCallSettings.enabled || - (dataInfo.roaming && !this.dataCallSettings.roamingEnabled))) { - if (DEBUG) { - this.debug("Data call settings: disconnect data call."); - } - networkInterface.disconnect(); - return; - } - - if (networkInterface.enabled && wifi_active) { - if (DEBUG) { - this.debug("Disconnect data call when Wifi is connected."); - } - networkInterface.disconnect(); - return; - } - - if (!this.dataCallSettings.enabled || defaultDataCallConnected) { - if (DEBUG) { - this.debug("Data call settings: nothing to do."); - } - return; - } - if (dataInfo.roaming && !this.dataCallSettings.roamingEnabled) { - if (DEBUG) { - this.debug("We're roaming, but data roaming is disabled."); - } - return; - } - if (wifi_active) { - if (DEBUG) { - this.debug("Don't connect data call when Wifi is connected."); - } - return; - } - if (this._pendingApnSettings) { - if (DEBUG) this.debug("We're changing apn settings, ignore any changes."); - return; - } - - if (this._deactivatingDataCalls) { - if (DEBUG) this.debug("We're deactivating all data calls, ignore any changes."); - return; - } - - if (DEBUG) { - this.debug("Data call settings: connect data call."); - } - networkInterface.connect(); - }, - - _isMobileNetworkType: function(aNetworkType) { - if (aNetworkType === NETWORK_TYPE_MOBILE || - aNetworkType === NETWORK_TYPE_MOBILE_MMS || - aNetworkType === NETWORK_TYPE_MOBILE_SUPL || - aNetworkType === NETWORK_TYPE_MOBILE_IMS || - aNetworkType === NETWORK_TYPE_MOBILE_DUN || - aNetworkType === NETWORK_TYPE_MOBILE_FOTA) { - return true; - } - - return false; - }, - - getDataCallStateByType: function(aNetworkType) { - if (!this._isMobileNetworkType(aNetworkType)) { - if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!"); - throw Cr.NS_ERROR_INVALID_ARG; - } - - let networkInterface = this.dataNetworkInterfaces.get(aNetworkType); - if (!networkInterface) { - return NETWORK_STATE_UNKNOWN; - } - return networkInterface.info.state; - }, - - setupDataCallByType: function(aNetworkType) { - if (DEBUG) { - this.debug("setupDataCallByType: " + aNetworkType); - } - - if (!this._isMobileNetworkType(aNetworkType)) { - if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!"); - throw Cr.NS_ERROR_INVALID_ARG; - } - - let networkInterface = this.dataNetworkInterfaces.get(aNetworkType); - if (!networkInterface) { - if (DEBUG) { - this.debug("No network interface for type: " + aNetworkType); - } - return; - } - - networkInterface.connect(); - }, - - deactivateDataCallByType: function(aNetworkType) { - if (DEBUG) { - this.debug("deactivateDataCallByType: " + aNetworkType); - } - - if (!this._isMobileNetworkType(aNetworkType)) { - if (DEBUG) this.debug(aNetworkType + " is not a mobile network type!"); - throw Cr.NS_ERROR_INVALID_ARG; - } - - let networkInterface = this.dataNetworkInterfaces.get(aNetworkType); - if (!networkInterface) { - if (DEBUG) { - this.debug("No network interface for type: " + aNetworkType); - } - return; - } - - networkInterface.disconnect(); - }, - - _deactivatingDataCalls: false, - - deactivateDataCalls: function(aCallback) { - let dataDisconnecting = false; - this.dataNetworkInterfaces.forEach(function(networkInterface) { - if (networkInterface.enabled) { - if (networkInterface.info.state != NETWORK_STATE_UNKNOWN && - networkInterface.info.state != NETWORK_STATE_DISCONNECTED) { - dataDisconnecting = true; - } - networkInterface.disconnect(); - } - }); - - this._deactivatingDataCalls = dataDisconnecting; - if (!dataDisconnecting) { - aCallback.notifyDataCallsDisconnected(); - return; - } - - let callback = { - notifyAllDataDisconnected: () => { - this._unregisterListener(callback); - aCallback.notifyDataCallsDisconnected(); - } - }; - this._registerListener(callback); - }, - - _listeners: null, - - _notifyListeners: function(aMethodName, aArgs) { - let listeners = this._listeners.slice(); - for (let listener of listeners) { - if (this._listeners.indexOf(listener) == -1) { - // Listener has been unregistered in previous run. - continue; - } - - let handler = listener[aMethodName]; - try { - handler.apply(listener, aArgs); - } catch (e) { - this.debug("listener for " + aMethodName + " threw an exception: " + e); - } - } - }, - - _registerListener: function(aListener) { - if (this._listeners.indexOf(aListener) >= 0) { - return; - } - - this._listeners.push(aListener); - }, - - _unregisterListener: function(aListener) { - let index = this._listeners.indexOf(aListener); - if (index >= 0) { - this._listeners.splice(index, 1); - } - }, - - _findDataCallByCid: function(aCid) { - if (aCid === undefined || aCid < 0) { - return -1; - } - - for (let i = 0; i < this._dataCalls.length; i++) { - let datacall = this._dataCalls[i]; - if (datacall.linkInfo.cid != null && - datacall.linkInfo.cid == aCid) { - return i; - } - } - - return -1; - }, - - /** - * Notify about data call setup error, called from DataCall. - */ - notifyDataCallError: function(aDataCall, aErrorMsg) { - // Notify data call error only for data APN - let networkInterface = this.dataNetworkInterfaces.get(NETWORK_TYPE_MOBILE); - if (networkInterface && networkInterface.enabled) { - let dataCall = networkInterface.dataCall; - if (this._compareDataCallOptions(dataCall, aDataCall)) { - Services.obs.notifyObservers(networkInterface.info, - TOPIC_DATA_CALL_ERROR, aErrorMsg); - } - } - }, - - /** - * Notify about data call changed, called from DataCall. - */ - notifyDataCallChanged: function(aUpdatedDataCall) { - // Process pending radio power off request after all data calls - // are disconnected. - if (aUpdatedDataCall.state == NETWORK_STATE_DISCONNECTED || - aUpdatedDataCall.state == NETWORK_STATE_UNKNOWN && - this.allDataDisconnected() && this._deactivatingDataCalls) { - this._deactivatingDataCalls = false; - this._notifyListeners("notifyAllDataDisconnected", { - clientId: this.clientId - }); - } - }, - - // nsIDataCallInterfaceListener - - notifyDataCallListChanged: function(aCount, aDataCallList) { - let currentDataCalls = this._dataCalls.slice(); - for (let i = 0; i < aDataCallList.length; i++) { - let dataCall = aDataCallList[i]; - let index = this._findDataCallByCid(dataCall.cid); - if (index == -1) { - if (DEBUG) { - this.debug("Unexpected new data call: " + JSON.stringify(dataCall)); - } - continue; - } - currentDataCalls[index].onDataCallChanged(dataCall); - currentDataCalls[index] = null; - } - - // If there is any CONNECTED DataCall left in currentDataCalls, means that - // it is missing in dataCallList, we should send a DISCONNECTED event to - // notify about this. - for (let i = 0; i < currentDataCalls.length; i++) { - let currentDataCall = currentDataCalls[i]; - if (currentDataCall && currentDataCall.linkInfo.cid != null && - currentDataCall.state == NETWORK_STATE_CONNECTED) { - if (DEBUG) { - this.debug("Expected data call missing: " + JSON.stringify( - currentDataCall.apnProfile) + ", must have been DISCONNECTED."); - } - currentDataCall.onDataCallChanged({ - state: NETWORK_STATE_DISCONNECTED - }); - } - } - }, - - // nsIMobileConnectionListener - - notifyVoiceChanged: function() {}, - - notifyDataChanged: function () { - let connection = gMobileConnectionService.getItemByServiceId(this.clientId); - let newDataInfo = connection.data; - - if (this._dataInfo.state == newDataInfo.state && - this._dataInfo.type == newDataInfo.type && - this._dataInfo.roaming == newDataInfo.roaming) { - return; - } - - this._dataInfo.state = newDataInfo.state; - this._dataInfo.type = newDataInfo.type; - this._dataInfo.roaming = newDataInfo.roaming; - this.updateRILNetworkInterface(); - }, - - notifyDataError: function (aMessage) {}, - - notifyCFStateChanged: function(aAction, aReason, aNumber, aTimeSeconds, aServiceClass) {}, - - notifyEmergencyCbModeChanged: function(aActive, aTimeoutMs) {}, - - notifyOtaStatusChanged: function(aStatus) {}, - - notifyRadioStateChanged: function() {}, - - notifyClirModeChanged: function(aMode) {}, - - notifyLastKnownNetworkChanged: function() {}, - - notifyLastKnownHomeNetworkChanged: function() {}, - - notifyNetworkSelectionModeChanged: function() {}, - - notifyDeviceIdentitiesChanged: function() {} -}; - -function DataCall(aClientId, aApnSetting, aDataCallHandler) { - this.clientId = aClientId; - this.dataCallHandler = aDataCallHandler; - this.apnProfile = { - apn: aApnSetting.apn, - user: aApnSetting.user, - password: aApnSetting.password, - authType: aApnSetting.authtype, - protocol: aApnSetting.protocol, - roaming_protocol: aApnSetting.roaming_protocol - }; - this.linkInfo = { - cid: null, - ifname: null, - addresses: [], - dnses: [], - gateways: [], - pcscf: [], - mtu: null - }; - this.state = NETWORK_STATE_UNKNOWN; - this.requestedNetworkIfaces = []; -} -DataCall.prototype = { - /** - * Standard values for the APN connection retry process - * Retry funcion: time(secs) = A * numer_of_retries^2 + B - */ - NETWORK_APNRETRY_FACTOR: 8, - NETWORK_APNRETRY_ORIGIN: 3, - NETWORK_APNRETRY_MAXRETRIES: 10, - - dataCallHandler: null, - - // Event timer for connection retries - timer: null, - - // APN failed connections. Retry counter - apnRetryCounter: 0, - - // Array to hold RILNetworkInterfaces that requested this DataCall. - requestedNetworkIfaces: null, - - /** - * @return "deactivate" if changes or one of the aCurrentDataCall - * addresses is missing in updatedDataCall, or "identical" if no - * changes found, or "changed" otherwise. - */ - _compareDataCallLink: function(aUpdatedDataCall, aCurrentDataCall) { - // If network interface is changed, report as "deactivate". - if (aUpdatedDataCall.ifname != aCurrentDataCall.ifname) { - return "deactivate"; - } - - // If any existing address is missing, report as "deactivate". - for (let i = 0; i < aCurrentDataCall.addresses.length; i++) { - let address = aCurrentDataCall.addresses[i]; - if (aUpdatedDataCall.addresses.indexOf(address) < 0) { - return "deactivate"; - } - } - - if (aCurrentDataCall.addresses.length != aUpdatedDataCall.addresses.length) { - // Since now all |aCurrentDataCall.addresses| are found in - // |aUpdatedDataCall.addresses|, this means one or more new addresses are - // reported. - return "changed"; - } - - let fields = ["gateways", "dnses"]; - for (let i = 0; i < fields.length; i++) { - // Compare .. - let field = fields[i]; - let lhs = aUpdatedDataCall[field], rhs = aCurrentDataCall[field]; - if (lhs.length != rhs.length) { - return "changed"; - } - for (let i = 0; i < lhs.length; i++) { - if (lhs[i] != rhs[i]) { - return "changed"; - } - } - } - - if (aCurrentDataCall.mtu != aUpdatedDataCall.mtu) { - return "changed"; - } - - return "identical"; - }, - - _getGeckoDataCallState:function (aDataCall) { - if (aDataCall.active == Ci.nsIDataCallInterface.DATACALL_STATE_ACTIVE_UP || - aDataCall.active == Ci.nsIDataCallInterface.DATACALL_STATE_ACTIVE_DOWN) { - return NETWORK_STATE_CONNECTED; - } - - return NETWORK_STATE_DISCONNECTED; - }, - - onSetupDataCallResult: function(aDataCall) { - this.debug("onSetupDataCallResult: " + JSON.stringify(aDataCall)); - let errorMsg = aDataCall.errorMsg; - if (aDataCall.failCause && - aDataCall.failCause != Ci.nsIDataCallInterface.DATACALL_FAIL_NONE) { - errorMsg = - RIL.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[aDataCall.failCause]; - } - - if (errorMsg) { - if (DEBUG) { - this.debug("SetupDataCall error for apn " + this.apnProfile.apn + ": " + - errorMsg + " (" + aDataCall.failCause + "), retry time: " + - aDataCall.suggestedRetryTime); - } - - this.state = NETWORK_STATE_DISCONNECTED; - - if (this.requestedNetworkIfaces.length === 0) { - if (DEBUG) this.debug("This DataCall is not requested anymore."); - return; - } - - // Let DataCallHandler notify MobileConnectionService - this.dataCallHandler.notifyDataCallError(this, errorMsg); - - // For suggestedRetryTime, the value of INT32_MAX(0x7fffffff) means no retry. - if (aDataCall.suggestedRetryTime === INT32_MAX || - this.isPermanentFail(aDataCall.failCause, errorMsg)) { - if (DEBUG) this.debug("Data call error: no retry needed."); - return; - } - - this.retry(aDataCall.suggestedRetryTime); - return; - } - - this.apnRetryCounter = 0; - this.linkInfo.cid = aDataCall.cid; - - if (this.requestedNetworkIfaces.length === 0) { - if (DEBUG) { - this.debug("State is connected, but no network interface requested" + - " this DataCall"); - } - this.deactivate(); - return; - } - - this.linkInfo.ifname = aDataCall.ifname; - this.linkInfo.addresses = aDataCall.addresses ? aDataCall.addresses.split(" ") : []; - this.linkInfo.gateways = aDataCall.gateways ? aDataCall.gateways.split(" ") : []; - this.linkInfo.dnses = aDataCall.dnses ? aDataCall.dnses.split(" ") : []; - this.linkInfo.pcscf = aDataCall.pcscf ? aDataCall.pcscf.split(" ") : []; - this.linkInfo.mtu = aDataCall.mtu > 0 ? aDataCall.mtu : 0; - this.state = this._getGeckoDataCallState(aDataCall); - - // Notify DataCallHandler about data call connected. - this.dataCallHandler.notifyDataCallChanged(this); - - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - this.requestedNetworkIfaces[i].notifyRILNetworkInterface(); - } - }, - - onDeactivateDataCallResult: function() { - if (DEBUG) this.debug("onDeactivateDataCallResult"); - - this.reset(); - - if (this.requestedNetworkIfaces.length > 0) { - if (DEBUG) { - this.debug("State is disconnected/unknown, but this DataCall is" + - " requested."); - } - this.setup(); - return; - } - - // Notify DataCallHandler about data call disconnected. - this.dataCallHandler.notifyDataCallChanged(this); - }, - - onDataCallChanged: function(aUpdatedDataCall) { - if (DEBUG) { - this.debug("onDataCallChanged: " + JSON.stringify(aUpdatedDataCall)); - } - - if (this.state == NETWORK_STATE_CONNECTING || - this.state == NETWORK_STATE_DISCONNECTING) { - if (DEBUG) { - this.debug("We are in connecting/disconnecting state, ignore any " + - "unsolicited event for now."); - } - return; - } - - let dataCallState = this._getGeckoDataCallState(aUpdatedDataCall); - if (this.state == dataCallState && - dataCallState != NETWORK_STATE_CONNECTED) { - return; - } - - let newLinkInfo = { - ifname: aUpdatedDataCall.ifname, - addresses: aUpdatedDataCall.addresses ? aUpdatedDataCall.addresses.split(" ") : [], - dnses: aUpdatedDataCall.dnses ? aUpdatedDataCall.dnses.split(" ") : [], - gateways: aUpdatedDataCall.gateways ? aUpdatedDataCall.gateways.split(" ") : [], - pcscf: aUpdatedDataCall.pcscf ? aUpdatedDataCall.pcscf.split(" ") : [], - mtu: aUpdatedDataCall.mtu > 0 ? aUpdatedDataCall.mtu : 0 - }; - - switch (dataCallState) { - case NETWORK_STATE_CONNECTED: - if (this.state == NETWORK_STATE_CONNECTED) { - let result = - this._compareDataCallLink(newLinkInfo, this.linkInfo); - - if (result == "identical") { - if (DEBUG) this.debug("No changes in data call."); - return; - } - if (result == "deactivate") { - if (DEBUG) this.debug("Data link changed, cleanup."); - this.deactivate(); - return; - } - // Minor change, just update and notify. - if (DEBUG) { - this.debug("Data link minor change, just update and notify."); - } - - this.linkInfo.addresses = newLinkInfo.addresses.slice(); - this.linkInfo.gateways = newLinkInfo.gateways.slice(); - this.linkInfo.dnses = newLinkInfo.dnses.slice(); - this.linkInfo.pcscf = newLinkInfo.pcscf.slice(); - this.linkInfo.mtu = newLinkInfo.mtu; - } - break; - case NETWORK_STATE_DISCONNECTED: - case NETWORK_STATE_UNKNOWN: - if (this.state == NETWORK_STATE_CONNECTED) { - // Notify first on unexpected data call disconnection. - this.state = dataCallState; - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - this.requestedNetworkIfaces[i].notifyRILNetworkInterface(); - } - } - this.reset(); - - if (this.requestedNetworkIfaces.length > 0) { - if (DEBUG) { - this.debug("State is disconnected/unknown, but this DataCall is" + - " requested."); - } - this.setup(); - return; - } - break; - } - - this.state = dataCallState; - - // Notify DataCallHandler about data call changed. - this.dataCallHandler.notifyDataCallChanged(this); - - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - this.requestedNetworkIfaces[i].notifyRILNetworkInterface(); - } - }, - - // Helpers - - debug: function(aMsg) { - dump("-*- DataCall[" + this.clientId + ":" + this.apnProfile.apn + "]: " + - aMsg + "\n"); - }, - - get connected() { - return this.state == NETWORK_STATE_CONNECTED; - }, - - isPermanentFail: function(aDataFailCause, aErrorMsg) { - // Check ril.h for 'no retry' data call fail causes. - if (aErrorMsg === RIL.GECKO_ERROR_RADIO_NOT_AVAILABLE || - aErrorMsg === RIL.GECKO_ERROR_INVALID_PARAMETER || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_OPERATOR_BARRED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_MISSING_UKNOWN_APN || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_USER_AUTHENTICATION || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ACTIVATION_REJECT_GGSN || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_NSAPI_IN_USE || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ONLY_IPV4_ALLOWED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_ONLY_IPV6_ALLOWED || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_PROTOCOL_ERRORS || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_RADIO_POWER_OFF || - aDataFailCause === Ci.nsIDataCallInterface.DATACALL_FAIL_TETHERED_CALL_ACTIVE) { - return true; - } - - return false; - }, - - inRequestedTypes: function(aType) { - for (let i = 0; i < this.requestedNetworkIfaces.length; i++) { - if (this.requestedNetworkIfaces[i].info.type == aType) { - return true; - } - } - return false; - }, - - canHandleApn: function(aApnSetting) { - let isIdentical = this.apnProfile.apn == aApnSetting.apn && - (this.apnProfile.user || '') == (aApnSetting.user || '') && - (this.apnProfile.password || '') == (aApnSetting.password || '') && - (this.apnProfile.authType || '') == (aApnSetting.authtype || ''); - - if (RILQUIRKS_HAVE_IPV6) { - isIdentical = isIdentical && - (this.apnProfile.protocol || '') == (aApnSetting.protocol || '') && - (this.apnProfile.roaming_protocol || '') == (aApnSetting.roaming_protocol || ''); - } - - return isIdentical; - }, - - resetLinkInfo: function() { - this.linkInfo.cid = null; - this.linkInfo.ifname = null; - this.linkInfo.addresses = []; - this.linkInfo.dnses = []; - this.linkInfo.gateways = []; - this.linkInfo.pcscf = []; - this.linkInfo.mtu = null; - }, - - reset: function() { - this.resetLinkInfo(); - - this.state = NETWORK_STATE_UNKNOWN; - }, - - connect: function(aNetworkInterface) { - if (DEBUG) this.debug("connect: " + aNetworkInterface.info.type); - - if (this.requestedNetworkIfaces.indexOf(aNetworkInterface) == -1) { - this.requestedNetworkIfaces.push(aNetworkInterface); - } - - if (this.state == NETWORK_STATE_CONNECTING || - this.state == NETWORK_STATE_DISCONNECTING) { - return; - } - if (this.state == NETWORK_STATE_CONNECTED) { - // This needs to run asynchronously, to behave the same way as the case of - // non-shared apn, see bug 1059110. - Services.tm.currentThread.dispatch(() => { - // Do not notify if state changed while this event was being dispatched, - // the state probably was notified already or need not to be notified. - if (aNetworkInterface.info.state == RIL.GECKO_NETWORK_STATE_CONNECTED) { - aNetworkInterface.notifyRILNetworkInterface(); - } - }, Ci.nsIEventTarget.DISPATCH_NORMAL); - return; - } - - // If retry mechanism is running on background, stop it since we are going - // to setup data call now. - if (this.timer) { - this.timer.cancel(); - } - - this.setup(); - }, - - setup: function() { - if (DEBUG) { - this.debug("Going to set up data connection with APN " + - this.apnProfile.apn); - } - - let connection = - gMobileConnectionService.getItemByServiceId(this.clientId); - let dataInfo = connection && connection.data; - if (dataInfo == null || - dataInfo.state != RIL.GECKO_MOBILE_CONNECTION_STATE_REGISTERED || - dataInfo.type == RIL.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN) { - return; - } - - let radioTechType = dataInfo.type; - let radioTechnology = RIL.GECKO_RADIO_TECH.indexOf(radioTechType); - let authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(this.apnProfile.authType); - // Use the default authType if the value in database is invalid. - // For the case that user might not select the authentication type. - if (authType == -1) { - if (DEBUG) { - this.debug("Invalid authType '" + this.apnProfile.authtype + - "', using '" + RIL.GECKO_DATACALL_AUTH_DEFAULT + "'"); - } - authType = RIL.RIL_DATACALL_AUTH_TO_GECKO.indexOf(RIL.GECKO_DATACALL_AUTH_DEFAULT); - } - - let pdpType = Ci.nsIDataCallInterface.DATACALL_PDP_TYPE_IPV4; - if (RILQUIRKS_HAVE_IPV6) { - pdpType = !dataInfo.roaming - ? RIL.RIL_DATACALL_PDP_TYPES.indexOf(this.apnProfile.protocol) - : RIL.RIL_DATACALL_PDP_TYPES.indexOf(this.apnProfile.roaming_protocol); - if (pdpType == -1) { - if (DEBUG) { - this.debug("Invalid pdpType '" + (!dataInfo.roaming - ? this.apnProfile.protocol - : this.apnProfile.roaming_protocol) + - "', using '" + RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT + "'"); - } - pdpType = RIL.RIL_DATACALL_PDP_TYPES.indexOf(RIL.GECKO_DATACALL_PDP_TYPE_DEFAULT); - } - } - - let dcInterface = this.dataCallHandler.dataCallInterface; - dcInterface.setupDataCall( - this.apnProfile.apn, this.apnProfile.user, this.apnProfile.password, - authType, pdpType, { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]), - notifySetupDataCallSuccess: (aDataCall) => { - this.onSetupDataCallResult(aDataCall); - }, - notifyError: (aErrorMsg) => { - this.onSetupDataCallResult({errorMsg: aErrorMsg}); - } - }); - this.state = NETWORK_STATE_CONNECTING; - }, - - retry: function(aSuggestedRetryTime) { - let apnRetryTimer; - - // We will retry the connection in increasing times - // based on the function: time = A * numer_of_retries^2 + B - if (this.apnRetryCounter >= this.NETWORK_APNRETRY_MAXRETRIES) { - this.apnRetryCounter = 0; - this.timer = null; - if (DEBUG) this.debug("Too many APN Connection retries - STOP retrying"); - return; - } - - // If there is a valid aSuggestedRetryTime, override the retry timer. - if (aSuggestedRetryTime !== undefined && aSuggestedRetryTime >= 0) { - apnRetryTimer = aSuggestedRetryTime / 1000; - } else { - apnRetryTimer = this.NETWORK_APNRETRY_FACTOR * - (this.apnRetryCounter * this.apnRetryCounter) + - this.NETWORK_APNRETRY_ORIGIN; - } - this.apnRetryCounter++; - if (DEBUG) { - this.debug("Data call - APN Connection Retry Timer (secs-counter): " + - apnRetryTimer + "-" + this.apnRetryCounter); - } - - if (this.timer == null) { - // Event timer for connection retries - this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - } - this.timer.initWithCallback(this, apnRetryTimer * 1000, - Ci.nsITimer.TYPE_ONE_SHOT); - }, - - disconnect: function(aNetworkInterface) { - if (DEBUG) this.debug("disconnect: " + aNetworkInterface.info.type); - - let index = this.requestedNetworkIfaces.indexOf(aNetworkInterface); - if (index != -1) { - this.requestedNetworkIfaces.splice(index, 1); - - if (this.state == NETWORK_STATE_DISCONNECTED || - this.state == NETWORK_STATE_UNKNOWN) { - if (this.timer) { - this.timer.cancel(); - } - this.reset(); - return; - } - - // Notify the DISCONNECTED event immediately after network interface is - // removed from requestedNetworkIfaces, to make the DataCall, shared or - // not, to have the same behavior. - Services.tm.currentThread.dispatch(() => { - // Do not notify if state changed while this event was being dispatched, - // the state probably was notified already or need not to be notified. - if (aNetworkInterface.info.state == RIL.GECKO_NETWORK_STATE_DISCONNECTED) { - aNetworkInterface.notifyRILNetworkInterface(); - - // Clear link info after notifying NetworkManager. - if (this.requestedNetworkIfaces.length === 0) { - this.resetLinkInfo(); - } - } - }, Ci.nsIEventTarget.DISPATCH_NORMAL); - } - - // Only deactivate data call if no more network interface needs this - // DataCall and if state is CONNECTED, for other states, we simply remove - // the network interface from requestedNetworkIfaces. - if (this.requestedNetworkIfaces.length > 0 || - this.state != NETWORK_STATE_CONNECTED) { - return; - } - - this.deactivate(); - }, - - deactivate: function() { - let reason = Ci.nsIDataCallInterface.DATACALL_DEACTIVATE_NO_REASON; - if (DEBUG) { - this.debug("Going to disconnect data connection cid " + this.linkInfo.cid); - } - - let dcInterface = this.dataCallHandler.dataCallInterface; - dcInterface.deactivateDataCall(this.linkInfo.cid, reason, { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCallCallback]), - notifySuccess: () => { - this.onDeactivateDataCallResult(); - }, - notifyError: (aErrorMsg) => { - this.onDeactivateDataCallResult(); - } - }); - - this.state = NETWORK_STATE_DISCONNECTING; - }, - - // Entry method for timer events. Used to reconnect to a failed APN - notify: function(aTimer) { - this.setup(); - }, - - shutdown: function() { - if (this.timer) { - this.timer.cancel(); - this.timer = null; - } - } -}; - -function RILNetworkInfo(aClientId, aType, aNetworkInterface) -{ - this.serviceId = aClientId; - this.type = aType; - - this.networkInterface = aNetworkInterface; -} -RILNetworkInfo.prototype = { - classID: RILNETWORKINFO_CID, - classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINFO_CID, - classDescription: "RILNetworkInfo", - interfaces: [Ci.nsINetworkInfo, - Ci.nsIRilNetworkInfo]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo, - Ci.nsIRilNetworkInfo]), - - networkInterface: null, - - getDataCall: function() { - return this.networkInterface.dataCall; - }, - - getApnSetting: function() { - return this.networkInterface.apnSetting; - }, - - debug: function(aMsg) { - dump("-*- RILNetworkInfo[" + this.serviceId + ":" + this.type + "]: " + - aMsg + "\n"); - }, - - /** - * nsINetworkInfo Implementation - */ - get state() { - let dataCall = this.getDataCall(); - if (!dataCall.inRequestedTypes(this.type)) { - return NETWORK_STATE_DISCONNECTED; - } - return dataCall.state; - }, - - type: null, - - get name() { - return this.getDataCall().linkInfo.ifname; - }, - - getAddresses: function(aIps, aPrefixLengths) { - let addresses = this.getDataCall().linkInfo.addresses; - - let ips = []; - let prefixLengths = []; - for (let i = 0; i < addresses.length; i++) { - let [ip, prefixLength] = addresses[i].split("/"); - ips.push(ip); - prefixLengths.push(prefixLength); - } - - aIps.value = ips.slice(); - aPrefixLengths.value = prefixLengths.slice(); - - return ips.length; - }, - - getGateways: function(aCount) { - let linkInfo = this.getDataCall().linkInfo; - - if (aCount) { - aCount.value = linkInfo.gateways.length; - } - - return linkInfo.gateways.slice(); - }, - - getDnses: function(aCount) { - let linkInfo = this.getDataCall().linkInfo; - - if (aCount) { - aCount.value = linkInfo.dnses.length; - } - - return linkInfo.dnses.slice(); - }, - - /** - * nsIRilNetworkInfo Implementation - */ - - serviceId: 0, - - get iccId() { - let icc = gIccService.getIccByServiceId(this.serviceId); - let iccInfo = icc && icc.iccInfo; - - return iccInfo && iccInfo.iccid; - }, - - get mmsc() { - if (this.type != NETWORK_TYPE_MOBILE_MMS) { - if (DEBUG) this.debug("Error! Only MMS network can get MMSC."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - return this.getApnSetting().mmsc || ""; - }, - - get mmsProxy() { - if (this.type != NETWORK_TYPE_MOBILE_MMS) { - if (DEBUG) this.debug("Error! Only MMS network can get MMS proxy."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - return this.getApnSetting().mmsproxy || ""; - }, - - get mmsPort() { - if (this.type != NETWORK_TYPE_MOBILE_MMS) { - if (DEBUG) this.debug("Error! Only MMS network can get MMS port."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - // Note: Port 0 is reserved, so we treat it as invalid as well. - // See http://www.iana.org/assignments/port-numbers - return this.getApnSetting().mmsport || -1; - }, - - getPcscf: function(aCount) { - if (this.type != NETWORK_TYPE_MOBILE_IMS) { - if (DEBUG) this.debug("Error! Only IMS network can get pcscf."); - throw Cr.NS_ERROR_UNEXPECTED; - } - - let linkInfo = this.getDataCall().linkInfo; - - if (aCount) { - aCount.value = linkInfo.pcscf.length; - } - return linkInfo.pcscf.slice(); - }, -}; - -function RILNetworkInterface(aDataCallHandler, aType, aApnSetting, aDataCall) { - if (!aDataCall) { - throw new Error("No dataCall for RILNetworkInterface: " + type); - } - - this.dataCallHandler = aDataCallHandler; - this.enabled = false; - this.dataCall = aDataCall; - this.apnSetting = aApnSetting; - - this.info = new RILNetworkInfo(aDataCallHandler.clientId, aType, this); -} - -RILNetworkInterface.prototype = { - classID: RILNETWORKINTERFACE_CID, - classInfo: XPCOMUtils.generateCI({classID: RILNETWORKINTERFACE_CID, - classDescription: "RILNetworkInterface", - interfaces: [Ci.nsINetworkInterface]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterface]), - - // If this RILNetworkInterface type is enabled or not. - enabled: null, - - apnSetting: null, - - dataCall: null, - - /** - * nsINetworkInterface Implementation - */ - - info: null, - - get httpProxyHost() { - return this.apnSetting.proxy || ""; - }, - - get httpProxyPort() { - return this.apnSetting.port || ""; - }, - - get mtu() { - // Value provided by network has higher priority than apn settings. - return this.dataCall.linkInfo.mtu || this.apnSetting.mtu || -1; - }, - - // Helpers - - debug: function(aMsg) { - dump("-*- RILNetworkInterface[" + this.dataCallHandler.clientId + ":" + - this.info.type + "]: " + aMsg + "\n"); - }, - - get connected() { - return this.info.state == NETWORK_STATE_CONNECTED; - }, - - notifyRILNetworkInterface: function() { - if (DEBUG) { - this.debug("notifyRILNetworkInterface type: " + this.info.type + - ", state: " + this.info.state); - } - - gNetworkManager.updateNetworkInterface(this); - }, - - connect: function() { - this.enabled = true; - - this.dataCall.connect(this); - }, - - disconnect: function() { - if (!this.enabled) { - return; - } - this.enabled = false; - - this.dataCall.disconnect(this); - }, - - shutdown: function() { - this.dataCall.shutdown(); - this.dataCall = null; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DataCallManager]); \ No newline at end of file diff --git a/dom/system/gonk/DataCallManager.manifest b/dom/system/gonk/DataCallManager.manifest deleted file mode 100644 index 2a982415e..000000000 --- a/dom/system/gonk/DataCallManager.manifest +++ /dev/null @@ -1,4 +0,0 @@ -# DataCallManager.js -component {35b9efa2-e42c-45ce-8210-0a13e6f4aadc} DataCallManager.js -contract @mozilla.org/datacall/manager;1 {35b9efa2-e42c-45ce-8210-0a13e6f4aadc} -category profile-after-change DataCallManager @mozilla.org/datacall/manager;1 \ No newline at end of file diff --git a/dom/system/gonk/GeolocationUtil.cpp b/dom/system/gonk/GeolocationUtil.cpp deleted file mode 100644 index 99d484a19..000000000 --- a/dom/system/gonk/GeolocationUtil.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GeolocationUtil.h" - -double CalculateDeltaInMeter(double aLat, double aLon, double aLastLat, double aLastLon) -{ - // Use spherical law of cosines to calculate difference - // Not quite as correct as the Haversine but simpler and cheaper - const double radsInDeg = M_PI / 180.0; - const double rNewLat = aLat * radsInDeg; - const double rNewLon = aLon * radsInDeg; - const double rOldLat = aLastLat * radsInDeg; - const double rOldLon = aLastLon * radsInDeg; - // WGS84 equatorial radius of earth = 6378137m - double cosDelta = (sin(rNewLat) * sin(rOldLat)) + - (cos(rNewLat) * cos(rOldLat) * cos(rOldLon - rNewLon)); - if (cosDelta > 1.0) { - cosDelta = 1.0; - } else if (cosDelta < -1.0) { - cosDelta = -1.0; - } - return acos(cosDelta) * 6378137; -} - diff --git a/dom/system/gonk/GeolocationUtil.h b/dom/system/gonk/GeolocationUtil.h deleted file mode 100644 index fde337fb8..000000000 --- a/dom/system/gonk/GeolocationUtil.h +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef GEOLOCATIONUTIL_H -#define GEOLOCATIONUTIL_H - -double CalculateDeltaInMeter(double aLat, double aLon, double aLastLat, double aLastLon); - -#endif - diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.cpp b/dom/system/gonk/GonkGPSGeolocationProvider.cpp deleted file mode 100644 index 9ce6ce2e5..000000000 --- a/dom/system/gonk/GonkGPSGeolocationProvider.cpp +++ /dev/null @@ -1,706 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "GonkGPSGeolocationProvider.h" - -#include -#include -#include - -#include "base/task.h" -#include "GeolocationUtil.h" -#include "mozstumbler/MozStumbler.h" -#include "mozilla/Preferences.h" -#include "mozilla/Services.h" -#include "nsContentUtils.h" -#include "nsGeoPosition.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsINetworkInterface.h" -#include "nsIObserverService.h" -#include "nsJSUtils.h" -#include "nsPrintfCString.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "prtime.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -#ifdef AGPS_TYPE_INVALID -#define AGPS_HAVE_DUAL_APN -#endif - -#define FLUSH_AIDE_DATA 0 - -#undef LOG -#undef ERR -#undef DBG -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "GonkGPSGeolocationProvider", ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "GonkGPSGeolocationProvider", ## args) -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "GonkGPSGeolocationProvider" , ## args) - -using namespace mozilla; -using namespace mozilla::dom; - -static const int kDefaultPeriod = 1000; // ms -static bool gDebug_isLoggingEnabled = false; -static bool gDebug_isGPSLocationIgnored = false; -static const char* kMozSettingsChangedTopic = "mozsettings-changed"; -// Both of these settings can be toggled in the Gaia Developer settings screen. -static const char* kSettingDebugEnabled = "geolocation.debugging.enabled"; -static const char* kSettingDebugGpsIgnored = "geolocation.debugging.gps-locations-ignored"; - -// While most methods of GonkGPSGeolocationProvider should only be -// called from main thread, we deliberately put the Init and ShutdownGPS -// methods off main thread to avoid blocking. -NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider, - nsIGeolocationProvider, - nsIObserver, - nsISettingsServiceCallback) - -/* static */ GonkGPSGeolocationProvider* GonkGPSGeolocationProvider::sSingleton = nullptr; -GpsCallbacks GonkGPSGeolocationProvider::mCallbacks; - - -void -GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location) -{ - if (gDebug_isGPSLocationIgnored) { - return; - } - - class UpdateLocationEvent : public Runnable { - public: - UpdateLocationEvent(nsGeoPosition* aPosition) - : mPosition(aPosition) - {} - NS_IMETHOD Run() override { - RefPtr provider = - GonkGPSGeolocationProvider::GetSingleton(); - nsCOMPtr callback = provider->mLocationCallback; - provider->mLastGPSPosition = mPosition; - if (callback) { - callback->Update(mPosition); - } - return NS_OK; - } - private: - RefPtr mPosition; - }; - - MOZ_ASSERT(location); - - const float kImpossibleAccuracy_m = 0.001; - if (location->accuracy < kImpossibleAccuracy_m) { - return; - } - - RefPtr somewhere = new nsGeoPosition(location->latitude, - location->longitude, - location->altitude, - location->accuracy, - location->accuracy, - location->bearing, - location->speed, - PR_Now() / PR_USEC_PER_MSEC); - // Note above: Can't use location->timestamp as the time from the satellite is a - // minimum of 16 secs old (see http://leapsecond.com/java/gpsclock.htm). - // All code from this point on expects the gps location to be timestamped with the - // current time, most notably: the geolocation service which respects maximumAge - // set in the DOM JS. - - if (gDebug_isLoggingEnabled) { - DBG("geo: GPS got a fix (%f, %f). accuracy: %f", - location->latitude, - location->longitude, - location->accuracy); - } - - RefPtr event = new UpdateLocationEvent(somewhere); - NS_DispatchToMainThread(event); - -} - -class NotifyObserversGPSTask final : public Runnable -{ -public: - explicit NotifyObserversGPSTask(const char16_t* aData) - : mData(aData) - {} - NS_IMETHOD Run() override { - RefPtr provider = - GonkGPSGeolocationProvider::GetSingleton(); - nsCOMPtr obsService = services::GetObserverService(); - obsService->NotifyObservers(provider, "geolocation-device-events", mData); - return NS_OK; - } -private: - const char16_t* mData; -}; - -void -GonkGPSGeolocationProvider::StatusCallback(GpsStatus* status) -{ - const char* msgStream=0; - switch (status->status) { - case GPS_STATUS_NONE: - msgStream = "geo: GPS_STATUS_NONE\n"; - break; - case GPS_STATUS_SESSION_BEGIN: - msgStream = "geo: GPS_STATUS_SESSION_BEGIN\n"; - break; - case GPS_STATUS_SESSION_END: - msgStream = "geo: GPS_STATUS_SESSION_END\n"; - break; - case GPS_STATUS_ENGINE_ON: - msgStream = "geo: GPS_STATUS_ENGINE_ON\n"; - NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSStarting")); - break; - case GPS_STATUS_ENGINE_OFF: - msgStream = "geo: GPS_STATUS_ENGINE_OFF\n"; - NS_DispatchToMainThread(new NotifyObserversGPSTask(u"GPSShutdown")); - break; - default: - msgStream = "geo: Unknown GPS status\n"; - break; - } - if (gDebug_isLoggingEnabled){ - DBG("%s", msgStream); - } -} - -void -GonkGPSGeolocationProvider::SvStatusCallback(GpsSvStatus* sv_info) -{ - if (gDebug_isLoggingEnabled) { - static int numSvs = 0; - static uint32_t numEphemeris = 0; - static uint32_t numAlmanac = 0; - static uint32_t numUsedInFix = 0; - - unsigned int i = 1; - uint32_t svAlmanacCount = 0; - for (i = 1; i > 0; i <<= 1) { - if (i & sv_info->almanac_mask) { - svAlmanacCount++; - } - } - - uint32_t svEphemerisCount = 0; - for (i = 1; i > 0; i <<= 1) { - if (i & sv_info->ephemeris_mask) { - svEphemerisCount++; - } - } - - uint32_t svUsedCount = 0; - for (i = 1; i > 0; i <<= 1) { - if (i & sv_info->used_in_fix_mask) { - svUsedCount++; - } - } - - // Log the message only if the the status changed. - if (sv_info->num_svs != numSvs || - svAlmanacCount != numAlmanac || - svEphemerisCount != numEphemeris || - svUsedCount != numUsedInFix) { - - LOG( - "geo: Number of SVs have (visibility, almanac, ephemeris): (%d, %d, %d)." - " %d of these SVs were used in fix.\n", - sv_info->num_svs, svAlmanacCount, svEphemerisCount, svUsedCount); - - numSvs = sv_info->num_svs; - numAlmanac = svAlmanacCount; - numEphemeris = svEphemerisCount; - numUsedInFix = svUsedCount; - } - } -} - -void -GonkGPSGeolocationProvider::NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length) -{ - if (gDebug_isLoggingEnabled) { - DBG("NMEA: timestamp:\t%lld, length: %d, %s", timestamp, length, nmea); - } -} - -void -GonkGPSGeolocationProvider::SetCapabilitiesCallback(uint32_t capabilities) -{ - class UpdateCapabilitiesEvent : public Runnable { - public: - UpdateCapabilitiesEvent(uint32_t aCapabilities) - : mCapabilities(aCapabilities) - {} - NS_IMETHOD Run() override { - RefPtr provider = - GonkGPSGeolocationProvider::GetSingleton(); - - provider->mSupportsScheduling = mCapabilities & GPS_CAPABILITY_SCHEDULING; - provider->mSupportsSingleShot = mCapabilities & GPS_CAPABILITY_SINGLE_SHOT; -#ifdef GPS_CAPABILITY_ON_DEMAND_TIME - provider->mSupportsTimeInjection = mCapabilities & GPS_CAPABILITY_ON_DEMAND_TIME; -#endif - return NS_OK; - } - private: - uint32_t mCapabilities; - }; - - NS_DispatchToMainThread(new UpdateCapabilitiesEvent(capabilities)); -} - -void -GonkGPSGeolocationProvider::AcquireWakelockCallback() -{ -} - -void -GonkGPSGeolocationProvider::ReleaseWakelockCallback() -{ -} - -typedef void *(*pthread_func)(void *); - -/** Callback for creating a thread that can call into the JS codes. - */ -pthread_t -GonkGPSGeolocationProvider::CreateThreadCallback(const char* name, void (*start)(void *), void* arg) -{ - pthread_t thread; - pthread_attr_t attr; - - pthread_attr_init(&attr); - - /* Unfortunately pthread_create and the callback disagreed on what - * start function should return. - */ - pthread_create(&thread, &attr, reinterpret_cast(start), arg); - - return thread; -} - -void -GonkGPSGeolocationProvider::RequestUtcTimeCallback() -{ -} - -GonkGPSGeolocationProvider::GonkGPSGeolocationProvider() - : mStarted(false) - , mSupportsScheduling(false) - , mObservingSettingsChange(false) - , mSupportsSingleShot(false) - , mSupportsTimeInjection(false) - , mGpsInterface(nullptr) -{ -} - -GonkGPSGeolocationProvider::~GonkGPSGeolocationProvider() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mStarted, "Must call Shutdown before destruction"); - - sSingleton = nullptr; -} - -already_AddRefed -GonkGPSGeolocationProvider::GetSingleton() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!sSingleton) - sSingleton = new GonkGPSGeolocationProvider(); - - RefPtr provider = sSingleton; - return provider.forget(); -} - -const GpsInterface* -GonkGPSGeolocationProvider::GetGPSInterface() -{ - hw_module_t* module; - - if (hw_get_module(GPS_HARDWARE_MODULE_ID, (hw_module_t const**)&module)) - return nullptr; - - hw_device_t* device; - if (module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device)) - return nullptr; - - gps_device_t* gps_device = (gps_device_t *)device; - const GpsInterface* result = gps_device->get_gps_interface(gps_device); - - if (result->size != sizeof(GpsInterface)) { - return nullptr; - } - return result; -} - -void -GonkGPSGeolocationProvider::RequestSettingValue(const char* aKey) -{ - MOZ_ASSERT(aKey); - nsCOMPtr ss = do_GetService("@mozilla.org/settingsService;1"); - if (!ss) { - MOZ_ASSERT(ss); - return; - } - - nsCOMPtr lock; - nsresult rv = ss->CreateLock(nullptr, getter_AddRefs(lock)); - if (NS_FAILED(rv)) { - ERR("error while createLock setting '%s': %d\n", aKey, uint32_t(rv)); - return; - } - - rv = lock->Get(aKey, this); - if (NS_FAILED(rv)) { - ERR("error while get setting '%s': %d\n", aKey, uint32_t(rv)); - return; - } -} - -void -GonkGPSGeolocationProvider::InjectLocation(double latitude, - double longitude, - float accuracy) -{ - if (gDebug_isLoggingEnabled) { - DBG("injecting location (%f, %f) accuracy: %f", latitude, longitude, accuracy); - } - - MOZ_ASSERT(NS_IsMainThread()); - if (!mGpsInterface) { - return; - } - - mGpsInterface->inject_location(latitude, longitude, accuracy); -} - -void -GonkGPSGeolocationProvider::Init() -{ - // Must not be main thread. Some GPS driver's first init takes very long. - MOZ_ASSERT(!NS_IsMainThread()); - - mGpsInterface = GetGPSInterface(); - if (!mGpsInterface) { - return; - } - - if (!mCallbacks.size) { - mCallbacks.size = sizeof(GpsCallbacks); - mCallbacks.location_cb = LocationCallback; - mCallbacks.status_cb = StatusCallback; - mCallbacks.sv_status_cb = SvStatusCallback; - mCallbacks.nmea_cb = NmeaCallback; - mCallbacks.set_capabilities_cb = SetCapabilitiesCallback; - mCallbacks.acquire_wakelock_cb = AcquireWakelockCallback; - mCallbacks.release_wakelock_cb = ReleaseWakelockCallback; - mCallbacks.create_thread_cb = CreateThreadCallback; - -#ifdef GPS_CAPABILITY_ON_DEMAND_TIME - mCallbacks.request_utc_time_cb = RequestUtcTimeCallback; -#endif - - } - - if (mGpsInterface->init(&mCallbacks) != 0) { - return; - } - - NS_DispatchToMainThread(NewRunnableMethod(this, &GonkGPSGeolocationProvider::StartGPS)); -} - -void -GonkGPSGeolocationProvider::StartGPS() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(mGpsInterface); - - int32_t update = Preferences::GetInt("geo.default.update", kDefaultPeriod); - - int positionMode = GPS_POSITION_MODE_STANDALONE; - - if (!mSupportsScheduling) { - update = kDefaultPeriod; - } - - mGpsInterface->set_position_mode(positionMode, - GPS_POSITION_RECURRENCE_PERIODIC, - update, 0, 0); -#if FLUSH_AIDE_DATA - // Delete cached data - mGpsInterface->delete_aiding_data(GPS_DELETE_ALL); -#endif - - mGpsInterface->start(); -} - - -NS_IMPL_ISUPPORTS(GonkGPSGeolocationProvider::NetworkLocationUpdate, - nsIGeolocationUpdate) - -NS_IMETHODIMP -GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *position) -{ - RefPtr provider = - GonkGPSGeolocationProvider::GetSingleton(); - - nsCOMPtr coords; - position->GetCoords(getter_AddRefs(coords)); - if (!coords) { - return NS_ERROR_FAILURE; - } - - double lat, lon, acc; - coords->GetLatitude(&lat); - coords->GetLongitude(&lon); - coords->GetAccuracy(&acc); - - double delta = -1.0; - - static double sLastMLSPosLat = 0; - static double sLastMLSPosLon = 0; - - if (0 != sLastMLSPosLon || 0 != sLastMLSPosLat) { - delta = CalculateDeltaInMeter(lat, lon, sLastMLSPosLat, sLastMLSPosLon); - } - - sLastMLSPosLat = lat; - sLastMLSPosLon = lon; - - // if the MLS coord change is smaller than this arbitrarily small value - // assume the MLS coord is unchanged, and stick with the GPS location - const double kMinMLSCoordChangeInMeters = 10; - - DOMTimeStamp time_ms = 0; - if (provider->mLastGPSPosition) { - provider->mLastGPSPosition->GetTimestamp(&time_ms); - } - const int64_t diff_ms = (PR_Now() / PR_USEC_PER_MSEC) - time_ms; - - // We want to distinguish between the GPS being inactive completely - // and temporarily inactive. In the former case, we would use a low - // accuracy network location; in the latter, we only want a network - // location that appears to updating with movement. - - const bool isGPSFullyInactive = diff_ms > 1000 * 60 * 2; // two mins - const bool isGPSTempInactive = diff_ms > 1000 * 10; // 10 secs - - if (provider->mLocationCallback) { - if (isGPSFullyInactive || - (isGPSTempInactive && delta > kMinMLSCoordChangeInMeters)) - { - if (gDebug_isLoggingEnabled) { - DBG("Using MLS, GPS age:%fs, MLS Delta:%fm\n", diff_ms / 1000.0, delta); - } - provider->mLocationCallback->Update(position); - } else if (provider->mLastGPSPosition) { - if (gDebug_isLoggingEnabled) { - DBG("Using old GPS age:%fs\n", diff_ms / 1000.0); - } - - // This is a fallback case so that the GPS provider responds with its last - // location rather than waiting for a more recent GPS or network location. - // The service decides if the location is too old, not the provider. - provider->mLocationCallback->Update(provider->mLastGPSPosition); - } - } - provider->InjectLocation(lat, lon, acc); - return NS_OK; -} -NS_IMETHODIMP -GonkGPSGeolocationProvider::NetworkLocationUpdate::NotifyError(uint16_t error) -{ - return NS_OK; -} -NS_IMETHODIMP -GonkGPSGeolocationProvider::Startup() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (mStarted) { - return NS_OK; - } - - RequestSettingValue(kSettingDebugEnabled); - RequestSettingValue(kSettingDebugGpsIgnored); - - // Setup an observer to watch changes to the setting. - nsCOMPtr observerService = services::GetObserverService(); - if (observerService) { - MOZ_ASSERT(!mObservingSettingsChange); - nsresult rv = observerService->AddObserver(this, kMozSettingsChangedTopic, false); - if (NS_FAILED(rv)) { - NS_WARNING("geo: Gonk GPS AddObserver failed"); - } else { - mObservingSettingsChange = true; - } - } - - if (!mInitThread) { - nsresult rv = NS_NewThread(getter_AddRefs(mInitThread)); - NS_ENSURE_SUCCESS(rv, rv); - } - - mInitThread->Dispatch(NewRunnableMethod(this, &GonkGPSGeolocationProvider::Init), - NS_DISPATCH_NORMAL); - - mNetworkLocationProvider = do_CreateInstance("@mozilla.org/geolocation/mls-provider;1"); - if (mNetworkLocationProvider) { - nsresult rv = mNetworkLocationProvider->Startup(); - if (NS_SUCCEEDED(rv)) { - RefPtr update = new NetworkLocationUpdate(); - mNetworkLocationProvider->Watch(update); - } - } - - mStarted = true; - return NS_OK; -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Watch(nsIGeolocationUpdate* aCallback) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mLocationCallback = aCallback; - return NS_OK; -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Shutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!mStarted) { - return NS_OK; - } - - mStarted = false; - if (mNetworkLocationProvider) { - mNetworkLocationProvider->Shutdown(); - mNetworkLocationProvider = nullptr; - } - - nsCOMPtr obs = services::GetObserverService(); - if (obs) { - nsresult rv; - rv = obs->RemoveObserver(this, kMozSettingsChangedTopic); - if (NS_FAILED(rv)) { - NS_WARNING("geo: Gonk GPS mozsettings RemoveObserver failed"); - } else { - mObservingSettingsChange = false; - } - } - - mInitThread->Dispatch(NewRunnableMethod(this, &GonkGPSGeolocationProvider::ShutdownGPS), - NS_DISPATCH_NORMAL); - - return NS_OK; -} - -void -GonkGPSGeolocationProvider::ShutdownGPS() -{ - MOZ_ASSERT(!mStarted, "Should only be called after Shutdown"); - - if (mGpsInterface) { - mGpsInterface->stop(); - mGpsInterface->cleanup(); - } -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::SetHighAccuracy(bool) -{ - return NS_OK; -} - -namespace { -int -ConvertToGpsNetworkType(int aNetworkInterfaceType) -{ - switch (aNetworkInterfaceType) { - case nsINetworkInfo::NETWORK_TYPE_WIFI: - return AGPS_RIL_NETWORK_TYPE_WIFI; - case nsINetworkInfo::NETWORK_TYPE_MOBILE: - return AGPS_RIL_NETWORK_TYPE_MOBILE; - case nsINetworkInfo::NETWORK_TYPE_MOBILE_MMS: - return AGPS_RIL_NETWORK_TYPE_MOBILE_MMS; - case nsINetworkInfo::NETWORK_TYPE_MOBILE_SUPL: - return AGPS_RIL_NETWORK_TYPE_MOBILE_SUPL; - case nsINetworkInfo::NETWORK_TYPE_MOBILE_DUN: - return AGPS_RIL_NETWORK_TTYPE_MOBILE_DUN; - default: - NS_WARNING(nsPrintfCString("Unknown network type mapping %d", - aNetworkInterfaceType).get()); - return -1; - } -} -} // namespace - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!strcmp(aTopic, kMozSettingsChangedTopic)) { - // Read changed setting value - RootedDictionary setting(RootingCx()); - if (!WrappedJSToDictionary(aSubject, setting)) { - return NS_OK; - } - - if (setting.mKey.EqualsASCII(kSettingDebugGpsIgnored)) { - LOG("received mozsettings-changed: ignoring\n"); - gDebug_isGPSLocationIgnored = - setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; - if (gDebug_isLoggingEnabled) { - DBG("GPS ignored %d\n", gDebug_isGPSLocationIgnored); - } - return NS_OK; - } else if (setting.mKey.EqualsASCII(kSettingDebugEnabled)) { - LOG("received mozsettings-changed: logging\n"); - gDebug_isLoggingEnabled = - setting.mValue.isBoolean() ? setting.mValue.toBoolean() : false; - return NS_OK; - } - } - - return NS_OK; -} - -/** nsISettingsServiceCallback **/ - -NS_IMETHODIMP -GonkGPSGeolocationProvider::Handle(const nsAString& aName, - JS::Handle aResult) -{ - return NS_OK; -} - -NS_IMETHODIMP -GonkGPSGeolocationProvider::HandleError(const nsAString& aErrorMessage) -{ - return NS_OK; -} diff --git a/dom/system/gonk/GonkGPSGeolocationProvider.h b/dom/system/gonk/GonkGPSGeolocationProvider.h deleted file mode 100644 index 514398edf..000000000 --- a/dom/system/gonk/GonkGPSGeolocationProvider.h +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GonkGPSGeolocationProvider_h -#define GonkGPSGeolocationProvider_h - -#include // for GpsInterface -#include "nsCOMPtr.h" -#include "nsIGeolocationProvider.h" -#include "nsIObserver.h" -#include "nsIDOMGeoPosition.h" -#include "nsISettingsService.h" - -class nsIThread; - -#define GONK_GPS_GEOLOCATION_PROVIDER_CID \ -{ 0x48525ec5, 0x5a7f, 0x490a, { 0x92, 0x77, 0xba, 0x66, 0xe0, 0xd2, 0x2c, 0x8b } } - -#define GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID \ -"@mozilla.org/gonk-gps-geolocation-provider;1" - -class GonkGPSGeolocationProvider : public nsIGeolocationProvider - , public nsIObserver - , public nsISettingsServiceCallback -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIGEOLOCATIONPROVIDER - NS_DECL_NSIOBSERVER - NS_DECL_NSISETTINGSSERVICECALLBACK - - static already_AddRefed GetSingleton(); - -private: - - /* Client should use GetSingleton() to get the provider instance. */ - GonkGPSGeolocationProvider(); - GonkGPSGeolocationProvider(const GonkGPSGeolocationProvider &); - GonkGPSGeolocationProvider & operator = (const GonkGPSGeolocationProvider &); - virtual ~GonkGPSGeolocationProvider(); - - static void LocationCallback(GpsLocation* location); - static void StatusCallback(GpsStatus* status); - static void SvStatusCallback(GpsSvStatus* sv_info); - static void NmeaCallback(GpsUtcTime timestamp, const char* nmea, int length); - static void SetCapabilitiesCallback(uint32_t capabilities); - static void AcquireWakelockCallback(); - static void ReleaseWakelockCallback(); - static pthread_t CreateThreadCallback(const char* name, void (*start)(void*), void* arg); - static void RequestUtcTimeCallback(); - - static GpsCallbacks mCallbacks; - - void Init(); - void StartGPS(); - void ShutdownGPS(); - void InjectLocation(double latitude, double longitude, float accuracy); - void RequestSettingValue(const char* aKey); - - const GpsInterface* GetGPSInterface(); - - static GonkGPSGeolocationProvider* sSingleton; - - bool mStarted; - - bool mSupportsScheduling; - bool mObservingSettingsChange; - bool mSupportsSingleShot; - bool mSupportsTimeInjection; - - const GpsInterface* mGpsInterface; - nsCOMPtr mLocationCallback; - nsCOMPtr mInitThread; - nsCOMPtr mNetworkLocationProvider; - nsCOMPtr mLastGPSPosition; - - class NetworkLocationUpdate : public nsIGeolocationUpdate - { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSIGEOLOCATIONUPDATE - - NetworkLocationUpdate() {} - - private: - virtual ~NetworkLocationUpdate() {} - }; -}; - -#endif /* GonkGPSGeolocationProvider_h */ diff --git a/dom/system/gonk/MozMtpCommon.h b/dom/system/gonk/MozMtpCommon.h deleted file mode 100644 index 81c0a3a74..000000000 --- a/dom/system/gonk/MozMtpCommon.h +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpcommon_h__ -#define mozilla_system_mozmtpcommon_h__ - -#include "mozilla/Types.h" -#include - -#define USE_DEBUG 0 - -#if USE_DEBUG -#define MTP_DBG(msg, ...) \ - __android_log_print(ANDROID_LOG_DEBUG, "MozMtp", \ - "%s: " msg, __FUNCTION__, ##__VA_ARGS__) -#else -#define MTP_DBG(msg, ...) -#endif - -#define MTP_LOG(msg, ...) \ - __android_log_print(ANDROID_LOG_INFO, "MozMtp", \ - "%s: " msg, __FUNCTION__, ##__VA_ARGS__) - -#define MTP_ERR(msg, ...) \ - __android_log_print(ANDROID_LOG_ERROR, "MozMtp", \ - "%s: " msg, __FUNCTION__, ##__VA_ARGS__) - -#define BEGIN_MTP_NAMESPACE \ - namespace mozilla { namespace system { namespace mtp { -#define END_MTP_NAMESPACE \ - } /* namespace mtp */ } /* namespace system */ } /* namespace mozilla */ -#define USING_MTP_NAMESPACE \ - using namespace mozilla::system::mtp; - -namespace android { - class MOZ_EXPORT MtpServer; - class MOZ_EXPORT MtpStorage; - class MOZ_EXPORT MtpStringBuffer; - class MOZ_EXPORT MtpDatabase; - class MOZ_EXPORT MtpDataPacket; - class MOZ_EXPORT MtpProperty; -} - -#include -#include -#include -#include -#include -#include -#include -#include - -#endif // mozilla_system_mtpcommon_h__ diff --git a/dom/system/gonk/MozMtpDatabase.cpp b/dom/system/gonk/MozMtpDatabase.cpp deleted file mode 100644 index 29fe23e8d..000000000 --- a/dom/system/gonk/MozMtpDatabase.cpp +++ /dev/null @@ -1,1542 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozMtpDatabase.h" -#include "MozMtpServer.h" - -#include "base/message_loop.h" -#include "DeviceStorage.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/AutoRestore.h" -#include "mozilla/Scoped.h" -#include "mozilla/Services.h" -#include "nsIFile.h" -#include "nsIObserverService.h" -#include "nsPrintfCString.h" -#include "nsString.h" -#include "prio.h" - -#include -#include -#include -#include - -using namespace android; -using namespace mozilla; - -namespace mozilla { -MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCloseDir, PRDir, PR_CloseDir) -} - -BEGIN_MTP_NAMESPACE - -static const char* kMtpWatcherNotify = "mtp-watcher-notify"; - -#if 0 -// Some debug code for figuring out deadlocks, if you happen to run into -// that scenario - -class DebugMutexAutoLock: public MutexAutoLock -{ -public: - DebugMutexAutoLock(mozilla::Mutex& aMutex) - : MutexAutoLock(aMutex) - { - MTP_LOG("Mutex acquired"); - } - - ~DebugMutexAutoLock() - { - MTP_LOG("Releasing mutex"); - } -}; -#define MutexAutoLock MTP_LOG("About to enter mutex"); DebugMutexAutoLock - -#endif - -static const char * -ObjectPropertyAsStr(MtpObjectProperty aProperty) -{ - switch (aProperty) { - case MTP_PROPERTY_STORAGE_ID: return "MTP_PROPERTY_STORAGE_ID"; - case MTP_PROPERTY_OBJECT_FORMAT: return "MTP_PROPERTY_OBJECT_FORMAT"; - case MTP_PROPERTY_PROTECTION_STATUS: return "MTP_PROPERTY_PROTECTION_STATUS"; - case MTP_PROPERTY_OBJECT_SIZE: return "MTP_PROPERTY_OBJECT_SIZE"; - case MTP_PROPERTY_OBJECT_FILE_NAME: return "MTP_PROPERTY_OBJECT_FILE_NAME"; - case MTP_PROPERTY_DATE_CREATED: return "MTP_PROPERTY_DATE_CREATED"; - case MTP_PROPERTY_DATE_MODIFIED: return "MTP_PROPERTY_DATE_MODIFIED"; - case MTP_PROPERTY_PARENT_OBJECT: return "MTP_PROPERTY_PARENT_OBJECT"; - case MTP_PROPERTY_PERSISTENT_UID: return "MTP_PROPERTY_PERSISTENT_UID"; - case MTP_PROPERTY_NAME: return "MTP_PROPERTY_NAME"; - case MTP_PROPERTY_DATE_ADDED: return "MTP_PROPERTY_DATE_ADDED"; - case MTP_PROPERTY_WIDTH: return "MTP_PROPERTY_WIDTH"; - case MTP_PROPERTY_HEIGHT: return "MTP_PROPERTY_HEIGHT"; - case MTP_PROPERTY_IMAGE_BIT_DEPTH: return "MTP_PROPERTY_IMAGE_BIT_DEPTH"; - case MTP_PROPERTY_DISPLAY_NAME: return "MTP_PROPERTY_DISPLAY_NAME"; - } - return "MTP_PROPERTY_???"; -} - -static char* -FormatDate(time_t aTime, char *aDateStr, size_t aDateStrSize) -{ - struct tm tm; - localtime_r(&aTime, &tm); - MTP_LOG("(%ld) tm_zone = %s off = %ld", aTime, tm.tm_zone, tm.tm_gmtoff); - strftime(aDateStr, aDateStrSize, "%Y%m%dT%H%M%S", &tm); - return aDateStr; -} - -MozMtpDatabase::MozMtpDatabase() - : mMutex("MozMtpDatabase::mMutex"), - mDb(mMutex), - mStorage(mMutex), - mBeginSendObjectCalled(false) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // We use the index into the array as the handle. Since zero isn't a valid - // index, we stick a dummy entry there. - - RefPtr dummy; - - MutexAutoLock lock(mMutex); - mDb.AppendElement(dummy); -} - -//virtual -MozMtpDatabase::~MozMtpDatabase() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); -} - -void -MozMtpDatabase::AddEntry(DbEntry *entry) -{ - MutexAutoLock lock(mMutex); - - entry->mHandle = GetNextHandle(); - MOZ_ASSERT(mDb.Length() == entry->mHandle); - mDb.AppendElement(entry); - - MTP_DBG("Handle: 0x%08x Parent: 0x%08x Path:'%s'", - entry->mHandle, entry->mParent, entry->mPath.get()); -} - -void -MozMtpDatabase::AddEntryAndNotify(DbEntry* entry, RefCountedMtpServer* aMtpServer) -{ - AddEntry(entry); - aMtpServer->sendObjectAdded(entry->mHandle); -} - -void -MozMtpDatabase::DumpEntries(const char* aLabel) -{ - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - MTP_LOG("%s: numEntries = %d", aLabel, numEntries); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr entry = mDb[entryIndex]; - if (entry) { - MTP_LOG("%s: mDb[%d]: mHandle: 0x%08x mParent: 0x%08x StorageID: 0x%08x path: '%s'", - aLabel, entryIndex, entry->mHandle, entry->mParent, entry->mStorageID, entry->mPath.get()); - } else { - MTP_LOG("%s: mDb[%2d]: entry is NULL", aLabel, entryIndex); - } - } -} - -MtpObjectHandle -MozMtpDatabase::FindEntryByPath(const nsACString& aPath) -{ - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr entry = mDb[entryIndex]; - if (entry && entry->mPath.Equals(aPath)) { - return entryIndex; - } - } - return 0; -} - -already_AddRefed -MozMtpDatabase::GetEntry(MtpObjectHandle aHandle) -{ - MutexAutoLock lock(mMutex); - - RefPtr entry; - - if (aHandle > 0 && aHandle < mDb.Length()) { - entry = mDb[aHandle]; - } - return entry.forget(); -} - -void -MozMtpDatabase::RemoveEntry(MtpObjectHandle aHandle) -{ - MutexAutoLock lock(mMutex); - if (!IsValidHandle(aHandle)) { - return; - } - - RefPtr removedEntry = mDb[aHandle]; - mDb[aHandle] = nullptr; - MTP_DBG("0x%08x removed", aHandle); - // if the entry is not a folder, just return. - if (removedEntry->mObjectFormat != MTP_FORMAT_ASSOCIATION) { - return; - } - - // Find out and remove the children of aHandle. - // Since the index for a directory will always be less than the index of any of its children, - // we can remove the entire subtree in one pass. - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = aHandle+1; entryIndex < numEntries; entryIndex++) { - RefPtr entry = mDb[entryIndex]; - if (entry && IsValidHandle(entry->mParent) && !mDb[entry->mParent]) { - mDb[entryIndex] = nullptr; - MTP_DBG("0x%08x removed", aHandle); - } - } -} - -void -MozMtpDatabase::RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer) -{ - RemoveEntry(aHandle); - aMtpServer->sendObjectRemoved(aHandle); -} - -void -MozMtpDatabase::UpdateEntryAndNotify(MtpObjectHandle aHandle, DeviceStorageFile* aFile, RefCountedMtpServer* aMtpServer) -{ - UpdateEntry(aHandle, aFile); - aMtpServer->sendObjectAdded(aHandle); -} - - -void -MozMtpDatabase::UpdateEntry(MtpObjectHandle aHandle, DeviceStorageFile* aFile) -{ - MutexAutoLock lock(mMutex); - - RefPtr entry = mDb[aHandle]; - - int64_t fileSize = 0; - aFile->mFile->GetFileSize(&fileSize); - entry->mObjectSize = fileSize; - - PRTime dateModifiedMsecs; - // GetLastModifiedTime returns msecs - aFile->mFile->GetLastModifiedTime(&dateModifiedMsecs); - entry->mDateModified = dateModifiedMsecs / PR_MSEC_PER_SEC; - entry->mDateCreated = entry->mDateModified; - entry->mDateAdded = entry->mDateModified; - - #if USE_DEBUG - char dateStr[20]; - MTP_DBG("UpdateEntry (0x%08x file %s) modified (%ld) %s", - entry->mHandle, entry->mPath.get(), - entry->mDateModified, - FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - #endif -} - - -class MtpWatcherNotifyRunnable final : public Runnable -{ -public: - MtpWatcherNotifyRunnable(nsACString& aStorageName, - nsACString& aPath, - const char* aEventType) - : mStorageName(aStorageName), - mPath(aPath), - mEventType(aEventType) - {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - NS_ConvertUTF8toUTF16 storageName(mStorageName); - NS_ConvertUTF8toUTF16 path(mPath); - - RefPtr dsf( - new DeviceStorageFile(NS_LITERAL_STRING(DEVICESTORAGE_SDCARD), - storageName, path)); - NS_ConvertUTF8toUTF16 eventType(mEventType); - nsCOMPtr obs = mozilla::services::GetObserverService(); - - MTP_DBG("Sending mtp-watcher-notify %s %s %s", - mEventType.get(), mStorageName.get(), mPath.get()); - - obs->NotifyObservers(dsf, kMtpWatcherNotify, eventType.get()); - return NS_OK; - } - -private: - nsCString mStorageName; - nsCString mPath; - nsCString mEventType; -}; - -// MtpWatcherNotify is used to tell DeviceStorage when a file was changed -// through the MTP server. -void -MozMtpDatabase::MtpWatcherNotify(DbEntry* aEntry, const char* aEventType) -{ - // This function gets called from the MozMtpServer::mServerThread - MOZ_ASSERT(!NS_IsMainThread()); - - MTP_DBG("file: %s %s", aEntry->mPath.get(), aEventType); - - // Tell interested parties that a file was created, deleted, or modified. - - RefPtr storageEntry; - { - MutexAutoLock lock(mMutex); - - // FindStorage and the mStorage[] access both need to have the mutex held. - StorageArray::index_type storageIndex = FindStorage(aEntry->mStorageID); - if (storageIndex == StorageArray::NoIndex) { - return; - } - storageEntry = mStorage[storageIndex]; - } - - // DeviceStorage wants the storageName and the path relative to the root - // of the storage area, so we need to strip off the storagePath - - nsAutoCString relPath(Substring(aEntry->mPath, - storageEntry->mStoragePath.Length() + 1)); - - RefPtr r = - new MtpWatcherNotifyRunnable(storageEntry->mStorageName, relPath, aEventType); - DebugOnly rv = NS_DispatchToMainThread(r); - MOZ_ASSERT(NS_SUCCEEDED(rv)); -} - -// Called to tell the MTP server about new or deleted files, -void -MozMtpDatabase::MtpWatcherUpdate(RefCountedMtpServer* aMtpServer, - DeviceStorageFile* aFile, - const nsACString& aEventType) -{ - // Runs on the MtpWatcherUpdate->mIOThread (see MozMtpServer.cpp) - MOZ_ASSERT(!NS_IsMainThread()); - - // Figure out which storage the belongs to (if any) - - if (!aFile->mFile) { - // No path - don't bother looking. - return; - } - nsString wideFilePath; - aFile->mFile->GetPath(wideFilePath); - NS_ConvertUTF16toUTF8 filePath(wideFilePath); - - nsCString evtType(aEventType); - MTP_LOG("file %s %s", filePath.get(), evtType.get()); - - MtpObjectHandle entryHandle = FindEntryByPath(filePath); - - if (aEventType.EqualsLiteral("modified")) { - // To update the file information to the newest, we remove the entry for - // the existing file, then re-add the entry for the file. - - if (entryHandle != 0) { - // Update entry for the file and tell MTP. - MTP_LOG("About to update handle 0x%08x file %s", entryHandle, filePath.get()); - UpdateEntryAndNotify(entryHandle, aFile, aMtpServer); - } - else { - // Create entry for the file and tell MTP. - CreateEntryForFileAndNotify(filePath, aFile, aMtpServer); - } - return; - } - - if (aEventType.EqualsLiteral("deleted")) { - if (entryHandle == 0) { - // The entry has already been removed. We can't tell MTP. - return; - } - MTP_LOG("About to call sendObjectRemoved Handle 0x%08x file %s", entryHandle, filePath.get()); - RemoveEntryAndNotify(entryHandle, aMtpServer); - return; - } -} - -nsCString -MozMtpDatabase::BaseName(const nsCString& path) -{ - nsCOMPtr file; - NS_NewNativeLocalFile(path, false, getter_AddRefs(file)); - if (file) { - nsCString leafName; - file->GetNativeLeafName(leafName); - return leafName; - } - return path; -} - -static nsCString -GetPathWithoutFileName(const nsCString& aFullPath) -{ - nsCString path; - - int32_t offset = aFullPath.RFindChar('/'); - if (offset != kNotFound) { - // The trailing slash will be as part of 'path' - path = StringHead(aFullPath, offset + 1); - } - - MTP_LOG("returning '%s'", path.get()); - - return path; -} - -void -MozMtpDatabase::CreateEntryForFileAndNotify(const nsACString& aPath, - DeviceStorageFile* aFile, - RefCountedMtpServer* aMtpServer) -{ - // Find the StorageID that this path corresponds to. - - nsCString remainder; - MtpStorageID storageID = FindStorageIDFor(aPath, remainder); - if (storageID == 0) { - // The path in question isn't for a storage area we're monitoring. - nsCString path(aPath); - return; - } - - bool exists = false; - aFile->mFile->Exists(&exists); - if (!exists) { - // File doesn't exist, no sense telling MTP about it. - // This could happen if Device Storage created and deleted a file right - // away. Since the notifications wind up being async, the file might - // not exist any more. - return; - } - - // Now walk the remaining directories, finding or creating as required. - - MtpObjectHandle parent = MTP_PARENT_ROOT; - bool doFind = true; - int32_t offset = aPath.Length() - remainder.Length(); - int32_t slash; - - do { - nsDependentCSubstring component; - slash = aPath.FindChar('/', offset); - if (slash == kNotFound) { - component.Rebind(aPath, 0, aPath.Length()); - } else { - component.Rebind(aPath, 0 , slash); - } - if (doFind) { - MtpObjectHandle entryHandle = FindEntryByPath(component); - if (entryHandle != 0) { - // We found an entry. - parent = entryHandle; - offset = slash + 1 ; - continue; - } - } - - // We've got a directory component that doesn't exist. This means that all - // further subdirectories won't exist either, so we can skip searching - // for them. - doFind = false; - - // This directory and the file don't exist, create them - - RefPtr entry = new DbEntry; - - entry->mStorageID = storageID; - entry->mObjectName = Substring(aPath, offset, slash - offset); - entry->mParent = parent; - entry->mDisplayName = entry->mObjectName; - entry->mPath = component; - - if (slash == kNotFound) { - // No slash - this is the file component - entry->mObjectFormat = MTP_FORMAT_DEFINED; - - int64_t fileSize = 0; - aFile->mFile->GetFileSize(&fileSize); - entry->mObjectSize = fileSize; - - // Note: Even though PRTime records usec, GetLastModifiedTime returns - // msecs. - PRTime dateModifiedMsecs; - aFile->mFile->GetLastModifiedTime(&dateModifiedMsecs); - entry->mDateModified = dateModifiedMsecs / PR_MSEC_PER_SEC; - } else { - // Found a slash, this makes this a directory component - entry->mObjectFormat = MTP_FORMAT_ASSOCIATION; - entry->mObjectSize = 0; - time(&entry->mDateModified); - } - entry->mDateCreated = entry->mDateModified; - entry->mDateAdded = entry->mDateModified; - - AddEntryAndNotify(entry, aMtpServer); - MTP_LOG("About to call sendObjectAdded Handle 0x%08x file %s", entry->mHandle, entry->mPath.get()); - - parent = entry->mHandle; - offset = slash + 1; - } while (slash != kNotFound); - - return; -} - -void -MozMtpDatabase::AddDirectory(MtpStorageID aStorageID, - const char* aPath, - MtpObjectHandle aParent) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - ScopedCloseDir dir; - - if (!(dir = PR_OpenDir(aPath))) { - MTP_ERR("Unable to open directory '%s'", aPath); - return; - } - - PRDirEntry* dirEntry; - while ((dirEntry = PR_ReadDir(dir, PR_SKIP_BOTH))) { - nsPrintfCString filename("%s/%s", aPath, dirEntry->name); - PRFileInfo64 fileInfo; - if (PR_GetFileInfo64(filename.get(), &fileInfo) != PR_SUCCESS) { - MTP_ERR("Unable to retrieve file information for '%s'", filename.get()); - continue; - } - - RefPtr entry = new DbEntry; - - entry->mStorageID = aStorageID; - entry->mParent = aParent; - entry->mObjectName = dirEntry->name; - entry->mDisplayName = dirEntry->name; - entry->mPath = filename; - - // PR_GetFileInfo64 returns timestamps in usecs - entry->mDateModified = fileInfo.modifyTime / PR_USEC_PER_SEC; - entry->mDateCreated = fileInfo.creationTime / PR_USEC_PER_SEC; - time(&entry->mDateAdded); - - if (fileInfo.type == PR_FILE_FILE) { - entry->mObjectFormat = MTP_FORMAT_DEFINED; - //TODO: Check how 64-bit filesize are dealt with - entry->mObjectSize = fileInfo.size; - AddEntry(entry); - } else if (fileInfo.type == PR_FILE_DIRECTORY) { - entry->mObjectFormat = MTP_FORMAT_ASSOCIATION; - entry->mObjectSize = 0; - AddEntry(entry); - AddDirectory(aStorageID, filename.get(), entry->mHandle); - } - } -} - -MozMtpDatabase::StorageArray::index_type -MozMtpDatabase::FindStorage(MtpStorageID aStorageID) -{ - // Currently, this routine is called from MozMtpDatabase::RemoveStorage - // and MozMtpDatabase::MtpWatcherNotify, which both hold mMutex. - - StorageArray::size_type numStorages = mStorage.Length(); - StorageArray::index_type storageIndex; - - for (storageIndex = 0; storageIndex < numStorages; storageIndex++) { - RefPtr storage = mStorage[storageIndex]; - if (storage->mStorageID == aStorageID) { - return storageIndex; - } - } - return StorageArray::NoIndex; -} - -// Find the storage ID for the storage area that contains aPath. -MtpStorageID -MozMtpDatabase::FindStorageIDFor(const nsACString& aPath, nsCSubstring& aRemainder) -{ - MutexAutoLock lock(mMutex); - - aRemainder.Truncate(); - - StorageArray::size_type numStorages = mStorage.Length(); - StorageArray::index_type storageIndex; - - for (storageIndex = 0; storageIndex < numStorages; storageIndex++) { - RefPtr storage = mStorage[storageIndex]; - if (StringHead(aPath, storage->mStoragePath.Length()).Equals(storage->mStoragePath)) { - if (aPath.Length() == storage->mStoragePath.Length()) { - return storage->mStorageID; - } - if (aPath[storage->mStoragePath.Length()] == '/') { - aRemainder = Substring(aPath, storage->mStoragePath.Length() + 1); - return storage->mStorageID; - } - } - } - return 0; -} - -void -MozMtpDatabase::AddStorage(MtpStorageID aStorageID, - const char* aPath, - const char* aName) -{ - // This is called on the IOThread from MozMtpStorage::StorageAvailable - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - MTP_DBG("StorageID: 0x%08x aPath: '%s' aName: '%s'", - aStorageID, aPath, aName); - - PRFileInfo fileInfo; - if (PR_GetFileInfo(aPath, &fileInfo) != PR_SUCCESS) { - MTP_ERR("'%s' doesn't exist", aPath); - return; - } - if (fileInfo.type != PR_FILE_DIRECTORY) { - MTP_ERR("'%s' isn't a directory", aPath); - return; - } - - RefPtr storageEntry = new StorageEntry; - - storageEntry->mStorageID = aStorageID; - storageEntry->mStoragePath = aPath; - storageEntry->mStorageName = aName; - { - MutexAutoLock lock(mMutex); - mStorage.AppendElement(storageEntry); - } - - AddDirectory(aStorageID, aPath, MTP_PARENT_ROOT); - { - MutexAutoLock lock(mMutex); - MTP_LOG("added %d items from tree '%s'", mDb.Length(), aPath); - } -} - -void -MozMtpDatabase::RemoveStorage(MtpStorageID aStorageID) -{ - MutexAutoLock lock(mMutex); - - // This is called on the IOThread from MozMtpStorage::StorageAvailable - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr entry = mDb[entryIndex]; - if (entry && entry->mStorageID == aStorageID) { - mDb[entryIndex] = nullptr; - } - } - StorageArray::index_type storageIndex = FindStorage(aStorageID); - if (storageIndex != StorageArray::NoIndex) { - mStorage.RemoveElementAt(storageIndex); - } -} - -// called from SendObjectInfo to reserve a database entry for the incoming file -//virtual -MtpObjectHandle -MozMtpDatabase::beginSendObject(const char* aPath, - MtpObjectFormat aFormat, - MtpObjectHandle aParent, - MtpStorageID aStorageID, - uint64_t aSize, - time_t aModified) -{ - // If MtpServer::doSendObjectInfo receives a request with a parent of - // MTP_PARENT_ROOT, then it fills in aPath with the fully qualified path - // and then passes in a parent of zero. - - if (aParent == 0) { - // Undo what doSendObjectInfo did - aParent = MTP_PARENT_ROOT; - } - - RefPtr entry = new DbEntry; - - entry->mStorageID = aStorageID; - entry->mParent = aParent; - entry->mPath = aPath; - entry->mObjectName = BaseName(entry->mPath); - entry->mDisplayName = entry->mObjectName; - entry->mObjectFormat = aFormat; - entry->mObjectSize = aSize; - - if (aModified != 0) { - // Currently, due to the way that parseDateTime is coded in - // frameworks/av/media/mtp/MtpUtils.cpp, aModified winds up being the number - // of seconds from the epoch in local time, rather than UTC time. So we - // need to convert it back to being relative to UTC since that's what linux - // expects time_t to contain. - // - // In more concrete testable terms, if the host parses 2015-08-02 02:22:00 - // as a local time in the Pacific timezone, aModified will come to us as - // 1438482120. - // - // What we want is what mktime would pass us with the same date. Using python - // (because its simple) with the current timezone set to be America/Vancouver: - // - // >>> import time - // >>> time.mktime((2015, 8, 2, 2, 22, 0, 0, 0, -1)) - // 1438507320.0 - // >>> time.localtime(1438507320) - // time.struct_time(tm_year=2015, tm_mon=8, tm_mday=2, tm_hour=2, tm_min=22, tm_sec=0, tm_wday=6, tm_yday=214, tm_isdst=1) - // - // Currently, when a file has a modification time of 2015-08-22 02:22:00 PDT - // then aModified will come in as 1438482120 which corresponds to - // 2015-08-22 02:22:00 UTC - - struct tm tm; - if (gmtime_r(&aModified, &tm) != NULL) { - // GMT always comes back with tm_isdst = 0, so we set it to -1 in order - // to have mktime figure out dst based on the date. - tm.tm_isdst = -1; - aModified = mktime(&tm); - if (aModified == (time_t)-1) { - aModified = 0; - } - } else { - aModified = 0; - } - } - if (aModified == 0) { - // The ubuntu host doesn't pass in the modified/created times in the - // SENDOBJECT packet, so aModified winds up being zero. About the best - // we can do with that is to use the current time. - time(&aModified); - } - - // And just an FYI for anybody else looking at timestamps. Under OSX you - // need to use the Android File Transfer program to copy files into the - // phone. That utility passes in both date modified and date created - // timestamps, but they're both equal to the time that the file was copied - // and not the times that are associated with the files. - - // Now we have aModified in a traditional time_t format, which is the number - // of seconds from the UTC epoch. - - entry->mDateModified = aModified; - entry->mDateCreated = entry->mDateModified; - entry->mDateAdded = entry->mDateModified; - - AddEntry(entry); - - #if USE_DEBUG - char dateStr[20]; - MTP_LOG("Handle: 0x%08x Parent: 0x%08x Path: '%s' aModified %ld %s", - entry->mHandle, aParent, aPath, aModified, - FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - #endif - - mBeginSendObjectCalled = true; - return entry->mHandle; -} - -// called to report success or failure of the SendObject file transfer -// success should signal a notification of the new object's creation, -// failure should remove the database entry created in beginSendObject - -//virtual -void -MozMtpDatabase::endSendObject(const char* aPath, - MtpObjectHandle aHandle, - MtpObjectFormat aFormat, - bool aSucceeded) -{ - MTP_LOG("Handle: 0x%08x Path: '%s'", aHandle, aPath); - - if (aSucceeded) { - RefPtr entry = GetEntry(aHandle); - if (entry) { - // The android MTP server only copies the data in, it doesn't set the - // modified timestamp, so we do that here. - - struct utimbuf new_times; - struct stat sb; - - char dateStr[20]; - MTP_LOG("Path: '%s' setting modified time to (%ld) %s", - entry->mPath.get(), entry->mDateModified, - FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - - stat(entry->mPath.get(), &sb); - new_times.actime = sb.st_atime; // Preserve atime - new_times.modtime = entry->mDateModified; - utime(entry->mPath.get(), &new_times); - - MtpWatcherNotify(entry, "modified"); - } - } else { - RemoveEntry(aHandle); - } - mBeginSendObjectCalled = false; -} - -//virtual -MtpObjectHandleList* -MozMtpDatabase::getObjectList(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent) -{ - MTP_LOG("StorageID: 0x%08x Format: 0x%04x Parent: 0x%08x", - aStorageID, aFormat, aParent); - - // aStorageID == 0xFFFFFFFF for all storage - // aFormat == 0 for all formats - // aParent == 0xFFFFFFFF for objects with no parents - // aParent == 0 for all objects - - //TODO: Optimize - - UniquePtr list(new MtpObjectHandleList()); - - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr entry = mDb[entryIndex]; - if (entry && - (aStorageID == 0xFFFFFFFF || entry->mStorageID == aStorageID) && - (aFormat == 0 || entry->mObjectFormat == aFormat) && - (aParent == 0 || entry->mParent == aParent)) { - list->push(entry->mHandle); - } - } - MTP_LOG(" returning %d items", list->size()); - return list.release(); -} - -//virtual -int -MozMtpDatabase::getNumObjects(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent) -{ - MTP_LOG(""); - - // aStorageID == 0xFFFFFFFF for all storage - // aFormat == 0 for all formats - // aParent == 0xFFFFFFFF for objects with no parents - // aParent == 0 for all objects - - int count = 0; - - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIndex; - for (entryIndex = 1; entryIndex < numEntries; entryIndex++) { - RefPtr entry = mDb[entryIndex]; - if (entry && - (aStorageID == 0xFFFFFFFF || entry->mStorageID == aStorageID) && - (aFormat == 0 || entry->mObjectFormat == aFormat) && - (aParent == 0 || entry->mParent == aParent)) { - count++; - } - } - - MTP_LOG(" returning %d items", count); - return count; -} - -//virtual -MtpObjectFormatList* -MozMtpDatabase::getSupportedPlaybackFormats() -{ - static const uint16_t init_data[] = {MTP_FORMAT_UNDEFINED, MTP_FORMAT_ASSOCIATION, - MTP_FORMAT_TEXT, MTP_FORMAT_HTML, MTP_FORMAT_WAV, - MTP_FORMAT_MP3, MTP_FORMAT_MPEG, MTP_FORMAT_EXIF_JPEG, - MTP_FORMAT_TIFF_EP, MTP_FORMAT_BMP, MTP_FORMAT_GIF, - MTP_FORMAT_PNG, MTP_FORMAT_TIFF, MTP_FORMAT_WMA, - MTP_FORMAT_OGG, MTP_FORMAT_AAC, MTP_FORMAT_MP4_CONTAINER, - MTP_FORMAT_MP2, MTP_FORMAT_3GP_CONTAINER, MTP_FORMAT_FLAC}; - - MtpObjectFormatList *list = new MtpObjectFormatList(); - list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data)); - - MTP_LOG("returning Supported Playback Formats"); - return list; -} - -//virtual -MtpObjectFormatList* -MozMtpDatabase::getSupportedCaptureFormats() -{ - static const uint16_t init_data[] = {MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG}; - - MtpObjectFormatList *list = new MtpObjectFormatList(); - list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data)); - MTP_LOG("returning MTP_FORMAT_ASSOCIATION, MTP_FORMAT_PNG"); - return list; -} - -static const MtpObjectProperty sSupportedObjectProperties[] = -{ - MTP_PROPERTY_STORAGE_ID, - MTP_PROPERTY_OBJECT_FORMAT, - MTP_PROPERTY_PROTECTION_STATUS, // UINT16 - always 0 - MTP_PROPERTY_OBJECT_SIZE, - MTP_PROPERTY_OBJECT_FILE_NAME, // just the filename - no directory - MTP_PROPERTY_NAME, - MTP_PROPERTY_DATE_CREATED, - MTP_PROPERTY_DATE_MODIFIED, - MTP_PROPERTY_PARENT_OBJECT, - MTP_PROPERTY_PERSISTENT_UID, - MTP_PROPERTY_DATE_ADDED, -}; - -//virtual -MtpObjectPropertyList* -MozMtpDatabase::getSupportedObjectProperties(MtpObjectFormat aFormat) -{ - MTP_LOG(""); - MtpObjectPropertyList *list = new MtpObjectPropertyList(); - list->appendArray(sSupportedObjectProperties, - MOZ_ARRAY_LENGTH(sSupportedObjectProperties)); - return list; -} - -//virtual -MtpDevicePropertyList* -MozMtpDatabase::getSupportedDeviceProperties() -{ - MTP_LOG(""); - static const uint16_t init_data[] = { MTP_DEVICE_PROPERTY_UNDEFINED }; - - MtpDevicePropertyList *list = new MtpDevicePropertyList(); - list->appendArray(init_data, MOZ_ARRAY_LENGTH(init_data)); - return list; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket) -{ - RefPtr entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Invalid Handle: 0x%08x", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x '%s' Property: %s 0x%08x", - aHandle, entry->mDisplayName.get(), ObjectPropertyAsStr(aProperty), aProperty); - - switch (aProperty) - { - case MTP_PROPERTY_STORAGE_ID: aPacket.putUInt32(entry->mStorageID); break; - case MTP_PROPERTY_PARENT_OBJECT: aPacket.putUInt32(entry->mParent); break; - case MTP_PROPERTY_OBJECT_FORMAT: aPacket.putUInt16(entry->mObjectFormat); break; - case MTP_PROPERTY_OBJECT_SIZE: aPacket.putUInt64(entry->mObjectSize); break; - case MTP_PROPERTY_DISPLAY_NAME: aPacket.putString(entry->mDisplayName.get()); break; - case MTP_PROPERTY_PERSISTENT_UID: - // the same as aPacket.putUInt128 - aPacket.putUInt64(entry->mHandle); - aPacket.putUInt64(entry->mStorageID); - break; - case MTP_PROPERTY_NAME: aPacket.putString(entry->mDisplayName.get()); break; - - default: - MTP_LOG("Invalid Property: 0x%08x", aProperty); - return MTP_RESPONSE_INVALID_OBJECT_PROP_CODE; - } - - return MTP_RESPONSE_OK; -} - -static int -GetTypeOfObjectProp(MtpObjectProperty aProperty) -{ - struct PropertyTableEntry { - MtpObjectProperty property; - int type; - }; - - static const PropertyTableEntry kObjectPropertyTable[] = { - {MTP_PROPERTY_STORAGE_ID, MTP_TYPE_UINT32 }, - {MTP_PROPERTY_OBJECT_FORMAT, MTP_TYPE_UINT16 }, - {MTP_PROPERTY_PROTECTION_STATUS, MTP_TYPE_UINT16 }, - {MTP_PROPERTY_OBJECT_SIZE, MTP_TYPE_UINT64 }, - {MTP_PROPERTY_OBJECT_FILE_NAME, MTP_TYPE_STR }, - {MTP_PROPERTY_DATE_CREATED, MTP_TYPE_STR }, - {MTP_PROPERTY_DATE_MODIFIED, MTP_TYPE_STR }, - {MTP_PROPERTY_PARENT_OBJECT, MTP_TYPE_UINT32 }, - {MTP_PROPERTY_DISPLAY_NAME, MTP_TYPE_STR }, - {MTP_PROPERTY_NAME, MTP_TYPE_STR }, - {MTP_PROPERTY_PERSISTENT_UID, MTP_TYPE_UINT128 }, - {MTP_PROPERTY_DATE_ADDED, MTP_TYPE_STR }, - }; - - int count = sizeof(kObjectPropertyTable) / sizeof(kObjectPropertyTable[0]); - const PropertyTableEntry* entryProp = kObjectPropertyTable; - int type = 0; - - for (int i = 0; i < count; ++i, ++entryProp) { - if (entryProp->property == aProperty) { - type = entryProp->type; - break; - } - } - - return type; -} - -//virtual -MtpResponseCode -MozMtpDatabase::setObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket) -{ - MTP_LOG("Handle: 0x%08x Property: 0x%08x", aHandle, aProperty); - - // Only support file name change - if (aProperty != MTP_PROPERTY_OBJECT_FILE_NAME) { - MTP_ERR("property 0x%x not supported", aProperty); - return MTP_RESPONSE_OBJECT_PROP_NOT_SUPPORTED; - } - - if (GetTypeOfObjectProp(aProperty) != MTP_TYPE_STR) { - MTP_ERR("property type 0x%x not supported", GetTypeOfObjectProp(aProperty)); - return MTP_RESPONSE_GENERAL_ERROR; - } - - RefPtr entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Invalid Handle: 0x%08x", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MtpStringBuffer buf; - aPacket.getString(buf); - - nsDependentCString newFileName(buf); - nsCString newFileFullPath(GetPathWithoutFileName(entry->mPath) + newFileName); - - if (PR_Rename(entry->mPath.get(), newFileFullPath.get()) != PR_SUCCESS) { - MTP_ERR("Failed to rename '%s' to '%s'", - entry->mPath.get(), newFileFullPath.get()); - return MTP_RESPONSE_GENERAL_ERROR; - } - - MTP_LOG("renamed '%s' to '%s'", entry->mPath.get(), newFileFullPath.get()); - - entry->mPath = newFileFullPath; - entry->mObjectName = BaseName(entry->mPath); - entry->mDisplayName = entry->mObjectName; - - return MTP_RESPONSE_OK; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket) -{ - MTP_LOG("(GENERAL ERROR)"); - return MTP_RESPONSE_GENERAL_ERROR; -} - -//virtual -MtpResponseCode -MozMtpDatabase::setDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket) -{ - MTP_LOG("(NOT SUPPORTED)"); - return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; -} - -//virtual -MtpResponseCode -MozMtpDatabase::resetDeviceProperty(MtpDeviceProperty aProperty) -{ - MTP_LOG("(NOT SUPPORTED)"); - return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; -} - -void -MozMtpDatabase::QueryEntries(MozMtpDatabase::MatchType aMatchType, - uint32_t aMatchField1, - uint32_t aMatchField2, - UnprotectedDbArray &result) -{ - MutexAutoLock lock(mMutex); - - ProtectedDbArray::size_type numEntries = mDb.Length(); - ProtectedDbArray::index_type entryIdx; - RefPtr entry; - - result.Clear(); - - switch (aMatchType) { - - case MatchAll: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - if (mDb[entryIdx]) { - result.AppendElement(mDb[entryIdx]); - } - } - break; - - case MatchHandle: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mHandle == aMatchField1) { - result.AppendElement(entry); - // Handles are unique - return the one that we found. - return; - } - } - break; - - case MatchParent: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mParent == aMatchField1) { - result.AppendElement(entry); - } - } - break; - - case MatchFormat: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mObjectFormat == aMatchField1) { - result.AppendElement(entry); - } - } - break; - - case MatchHandleFormat: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mHandle == aMatchField1) { - if (entry->mObjectFormat == aMatchField2) { - result.AppendElement(entry); - } - // Only 1 entry can match my aHandle. So we can return early. - return; - } - } - break; - - case MatchParentFormat: - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - entry = mDb[entryIdx]; - if (entry && entry->mParent == aMatchField1 && entry->mObjectFormat == aMatchField2) { - result.AppendElement(entry); - } - } - break; - - default: - MOZ_ASSERT(!"Invalid MatchType"); - } -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectPropertyList(MtpObjectHandle aHandle, - uint32_t aFormat, - uint32_t aProperty, - int aGroupCode, - int aDepth, - MtpDataPacket& aPacket) -{ - MTP_LOG("Handle: 0x%08x Format: 0x%08x aProperty: 0x%08x aGroupCode: %d aDepth %d", - aHandle, aFormat, aProperty, aGroupCode, aDepth); - - if (aDepth > 1) { - return MTP_RESPONSE_SPECIFICATION_BY_DEPTH_UNSUPPORTED; - } - if (aGroupCode != 0) { - return MTP_RESPONSE_SPECIFICATION_BY_GROUP_UNSUPPORTED; - } - - MatchType matchType = MatchAll; - uint32_t matchField1 = 0; - uint32_t matchField2 = 0; - - // aHandle == 0 implies all objects at the root level - // further specificed by aFormat and/or aDepth - - if (aFormat == 0) { - if (aHandle == 0xffffffff) { - // select all objects - matchType = MatchAll; - } else { - if (aDepth == 1) { - // select objects whose Parent matches aHandle - matchType = MatchParent; - matchField1 = aHandle; - } else { - // select object whose handle matches aHandle - matchType = MatchHandle; - matchField1 = aHandle; - } - } - } else { - if (aHandle == 0xffffffff) { - // select all objects whose format matches aFormat - matchType = MatchFormat; - matchField1 = aFormat; - } else { - if (aDepth == 1) { - // select objects whose Parent is aHandle and format matches aFormat - matchType = MatchParentFormat; - matchField1 = aHandle; - matchField2 = aFormat; - } else { - // select objects whose handle is aHandle and format matches aFormat - matchType = MatchHandleFormat; - matchField1 = aHandle; - matchField2 = aFormat; - } - } - } - - UnprotectedDbArray result; - QueryEntries(matchType, matchField1, matchField2, result); - - const MtpObjectProperty *objectPropertyList; - size_t numObjectProperties = 0; - MtpObjectProperty objectProperty; - - if (aProperty == 0xffffffff) { - // return all supported properties - numObjectProperties = MOZ_ARRAY_LENGTH(sSupportedObjectProperties); - objectPropertyList = sSupportedObjectProperties; - } else { - // return property indicated by aProperty - numObjectProperties = 1; - objectProperty = aProperty; - objectPropertyList = &objectProperty; - } - - UnprotectedDbArray::size_type numEntries = result.Length(); - UnprotectedDbArray::index_type entryIdx; - - char dateStr[20]; - - aPacket.putUInt32(numObjectProperties * numEntries); - for (entryIdx = 0; entryIdx < numEntries; entryIdx++) { - RefPtr entry = result[entryIdx]; - - for (size_t propertyIdx = 0; propertyIdx < numObjectProperties; propertyIdx++) { - aPacket.putUInt32(entry->mHandle); - MtpObjectProperty prop = objectPropertyList[propertyIdx]; - aPacket.putUInt16(prop); - switch (prop) { - - case MTP_PROPERTY_STORAGE_ID: - aPacket.putUInt16(MTP_TYPE_UINT32); - aPacket.putUInt32(entry->mStorageID); - break; - - case MTP_PROPERTY_PARENT_OBJECT: - aPacket.putUInt16(MTP_TYPE_UINT32); - aPacket.putUInt32(entry->mParent); - break; - - case MTP_PROPERTY_PERSISTENT_UID: - aPacket.putUInt16(MTP_TYPE_UINT128); - // the same as aPacket.putUInt128 - aPacket.putUInt64(entry->mHandle); - aPacket.putUInt64(entry->mStorageID); - break; - - case MTP_PROPERTY_OBJECT_FORMAT: - aPacket.putUInt16(MTP_TYPE_UINT16); - aPacket.putUInt16(entry->mObjectFormat); - break; - - case MTP_PROPERTY_OBJECT_SIZE: - aPacket.putUInt16(MTP_TYPE_UINT64); - aPacket.putUInt64(entry->mObjectSize); - break; - - case MTP_PROPERTY_OBJECT_FILE_NAME: - case MTP_PROPERTY_NAME: - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(entry->mObjectName.get()); - break; - - case MTP_PROPERTY_PROTECTION_STATUS: - aPacket.putUInt16(MTP_TYPE_UINT16); - aPacket.putUInt16(0); // 0 = No Protection - break; - - case MTP_PROPERTY_DATE_CREATED: { - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(FormatDate(entry->mDateCreated, dateStr, sizeof(dateStr))); - MTP_LOG("mDateCreated: (%ld) %s", entry->mDateCreated, dateStr); - break; - } - - case MTP_PROPERTY_DATE_MODIFIED: { - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(FormatDate(entry->mDateModified, dateStr, sizeof(dateStr))); - MTP_LOG("mDateModified: (%ld) %s", entry->mDateModified, dateStr); - break; - } - - case MTP_PROPERTY_DATE_ADDED: { - aPacket.putUInt16(MTP_TYPE_STR); - aPacket.putString(FormatDate(entry->mDateAdded, dateStr, sizeof(dateStr))); - MTP_LOG("mDateAdded: (%ld) %s", entry->mDateAdded, dateStr); - break; - } - - default: - MTP_ERR("Unrecognized property code: %u", prop); - return MTP_RESPONSE_GENERAL_ERROR; - } - } - } - return MTP_RESPONSE_OK; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectInfo(MtpObjectHandle aHandle, - MtpObjectInfo& aInfo) -{ - RefPtr entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Handle 0x%08x is invalid", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x Display:'%s' Object:'%s'", aHandle, entry->mDisplayName.get(), entry->mObjectName.get()); - - aInfo.mHandle = aHandle; - aInfo.mStorageID = entry->mStorageID; - aInfo.mFormat = entry->mObjectFormat; - aInfo.mProtectionStatus = 0x0; - - if (entry->mObjectSize > 0xFFFFFFFFuLL) { - aInfo.mCompressedSize = 0xFFFFFFFFuLL; - } else { - aInfo.mCompressedSize = entry->mObjectSize; - } - - aInfo.mThumbFormat = MTP_FORMAT_UNDEFINED; - aInfo.mThumbCompressedSize = 0; - aInfo.mThumbPixWidth = 0; - aInfo.mThumbPixHeight = 0; - aInfo.mImagePixWidth = 0; - aInfo.mImagePixHeight = 0; - aInfo.mImagePixDepth = 0; - aInfo.mParent = entry->mParent; - aInfo.mAssociationType = 0; - aInfo.mAssociationDesc = 0; - aInfo.mSequenceNumber = 0; - aInfo.mName = ::strdup(entry->mObjectName.get()); - aInfo.mDateCreated = entry->mDateCreated; - aInfo.mDateModified = entry->mDateModified; - - MTP_LOG("aInfo.mDateCreated = %ld entry->mDateCreated = %ld", - aInfo.mDateCreated, entry->mDateCreated); - MTP_LOG("aInfo.mDateModified = %ld entry->mDateModified = %ld", - aInfo.mDateModified, entry->mDateModified); - - aInfo.mKeywords = ::strdup("fxos,touch"); - - return MTP_RESPONSE_OK; -} - -//virtual -void* -MozMtpDatabase::getThumbnail(MtpObjectHandle aHandle, size_t& aOutThumbSize) -{ - MTP_LOG("Handle: 0x%08x (returning nullptr)", aHandle); - - aOutThumbSize = 0; - - return nullptr; -} - -//virtual -MtpResponseCode -MozMtpDatabase::getObjectFilePath(MtpObjectHandle aHandle, - MtpString& aOutFilePath, - int64_t& aOutFileLength, - MtpObjectFormat& aOutFormat) -{ - RefPtr entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Handle 0x%08x is invalid", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x FilePath: '%s'", aHandle, entry->mPath.get()); - - aOutFilePath = entry->mPath.get(); - aOutFileLength = entry->mObjectSize; - aOutFormat = entry->mObjectFormat; - - return MTP_RESPONSE_OK; -} - -//virtual -MtpResponseCode -MozMtpDatabase::deleteFile(MtpObjectHandle aHandle) -{ - RefPtr entry = GetEntry(aHandle); - if (!entry) { - MTP_ERR("Invalid Handle: 0x%08x", aHandle); - return MTP_RESPONSE_INVALID_OBJECT_HANDLE; - } - - MTP_LOG("Handle: 0x%08x '%s'", aHandle, entry->mPath.get()); - - // File deletion will happen in lower level implementation. - // The only thing we need to do is removing the entry from the db. - RemoveEntry(aHandle); - - // Tell Device Storage that the file is gone. - MtpWatcherNotify(entry, "deleted"); - - return MTP_RESPONSE_OK; -} - -#if 0 -//virtual -MtpResponseCode -MozMtpDatabase::moveFile(MtpObjectHandle aHandle, MtpObjectHandle aNewParent) -{ - MTP_LOG("Handle: 0x%08x NewParent: 0x%08x", aHandle, aNewParent); - - // change parent - - return MTP_RESPONSE_OK -} - -//virtual -MtpResponseCode -MozMtpDatabase::copyFile(MtpObjectHandle aHandle, MtpObjectHandle aNewParent) -{ - MTP_LOG("Handle: 0x%08x NewParent: 0x%08x", aHandle, aNewParent); - - // duplicate DbEntry - // change parent - - return MTP_RESPONSE_OK -} -#endif - -//virtual -MtpObjectHandleList* -MozMtpDatabase::getObjectReferences(MtpObjectHandle aHandle) -{ - MTP_LOG("Handle: 0x%08x (returning nullptr)", aHandle); - return nullptr; -} - -//virtual -MtpResponseCode -MozMtpDatabase::setObjectReferences(MtpObjectHandle aHandle, - MtpObjectHandleList* aReferences) -{ - MTP_LOG("Handle: 0x%08x (NOT SUPPORTED)", aHandle); - return MTP_RESPONSE_OPERATION_NOT_SUPPORTED; -} - -//virtual -MtpProperty* -MozMtpDatabase::getObjectPropertyDesc(MtpObjectProperty aProperty, - MtpObjectFormat aFormat) -{ - MTP_LOG("Property: %s 0x%08x", ObjectPropertyAsStr(aProperty), aProperty); - - MtpProperty* result = nullptr; - switch (aProperty) - { - case MTP_PROPERTY_PROTECTION_STATUS: - result = new MtpProperty(aProperty, MTP_TYPE_UINT16); - break; - case MTP_PROPERTY_OBJECT_FORMAT: - result = new MtpProperty(aProperty, MTP_TYPE_UINT16, false, aFormat); - break; - case MTP_PROPERTY_STORAGE_ID: - case MTP_PROPERTY_PARENT_OBJECT: - case MTP_PROPERTY_WIDTH: - case MTP_PROPERTY_HEIGHT: - case MTP_PROPERTY_IMAGE_BIT_DEPTH: - result = new MtpProperty(aProperty, MTP_TYPE_UINT32); - break; - case MTP_PROPERTY_OBJECT_SIZE: - result = new MtpProperty(aProperty, MTP_TYPE_UINT64); - break; - case MTP_PROPERTY_DISPLAY_NAME: - case MTP_PROPERTY_NAME: - result = new MtpProperty(aProperty, MTP_TYPE_STR); - break; - case MTP_PROPERTY_OBJECT_FILE_NAME: - result = new MtpProperty(aProperty, MTP_TYPE_STR, true); - break; - case MTP_PROPERTY_DATE_CREATED: - case MTP_PROPERTY_DATE_MODIFIED: - case MTP_PROPERTY_DATE_ADDED: - result = new MtpProperty(aProperty, MTP_TYPE_STR); - result->setFormDateTime(); - break; - case MTP_PROPERTY_PERSISTENT_UID: - result = new MtpProperty(aProperty, MTP_TYPE_UINT128); - break; - default: - break; - } - - return result; -} - -//virtual -MtpProperty* -MozMtpDatabase::getDevicePropertyDesc(MtpDeviceProperty aProperty) -{ - MTP_LOG("(returning MTP_DEVICE_PROPERTY_UNDEFINED)"); - return new MtpProperty(MTP_DEVICE_PROPERTY_UNDEFINED, MTP_TYPE_UNDEFINED); -} - -//virtual -void -MozMtpDatabase::sessionStarted() -{ - MTP_LOG(""); -} - -//virtual -void -MozMtpDatabase::sessionEnded() -{ - MTP_LOG(""); -} - -END_MTP_NAMESPACE diff --git a/dom/system/gonk/MozMtpDatabase.h b/dom/system/gonk/MozMtpDatabase.h deleted file mode 100644 index 8b308762e..000000000 --- a/dom/system/gonk/MozMtpDatabase.h +++ /dev/null @@ -1,288 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpdatabase_h__ -#define mozilla_system_mozmtpdatabase_h__ - -#include "MozMtpCommon.h" - -#include "mozilla/Mutex.h" -#include "mozilla/RefPtr.h" -#include "nsCOMPtr.h" -#include "nsString.h" -#include "nsIThread.h" -#include "nsTArray.h" - -class DeviceStorageFile; - -BEGIN_MTP_NAMESPACE // mozilla::system::mtp - -class RefCountedMtpServer; - -using namespace android; - -class MozMtpDatabase final : public MtpDatabase -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpDatabase) - - MozMtpDatabase(); - - // called from SendObjectInfo to reserve a database entry for the incoming file - virtual MtpObjectHandle beginSendObject(const char* aPath, - MtpObjectFormat aFormat, - MtpObjectHandle aParent, - MtpStorageID aStorageID, - uint64_t aSize, - time_t aModified); - - // called to report success or failure of the SendObject file transfer - // success should signal a notification of the new object's creation, - // failure should remove the database entry created in beginSendObject - virtual void endSendObject(const char* aPath, - MtpObjectHandle aHandle, - MtpObjectFormat aFormat, - bool aSucceeded); - - virtual MtpObjectHandleList* getObjectList(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent); - - virtual int getNumObjects(MtpStorageID aStorageID, - MtpObjectFormat aFormat, - MtpObjectHandle aParent); - - virtual MtpObjectFormatList* getSupportedPlaybackFormats(); - - virtual MtpObjectFormatList* getSupportedCaptureFormats(); - - virtual MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat aFormat); - - virtual MtpDevicePropertyList* getSupportedDeviceProperties(); - - virtual MtpResponseCode getObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode setObjectPropertyValue(MtpObjectHandle aHandle, - MtpObjectProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode getDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode setDevicePropertyValue(MtpDeviceProperty aProperty, - MtpDataPacket& aPacket); - - virtual MtpResponseCode resetDeviceProperty(MtpDeviceProperty aProperty); - - virtual MtpResponseCode getObjectPropertyList(MtpObjectHandle aHandle, - uint32_t aFormat, - uint32_t aProperty, - int aGroupCode, - int aDepth, - MtpDataPacket& aPacket); - - virtual MtpResponseCode getObjectInfo(MtpObjectHandle aHandle, - MtpObjectInfo& aInfo); - - virtual void* getThumbnail(MtpObjectHandle aHandle, size_t& aOutThumbSize); - - virtual MtpResponseCode getObjectFilePath(MtpObjectHandle aHandle, - MtpString& aOutFilePath, - int64_t& aOutFileLength, - MtpObjectFormat& aOutFormat); - - virtual MtpResponseCode deleteFile(MtpObjectHandle aHandle); - - virtual MtpObjectHandleList* getObjectReferences(MtpObjectHandle aHandle); - - virtual MtpResponseCode setObjectReferences(MtpObjectHandle aHandle, - MtpObjectHandleList* aReferences); - - virtual MtpProperty* getObjectPropertyDesc(MtpObjectProperty aProperty, - MtpObjectFormat aFormat); - - virtual MtpProperty* getDevicePropertyDesc(MtpDeviceProperty aProperty); - - virtual void sessionStarted(); - - virtual void sessionEnded(); - - void AddStorage(MtpStorageID aStorageID, const char* aPath, const char *aName); - void RemoveStorage(MtpStorageID aStorageID); - - void MtpWatcherUpdate(RefCountedMtpServer* aMtpServer, - DeviceStorageFile* aFile, - const nsACString& aEventType); - -protected: - virtual ~MozMtpDatabase(); - -private: - - struct DbEntry final - { - DbEntry() - : mHandle(0), - mStorageID(0), - mObjectFormat(MTP_FORMAT_DEFINED), - mParent(0), - mObjectSize(0), - mDateCreated(0), - mDateModified(0), - mDateAdded(0) {} - - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DbEntry) - - MtpObjectHandle mHandle; // uint32_t - MtpStorageID mStorageID; // uint32_t - nsCString mObjectName; - MtpObjectFormat mObjectFormat; // uint16_t - MtpObjectHandle mParent; // uint32_t - uint64_t mObjectSize; - nsCString mDisplayName; - nsCString mPath; - time_t mDateCreated; - time_t mDateModified; - time_t mDateAdded; - - protected: - ~DbEntry() {} - }; - - template - class ProtectedTArray : private nsTArray - { - public: - typedef T elem_type; - typedef typename nsTArray::size_type size_type; - typedef typename nsTArray::index_type index_type; - typedef nsTArray base_type; - - static const index_type NoIndex = base_type::NoIndex; - - ProtectedTArray(mozilla::Mutex& aMutex) - : mMutex(aMutex) - {} - - size_type Length() const - { - // GRR - This assert prints to stderr and won't show up in logcat. - mMutex.AssertCurrentThreadOwns(); - return base_type::Length(); - } - - template - elem_type* AppendElement(const Item& aItem) - { - mMutex.AssertCurrentThreadOwns(); - return base_type::AppendElement(aItem); - } - - void Clear() - { - mMutex.AssertCurrentThreadOwns(); - base_type::Clear(); - } - - void RemoveElementAt(index_type aIndex) - { - mMutex.AssertCurrentThreadOwns(); - base_type::RemoveElementAt(aIndex); - } - - elem_type& operator[](index_type aIndex) - { - mMutex.AssertCurrentThreadOwns(); - return base_type::ElementAt(aIndex); - } - - const elem_type& operator[](index_type aIndex) const - { - mMutex.AssertCurrentThreadOwns(); - return base_type::ElementAt(aIndex); - } - - private: - mozilla::Mutex& mMutex; - }; - typedef nsTArray > UnprotectedDbArray; - typedef ProtectedTArray > ProtectedDbArray; - - struct StorageEntry final - { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(StorageEntry) - - MtpStorageID mStorageID; - nsCString mStoragePath; - nsCString mStorageName; - - protected: - ~StorageEntry() {} - }; - typedef ProtectedTArray > StorageArray; - - enum MatchType - { - MatchAll, - MatchHandle, - MatchParent, - MatchFormat, - MatchHandleFormat, - MatchParentFormat, - }; - - bool IsValidHandle(MtpObjectHandle aHandle) - { - return aHandle > 0 && aHandle < mDb.Length(); - } - - void AddEntry(DbEntry* aEntry); - void AddEntryAndNotify(DbEntry* aEntr, RefCountedMtpServer* aMtpServer); - void DumpEntries(const char* aLabel); - MtpObjectHandle FindEntryByPath(const nsACString& aPath); - already_AddRefed GetEntry(MtpObjectHandle aHandle); - void RemoveEntry(MtpObjectHandle aHandle); - void RemoveEntryAndNotify(MtpObjectHandle aHandle, RefCountedMtpServer* aMtpServer); - void UpdateEntry(MtpObjectHandle aHandle, DeviceStorageFile* aFile); - void UpdateEntryAndNotify(MtpObjectHandle aHandle, DeviceStorageFile* aFile, - RefCountedMtpServer* aMtpServer); - void QueryEntries(MatchType aMatchType, uint32_t aMatchField1, - uint32_t aMatchField2, UnprotectedDbArray& aResult); - - nsCString BaseName(const nsCString& aPath); - - - MtpObjectHandle GetNextHandle() - { - return mDb.Length(); - } - - void AddDirectory(MtpStorageID aStorageID, const char *aPath, MtpObjectHandle aParent); - - void CreateEntryForFileAndNotify(const nsACString& aPath, - DeviceStorageFile* aFile, - RefCountedMtpServer* aMtpServer); - - StorageArray::index_type FindStorage(MtpStorageID aStorageID); - MtpStorageID FindStorageIDFor(const nsACString& aPath, nsCSubstring& aRemainder); - void MtpWatcherNotify(DbEntry* aEntry, const char* aEventType); - - // We need a mutex to protext mDb and mStorage. The MTP server runs on a - // dedicated thread, and it updates/accesses mDb. When files are updated - // through DeviceStorage, we need to update/access mDb and mStorage as well - // (from a non-MTP server thread). - mozilla::Mutex mMutex; - ProtectedDbArray mDb; - StorageArray mStorage; - - bool mBeginSendObjectCalled; -}; - -END_MTP_NAMESPACE - -#endif // mozilla_system_mozmtpdatabase_h__ diff --git a/dom/system/gonk/MozMtpServer.cpp b/dom/system/gonk/MozMtpServer.cpp deleted file mode 100644 index c26b6368b..000000000 --- a/dom/system/gonk/MozMtpServer.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozMtpServer.h" -#include "MozMtpDatabase.h" - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include "base/message_loop.h" -#include "DeviceStorage.h" -#include "mozilla/LazyIdleThread.h" -#include "mozilla/Scoped.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsISupportsImpl.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" - -#include "Volume.h" - -#define DEFAULT_THREAD_TIMEOUT_MS 30000 - -using namespace android; -using namespace mozilla; -BEGIN_MTP_NAMESPACE - -static const char* kMtpWatcherUpdate = "mtp-watcher-update"; - -class MtpWatcherUpdateRunnable final : public Runnable -{ -public: - MtpWatcherUpdateRunnable(MozMtpDatabase* aMozMtpDatabase, - RefCountedMtpServer* aMtpServer, - DeviceStorageFile* aFile, - const nsACString& aEventType) - : mMozMtpDatabase(aMozMtpDatabase), - mMtpServer(aMtpServer), - mFile(aFile), - mEventType(aEventType) - {} - - NS_IMETHOD Run() override - { - // Runs on the MtpWatcherUpdate->mIOThread - MOZ_ASSERT(!NS_IsMainThread()); - - mMozMtpDatabase->MtpWatcherUpdate(mMtpServer, mFile, mEventType); - return NS_OK; - } - -private: - RefPtr mMozMtpDatabase; - RefPtr mMtpServer; - RefPtr mFile; - nsCString mEventType; -}; - -// The MtpWatcherUpdate class listens for mtp-watcher-update events -// and tells the MtpServer about changes made in device storage. -class MtpWatcherUpdate final : public nsIObserver -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - - MtpWatcherUpdate(MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer) - { - MOZ_ASSERT(NS_IsMainThread()); - - mIOThread = new LazyIdleThread( - DEFAULT_THREAD_TIMEOUT_MS, - NS_LITERAL_CSTRING("MtpWatcherUpdate")); - - nsCOMPtr obs = mozilla::services::GetObserverService(); - obs->AddObserver(this, kMtpWatcherUpdate, false); - } - - NS_IMETHOD - Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) - { - MOZ_ASSERT(NS_IsMainThread()); - - if (strcmp(aTopic, kMtpWatcherUpdate)) { - // We're only interested in mtp-watcher-update events - return NS_OK; - } - - NS_ConvertUTF16toUTF8 eventType(aData); - if (!eventType.EqualsLiteral("modified") && !eventType.EqualsLiteral("deleted")) { - // Bug 1074604: Needn't handle "created" event, once file operation - // finished, it would trigger "modified" event. - return NS_OK; - } - - DeviceStorageFile* file = static_cast(aSubject); - file->Dump(kMtpWatcherUpdate); - MTP_LOG("%s: file %s %s", kMtpWatcherUpdate, - NS_LossyConvertUTF16toASCII(file->mPath).get(), - eventType.get()); - - RefPtr mozMtpDatabase = mMozMtpServer->GetMozMtpDatabase(); - RefPtr mtpServer = mMozMtpServer->GetMtpServer(); - - // We're not supposed to perform I/O on the main thread, so punt the - // notification (which will write to /dev/mtp_usb) to an I/O Thread. - - RefPtr r = - new MtpWatcherUpdateRunnable(mozMtpDatabase, mtpServer, file, eventType); - mIOThread->Dispatch(r, NS_DISPATCH_NORMAL); - - return NS_OK; - } - -protected: - ~MtpWatcherUpdate() - { - MOZ_ASSERT(NS_IsMainThread()); - - nsCOMPtr obs = mozilla::services::GetObserverService(); - obs->RemoveObserver(this, kMtpWatcherUpdate); - } - -private: - RefPtr mMozMtpServer; - nsCOMPtr mIOThread; -}; -NS_IMPL_ISUPPORTS(MtpWatcherUpdate, nsIObserver) -static StaticRefPtr sMtpWatcherUpdate; - -class AllocMtpWatcherUpdateRunnable final : public Runnable -{ -public: - AllocMtpWatcherUpdateRunnable(MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer) - {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - sMtpWatcherUpdate = new MtpWatcherUpdate(mMozMtpServer); - return NS_OK; - } -private: - RefPtr mMozMtpServer; -}; - -class FreeMtpWatcherUpdateRunnable final : public Runnable -{ -public: - FreeMtpWatcherUpdateRunnable(MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer) - {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - sMtpWatcherUpdate = nullptr; - return NS_OK; - } -private: - RefPtr mMozMtpServer; -}; - -class MtpServerRunnable : public Runnable -{ -public: - MtpServerRunnable(int aMtpUsbFd, MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer), - mMtpUsbFd(aMtpUsbFd) - { - } - - nsresult Run() - { - RefPtr server = mMozMtpServer->GetMtpServer(); - - DebugOnly rv = - NS_DispatchToMainThread(new AllocMtpWatcherUpdateRunnable(mMozMtpServer)); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - MTP_LOG("MozMtpServer started"); - server->run(); - MTP_LOG("MozMtpServer finished"); - - // server->run will have closed the file descriptor. - mMtpUsbFd.forget(); - - rv = NS_DispatchToMainThread(new FreeMtpWatcherUpdateRunnable(mMozMtpServer)); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - - return NS_OK; - } - -private: - RefPtr mMozMtpServer; - ScopedClose mMtpUsbFd; // We want to hold this open while the server runs -}; - -already_AddRefed -MozMtpServer::GetMtpServer() -{ - RefPtr server = mMtpServer; - return server.forget(); -} - -already_AddRefed -MozMtpServer::GetMozMtpDatabase() -{ - RefPtr db = mMozMtpDatabase; - return db.forget(); -} - -bool -MozMtpServer::Init() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - const char *mtpUsbFilename = "/dev/mtp_usb"; - mMtpUsbFd = open(mtpUsbFilename, O_RDWR); - if (mMtpUsbFd.get() < 0) { - MTP_ERR("open of '%s' failed((%s))", mtpUsbFilename, strerror(errno)); - return false; - } - MTP_LOG("Opened '%s' fd %d", mtpUsbFilename, mMtpUsbFd.get()); - - mMozMtpDatabase = new MozMtpDatabase(); - mMtpServer = new RefCountedMtpServer(mMtpUsbFd.get(), // fd - mMozMtpDatabase.get(), // MtpDatabase - false, // ptp? - AID_MEDIA_RW, // file group - 0664, // file permissions - 0775); // dir permissions - return true; -} - -void -MozMtpServer::Run() -{ - nsresult rv = NS_NewNamedThread("MtpServer", getter_AddRefs(mServerThread)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return; - } - MOZ_ASSERT(mServerThread); - mServerThread->Dispatch(new MtpServerRunnable(mMtpUsbFd.forget(), this), NS_DISPATCH_NORMAL); -} - -END_MTP_NAMESPACE diff --git a/dom/system/gonk/MozMtpServer.h b/dom/system/gonk/MozMtpServer.h deleted file mode 100644 index 4989c25ef..000000000 --- a/dom/system/gonk/MozMtpServer.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpserver_h__ -#define mozilla_system_mozmtpserver_h__ - -#include "MozMtpCommon.h" -#include "MozMtpDatabase.h" - -#include "mozilla/FileUtils.h" - -#include "nsCOMPtr.h" -#include "nsIThread.h" - -BEGIN_MTP_NAMESPACE -using namespace android; - -class RefCountedMtpServer : public MtpServer -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMtpServer) - - RefCountedMtpServer(int aFd, MtpDatabase* aDatabase, bool aPtp, - int aFileGroup, int aFilePerm, int aDirectoryPerm) - : MtpServer(aFd, aDatabase, aPtp, aFileGroup, aFilePerm, aDirectoryPerm) - { - } - -protected: - virtual ~RefCountedMtpServer() {} -}; - -class MozMtpServer -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpServer) - - bool Init(); - void Run(); - - already_AddRefed GetMtpServer(); - already_AddRefed GetMozMtpDatabase(); - -protected: - virtual ~MozMtpServer() {} - -private: - RefPtr mMtpServer; - RefPtr mMozMtpDatabase; - nsCOMPtr mServerThread; - ScopedClose mMtpUsbFd; -}; - -END_MTP_NAMESPACE - -#endif // mozilla_system_mozmtpserver_h__ - - diff --git a/dom/system/gonk/MozMtpStorage.cpp b/dom/system/gonk/MozMtpStorage.cpp deleted file mode 100644 index 9c358a132..000000000 --- a/dom/system/gonk/MozMtpStorage.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozMtpStorage.h" -#include "MozMtpDatabase.h" -#include "MozMtpServer.h" - -#include "base/message_loop.h" -#include "nsXULAppAPI.h" - -BEGIN_MTP_NAMESPACE -using namespace android; - -MozMtpStorage::MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer) - : mMozMtpServer(aMozMtpServer), - mVolume(aVolume) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // The MtpStorageID has the physical volume in the top 16 bits, and the - // logical volumein the lower 16 bits. We treat each volume as a separate - // phsyical storage; - mStorageID = mVolume->Id() << 16 | 1; - - MTP_LOG("Storage constructed for Volume %s mStorageID 0x%08x", - aVolume->NameStr(), mStorageID); - - Volume::RegisterVolumeObserver(this, "MozMtpStorage"); - - // Get things in sync - Notify(mVolume); -} - -MozMtpStorage::~MozMtpStorage() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - MTP_LOG("Storage destructed for Volume %s mStorageID 0x%08x", - mVolume->NameStr(), mStorageID); - - Volume::UnregisterVolumeObserver(this, "MozMtpStorage"); - if (mMtpStorage) { - StorageUnavailable(); - } -} - -// virtual -void -MozMtpStorage::Notify(Volume* const& aVolume) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (aVolume != mVolume) { - // Not our volume - return; - } - Volume::STATE volState = aVolume->State(); - - MTP_LOG("Volume %s mStorageID 0x%08x state changed to %s SharingEnabled: %d", - aVolume->NameStr(), mStorageID, aVolume->StateStr(), - aVolume->IsSharingEnabled()); - - // vol->IsSharingEnabled really only applies to UMS volumes. We assume that - // that as long as MTP is enabled, then all volumes will be shared. The UI - // currently doesn't give us anything more granular than on/off. - - if (mMtpStorage) { - if (volState != nsIVolume::STATE_MOUNTED) { - // The volume is no longer accessible. We need to remove this storage - // from the MTP server - StorageUnavailable(); - } - } else { - if (volState == nsIVolume::STATE_MOUNTED) { - // The volume is accessible. Tell the MTP server. - StorageAvailable(); - } - } -} - -void -MozMtpStorage::StorageAvailable() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - nsCString mountPoint = mVolume->MountPoint(); - - MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MozMtpDatabase", - mVolume->NameStr(), mStorageID, mountPoint.get()); - - RefPtr db = mMozMtpServer->GetMozMtpDatabase(); - db->AddStorage(mStorageID, mountPoint.get(), mVolume->NameStr()); - - MOZ_ASSERT(!mMtpStorage); - - //TODO: Figure out what to do about maxFileSize. - - mMtpStorage.reset(new MtpStorage(mStorageID, // id - mountPoint.get(), // filePath - mVolume->NameStr(), // description - 1024uLL * 1024uLL, // reserveSpace - mVolume->IsHotSwappable(), // removable - 2uLL * 1024uLL * 1024uLL * 1024uLL)); // maxFileSize - RefPtr server = mMozMtpServer->GetMtpServer(); - - MTP_LOG("Adding Volume %s mStorageID 0x%08x mountPoint %s to MtpServer", - mVolume->NameStr(), mStorageID, mountPoint.get()); - server->addStorage(mMtpStorage.get()); -} - -void -MozMtpStorage::StorageUnavailable() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(mMtpStorage); - - MTP_LOG("Removing mStorageID 0x%08x from MtpServer", mStorageID); - - RefPtr server = mMozMtpServer->GetMtpServer(); - server->removeStorage(mMtpStorage.get()); - - MTP_LOG("Removing mStorageID 0x%08x from MozMtpDatabse", mStorageID); - - RefPtr db = mMozMtpServer->GetMozMtpDatabase(); - db->RemoveStorage(mStorageID); - - mMtpStorage = nullptr; -} - -END_MTP_NAMESPACE - - diff --git a/dom/system/gonk/MozMtpStorage.h b/dom/system/gonk/MozMtpStorage.h deleted file mode 100644 index 18d1e04ac..000000000 --- a/dom/system/gonk/MozMtpStorage.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozmtpstorage_h__ -#define mozilla_system_mozmtpstorage_h__ - -#include "MozMtpCommon.h" - -#include "mozilla/UniquePtr.h" - -#include "Volume.h" - -BEGIN_MTP_NAMESPACE -using namespace android; - -class MozMtpServer; - -class MozMtpStorage : public Volume::EventObserver -{ -public: - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MozMtpStorage) - - MozMtpStorage(Volume* aVolume, MozMtpServer* aMozMtpServer); - - typedef nsTArray > Array; - -private: - virtual ~MozMtpStorage(); - virtual void Notify(Volume* const& aEvent); - - void StorageAvailable(); - void StorageUnavailable(); - - RefPtr mMozMtpServer; - UniquePtr mMtpStorage; - RefPtr mVolume; - MtpStorageID mStorageID; -}; - -END_MTP_NAMESPACE - -#endif // mozilla_system_mozmtpstorage_h__ - - diff --git a/dom/system/gonk/NetIdManager.cpp b/dom/system/gonk/NetIdManager.cpp deleted file mode 100644 index 510ec8b22..000000000 --- a/dom/system/gonk/NetIdManager.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "NetIdManager.h" - -NetIdManager::NetIdManager() - : mNextNetId(MIN_NET_ID) -{ -} - -int NetIdManager::getNextNetId() -{ - // Modified from - // http://androidxref.com/5.0.0_r2/xref/frameworks/base/services/ - // core/java/com/android/server/ConnectivityService.java#764 - - int netId = mNextNetId; - if (++mNextNetId > MAX_NET_ID) { - mNextNetId = MIN_NET_ID; - } - - return netId; -} - -void NetIdManager::acquire(const nsString& aInterfaceName, - NetIdInfo* aNetIdInfo) -{ - // Lookup or create one. - if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) { - aNetIdInfo->mNetId = getNextNetId(); - aNetIdInfo->mRefCnt = 1; - } else { - aNetIdInfo->mRefCnt++; - } - - // Update hash and return. - mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo); - - return; -} - -bool NetIdManager::lookup(const nsString& aInterfaceName, - NetIdInfo* aNetIdInfo) -{ - return mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo); -} - -bool NetIdManager::release(const nsString& aInterfaceName, - NetIdInfo* aNetIdInfo) -{ - if (!mInterfaceToNetIdHash.Get(aInterfaceName, aNetIdInfo)) { - return false; // No such key. - } - - aNetIdInfo->mRefCnt--; - - // Update the hash if still be referenced. - if (aNetIdInfo->mRefCnt > 0) { - mInterfaceToNetIdHash.Put(aInterfaceName, *aNetIdInfo); - return true; - } - - // No longer be referenced. Remove the entry. - mInterfaceToNetIdHash.Remove(aInterfaceName); - - return true; -} \ No newline at end of file diff --git a/dom/system/gonk/NetIdManager.h b/dom/system/gonk/NetIdManager.h deleted file mode 100644 index e35d0ecd2..000000000 --- a/dom/system/gonk/NetIdManager.h +++ /dev/null @@ -1,45 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NetIdManager_h -#define NetIdManager_h - -#include "nsString.h" -#include "nsDataHashtable.h" - -// NetId is a logical network identifier defined by netd. -// A network is typically a physical one (i.e. PhysicalNetwork.cpp) -// for netd but it could be a virtual network as well. -// We currently use physical network only and use one-to-one -// network-interface mapping. - -class NetIdManager { -public: - // keep in sync with system/netd/NetworkController.cpp - enum { - MIN_NET_ID = 100, - MAX_NET_ID = 65535, - }; - - // We need to count the number of references since different - // application like data and mms may use the same interface. - struct NetIdInfo { - int mNetId; - int mRefCnt; - }; - -public: - NetIdManager(); - - bool lookup(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo); - void acquire(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo); - bool release(const nsString& aInterfaceName, NetIdInfo* aNetIdInfo); - -private: - int getNextNetId(); - int mNextNetId; - nsDataHashtable mInterfaceToNetIdHash; -}; - -#endif \ No newline at end of file diff --git a/dom/system/gonk/NetworkInterfaceListService.js b/dom/system/gonk/NetworkInterfaceListService.js deleted file mode 100644 index 62fe046aa..000000000 --- a/dom/system/gonk/NetworkInterfaceListService.js +++ /dev/null @@ -1,110 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -const NETWORKLISTSERVICE_CONTRACTID = - "@mozilla.org/network/interface-list-service;1"; -const NETWORKLISTSERVICE_CID = - Components.ID("{3780be6e-7012-4e53-ade6-15212fb88a0d}"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsISyncMessageSender"); - -function NetworkInterfaceListService () { -} - -NetworkInterfaceListService.prototype = { - classID: NETWORKLISTSERVICE_CID, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceListService]), - - getDataInterfaceList: function(aConditions) { - return new NetworkInterfaceList( - cpmm.sendSyncMessage( - 'NetworkInterfaceList:ListInterface', - { - excludeSupl: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_SUPL_INTERFACES) != 0, - excludeMms: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_MMS_INTERFACES) != 0, - excludeIms: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_IMS_INTERFACES) != 0, - excludeDun: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_DUN_INTERFACES) != 0, - excludeFota: (aConditions & - Ci.nsINetworkInterfaceListService. - LIST_NOT_INCLUDE_FOTA_INTERFACES) != 0 - } - )[0]); - } -}; - -function FakeNetworkInfo(aAttributes) { - this.state = aAttributes.state; - this.type = aAttributes.type; - this.name = aAttributes.name; - this.ips = aAttributes.ips; - this.prefixLengths = aAttributes.prefixLengths; - this.gateways = aAttributes.gateways; - this.dnses = aAttributes.dnses; -} -FakeNetworkInfo.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInfo]), - - getAddresses: function (ips, prefixLengths) { - ips.value = this.ips.slice(); - prefixLengths.value = this.prefixLengths.slice(); - - return this.ips.length; - }, - - getGateways: function (count) { - if (count) { - count.value = this.gateways.length; - } - return this.gateways.slice(); - }, - - getDnses: function (count) { - if (count) { - count.value = this.dnses.length; - } - return this.dnses.slice(); - } -}; - -function NetworkInterfaceList (aInterfaceLiterals) { - this._interfaces = []; - for (let entry of aInterfaceLiterals) { - this._interfaces.push(new FakeNetworkInfo(entry)); - } -} - -NetworkInterfaceList.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkInterfaceList]), - - getNumberOfInterface: function() { - return this._interfaces.length; - }, - - getInterfaceInfo: function(index) { - if (!this._interfaces) { - return null; - } - return this._interfaces[index]; - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkInterfaceListService]); - diff --git a/dom/system/gonk/NetworkInterfaceListService.manifest b/dom/system/gonk/NetworkInterfaceListService.manifest deleted file mode 100644 index a827e778f..000000000 --- a/dom/system/gonk/NetworkInterfaceListService.manifest +++ /dev/null @@ -1,17 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# 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. - -# NetworkInterfaceListService.js -component {3780be6e-7012-4e53-ade6-15212fb88a0d} NetworkInterfaceListService.js -contract @mozilla.org/network/interface-list-service;1 {3780be6e-7012-4e53-ade6-15212fb88a0d} diff --git a/dom/system/gonk/NetworkManager.js b/dom/system/gonk/NetworkManager.js deleted file mode 100644 index 9d7a5683e..000000000 --- a/dom/system/gonk/NetworkManager.js +++ /dev/null @@ -1,1219 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); -Cu.import("resource://gre/modules/Promise.jsm"); - -const NETWORKMANAGER_CONTRACTID = "@mozilla.org/network/manager;1"; -const NETWORKMANAGER_CID = - Components.ID("{1ba9346b-53b5-4660-9dc6-58f0b258d0a6}"); - -const DEFAULT_PREFERRED_NETWORK_TYPE = Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET; - -XPCOMUtils.defineLazyGetter(this, "ppmm", function() { - return Cc["@mozilla.org/parentprocessmessagemanager;1"] - .getService(Ci.nsIMessageBroadcaster); -}); - -XPCOMUtils.defineLazyServiceGetter(this, "gDNSService", - "@mozilla.org/network/dns-service;1", - "nsIDNSService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", - "@mozilla.org/network/service;1", - "nsINetworkService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gTetheringService", - "@mozilla.org/tethering/service;1", - "nsITetheringService"); - -const TOPIC_INTERFACE_REGISTERED = "network-interface-registered"; -const TOPIC_INTERFACE_UNREGISTERED = "network-interface-unregistered"; -const TOPIC_ACTIVE_CHANGED = "network-active-changed"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status"; -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -const IPV4_ADDRESS_ANY = "0.0.0.0"; -const IPV6_ADDRESS_ANY = "::0"; - -const IPV4_MAX_PREFIX_LENGTH = 32; -const IPV6_MAX_PREFIX_LENGTH = 128; - -// Connection Type for Network Information API -const CONNECTION_TYPE_CELLULAR = 0; -const CONNECTION_TYPE_BLUETOOTH = 1; -const CONNECTION_TYPE_ETHERNET = 2; -const CONNECTION_TYPE_WIFI = 3; -const CONNECTION_TYPE_OTHER = 4; -const CONNECTION_TYPE_NONE = 5; - -const MANUAL_PROXY_CONFIGURATION = 1; - -var debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- NetworkManager: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -function defineLazyRegExp(obj, name, pattern) { - obj.__defineGetter__(name, function() { - delete obj[name]; - return obj[name] = new RegExp(pattern); - }); -} - -function ExtraNetworkInfo(aNetwork) { - let ips = {}; - let prefixLengths = {}; - aNetwork.info.getAddresses(ips, prefixLengths); - - this.state = aNetwork.info.state; - this.type = aNetwork.info.type; - this.name = aNetwork.info.name; - this.ips = ips.value; - this.prefixLengths = prefixLengths.value; - this.gateways = aNetwork.info.getGateways(); - this.dnses = aNetwork.info.getDnses(); - this.httpProxyHost = aNetwork.httpProxyHost; - this.httpProxyPort = aNetwork.httpProxyPort; - this.mtu = aNetwork.mtu; -} -ExtraNetworkInfo.prototype = { - getAddresses: function(aIps, aPrefixLengths) { - aIps.value = this.ips.slice(); - aPrefixLengths.value = this.prefixLengths.slice(); - - return this.ips.length; - }, - - getGateways: function(aCount) { - if (aCount) { - aCount.value = this.gateways.length; - } - - return this.gateways.slice(); - }, - - getDnses: function(aCount) { - if (aCount) { - aCount.value = this.dnses.length; - } - - return this.dnses.slice(); - } -}; - -function NetworkInterfaceLinks() -{ - this.resetLinks(); -} -NetworkInterfaceLinks.prototype = { - linkRoutes: null, - gateways: null, - interfaceName: null, - extraRoutes: null, - - setLinks: function(linkRoutes, gateways, interfaceName) { - this.linkRoutes = linkRoutes; - this.gateways = gateways; - this.interfaceName = interfaceName; - }, - - resetLinks: function() { - this.linkRoutes = []; - this.gateways = []; - this.interfaceName = ""; - this.extraRoutes = []; - }, - - compareGateways: function(gateways) { - if (this.gateways.length != gateways.length) { - return false; - } - - for (let i = 0; i < this.gateways.length; i++) { - if (this.gateways[i] != gateways[i]) { - return false; - } - } - - return true; - } -}; - -/** - * This component watches for network interfaces changing state and then - * adjusts routes etc. accordingly. - */ -function NetworkManager() { - this.networkInterfaces = {}; - this.networkInterfaceLinks = {}; - - try { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - } catch(ex) { - // Ignore. - } - Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this, false); - Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false); - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - - this.setAndConfigureActive(); - - ppmm.addMessageListener('NetworkInterfaceList:ListInterface', this); - - // Used in resolveHostname(). - defineLazyRegExp(this, "REGEXP_IPV4", "^\\d{1,3}(?:\\.\\d{1,3}){3}$"); - defineLazyRegExp(this, "REGEXP_IPV6", "^[\\da-fA-F]{4}(?::[\\da-fA-F]{4}){7}$"); -} -NetworkManager.prototype = { - classID: NETWORKMANAGER_CID, - classInfo: XPCOMUtils.generateCI({classID: NETWORKMANAGER_CID, - contractID: NETWORKMANAGER_CONTRACTID, - classDescription: "Network Manager", - interfaces: [Ci.nsINetworkManager]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkManager, - Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - // nsIObserver - - observe: function(subject, topic, data) { - switch (topic) { - case TOPIC_PREF_CHANGED: - if (data === PREF_NETWORK_DEBUG_ENABLED) { - updateDebug(); - } else if (data === PREF_MANAGE_OFFLINE_STATUS) { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - debug(PREF_MANAGE_OFFLINE_STATUS + " has changed to " + this._manageOfflineStatus); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.prefs.removeObserver(PREF_MANAGE_OFFLINE_STATUS, this); - Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this); - break; - } - }, - - receiveMessage: function(aMsg) { - switch (aMsg.name) { - case "NetworkInterfaceList:ListInterface": { - let excludeMms = aMsg.json.excludeMms; - let excludeSupl = aMsg.json.excludeSupl; - let excludeIms = aMsg.json.excludeIms; - let excludeDun = aMsg.json.excludeDun; - let excludeFota = aMsg.json.excludeFota; - let interfaces = []; - - for (let key in this.networkInterfaces) { - let network = this.networkInterfaces[key]; - let i = network.info; - if ((i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS && excludeMms) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL && excludeSupl) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS && excludeIms) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN && excludeDun) || - (i.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA && excludeFota)) { - continue; - } - - let ips = {}; - let prefixLengths = {}; - i.getAddresses(ips, prefixLengths); - - interfaces.push({ - state: i.state, - type: i.type, - name: i.name, - ips: ips.value, - prefixLengths: prefixLengths.value, - gateways: i.getGateways(), - dnses: i.getDnses() - }); - } - return interfaces; - } - } - }, - - getNetworkId: function(aNetworkInfo) { - let id = "device"; - try { - if (aNetworkInfo instanceof Ci.nsIRilNetworkInfo) { - let rilInfo = aNetworkInfo.QueryInterface(Ci.nsIRilNetworkInfo); - id = "ril" + rilInfo.serviceId; - } - } catch (e) {} - - return id + "-" + aNetworkInfo.type; - }, - - // nsINetworkManager - - registerNetworkInterface: function(network) { - if (!(network instanceof Ci.nsINetworkInterface)) { - throw Components.Exception("Argument must be nsINetworkInterface.", - Cr.NS_ERROR_INVALID_ARG); - } - let networkId = this.getNetworkId(network.info); - if (networkId in this.networkInterfaces) { - throw Components.Exception("Network with that type already registered!", - Cr.NS_ERROR_INVALID_ARG); - } - this.networkInterfaces[networkId] = network; - this.networkInterfaceLinks[networkId] = new NetworkInterfaceLinks(); - - Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_REGISTERED, null); - debug("Network '" + networkId + "' registered."); - }, - - _addSubnetRoutes: function(network) { - let ips = {}; - let prefixLengths = {}; - let length = network.getAddresses(ips, prefixLengths); - let promises = []; - - for (let i = 0; i < length; i++) { - debug('Adding subnet routes: ' + ips.value[i] + '/' + prefixLengths.value[i]); - promises.push( - gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD, - network.name, ips.value[i], prefixLengths.value[i]) - .catch(aError => { - debug("_addSubnetRoutes error: " + aError); - })); - } - - return Promise.all(promises); - }, - - updateNetworkInterface: function(network) { - if (!(network instanceof Ci.nsINetworkInterface)) { - throw Components.Exception("Argument must be nsINetworkInterface.", - Cr.NS_ERROR_INVALID_ARG); - } - let networkId = this.getNetworkId(network.info); - if (!(networkId in this.networkInterfaces)) { - throw Components.Exception("No network with that type registered.", - Cr.NS_ERROR_INVALID_ARG); - } - debug("Network " + network.info.type + "/" + network.info.name + - " changed state to " + network.info.state); - - // Keep a copy of network in case it is modified while we are updating. - let extNetworkInfo = new ExtraNetworkInfo(network); - - // Note that since Lollipop we need to allocate and initialize - // something through netd, so we add createNetwork/destroyNetwork - // to deal with that explicitly. - - switch (extNetworkInfo.state) { - case Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED: - - this._createNetwork(extNetworkInfo.name) - // Remove pre-created default route and let setAndConfigureActive() - // to set default route only on preferred network - .then(() => this._removeDefaultRoute(extNetworkInfo)) - // Set DNS server as early as possible to prevent from - // premature domain name lookup. - .then(() => this._setDNS(extNetworkInfo)) - .then(() => { - // Add host route for data calls - if (!this.isNetworkTypeMobile(extNetworkInfo.type)) { - return; - } - - let currentInterfaceLinks = this.networkInterfaceLinks[networkId]; - let newLinkRoutes = extNetworkInfo.getDnses().concat( - extNetworkInfo.httpProxyHost); - // If gateways have changed, remove all old routes first. - return this._handleGateways(networkId, extNetworkInfo.getGateways()) - .then(() => this._updateRoutes(currentInterfaceLinks.linkRoutes, - newLinkRoutes, - extNetworkInfo.getGateways(), - extNetworkInfo.name)) - .then(() => currentInterfaceLinks.setLinks(newLinkRoutes, - extNetworkInfo.getGateways(), - extNetworkInfo.name)); - }) - .then(() => { - if (extNetworkInfo.type != - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) { - return; - } - // Dun type is a special case where we add the default route to a - // secondary table. - return this.setSecondaryDefaultRoute(extNetworkInfo); - }) - .then(() => this._addSubnetRoutes(extNetworkInfo)) - .then(() => { - if (extNetworkInfo.mtu <= 0) { - return; - } - - return this._setMtu(extNetworkInfo); - }) - .then(() => this.setAndConfigureActive()) - .then(() => { - // Update data connection when Wifi connected/disconnected - if (extNetworkInfo.type == - Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && this.mRil) { - for (let i = 0; i < this.mRil.numRadioInterfaces; i++) { - this.mRil.getRadioInterface(i).updateRILNetworkInterface(); - } - } - - // Probing the public network accessibility after routing table is ready - CaptivePortalDetectionHelper - .notify(CaptivePortalDetectionHelper.EVENT_CONNECT, - this.activeNetworkInfo); - }) - .then(() => { - // Notify outer modules like MmsService to start the transaction after - // the configuration of the network interface is done. - Services.obs.notifyObservers(network.info, - TOPIC_CONNECTION_STATE_CHANGED, - this.convertConnectionType(network.info)); - }) - .catch(aError => { - debug("updateNetworkInterface error: " + aError); - }); - break; - case Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED: - Promise.resolve() - .then(() => { - if (!this.isNetworkTypeMobile(extNetworkInfo.type)) { - return; - } - // Remove host route for data calls - return this._cleanupAllHostRoutes(networkId); - }) - .then(() => { - if (extNetworkInfo.type != - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) { - return; - } - // Remove secondary default route for dun. - return this.removeSecondaryDefaultRoute(extNetworkInfo); - }) - .then(() => { - if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI || - extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) { - // Remove routing table in /proc/net/route - return this._resetRoutingTable(extNetworkInfo.name); - } - if (extNetworkInfo.type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE) { - return this._removeDefaultRoute(extNetworkInfo) - } - }) - .then(() => { - // Clear http proxy on active network. - if (this.activeNetworkInfo && - extNetworkInfo.type == this.activeNetworkInfo.type) { - this.clearNetworkProxy(); - } - - // Abort ongoing captive portal detection on the wifi interface - CaptivePortalDetectionHelper - .notify(CaptivePortalDetectionHelper.EVENT_DISCONNECT, extNetworkInfo); - }) - .then(() => this.setAndConfigureActive()) - .then(() => { - // Update data connection when Wifi connected/disconnected - if (extNetworkInfo.type == - Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && this.mRil) { - for (let i = 0; i < this.mRil.numRadioInterfaces; i++) { - this.mRil.getRadioInterface(i).updateRILNetworkInterface(); - } - } - }) - .then(() => this._destroyNetwork(extNetworkInfo.name)) - .then(() => { - // Notify outer modules like MmsService to start the transaction after - // the configuration of the network interface is done. - Services.obs.notifyObservers(network.info, - TOPIC_CONNECTION_STATE_CHANGED, - this.convertConnectionType(network.info)); - }) - .catch(aError => { - debug("updateNetworkInterface error: " + aError); - }); - break; - } - }, - - unregisterNetworkInterface: function(network) { - if (!(network instanceof Ci.nsINetworkInterface)) { - throw Components.Exception("Argument must be nsINetworkInterface.", - Cr.NS_ERROR_INVALID_ARG); - } - let networkId = this.getNetworkId(network.info); - if (!(networkId in this.networkInterfaces)) { - throw Components.Exception("No network with that type registered.", - Cr.NS_ERROR_INVALID_ARG); - } - - // This is for in case a network gets unregistered without being - // DISCONNECTED. - if (this.isNetworkTypeMobile(network.info.type)) { - this._cleanupAllHostRoutes(networkId); - } - - delete this.networkInterfaces[networkId]; - - Services.obs.notifyObservers(network.info, TOPIC_INTERFACE_UNREGISTERED, null); - debug("Network '" + networkId + "' unregistered."); - }, - - _manageOfflineStatus: true, - - networkInterfaces: null, - - networkInterfaceLinks: null, - - _networkTypePriorityList: [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET, - Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE], - get networkTypePriorityList() { - return this._networkTypePriorityList; - }, - set networkTypePriorityList(val) { - if (val.length != this._networkTypePriorityList.length) { - throw "Priority list length should equal to " + - this._networkTypePriorityList.length; - } - - // Check if types in new priority list are valid and also make sure there - // are no duplicate types. - let list = [Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET, - Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE]; - while (list.length) { - let type = list.shift(); - if (val.indexOf(type) == -1) { - throw "There is missing network type"; - } - } - - this._networkTypePriorityList = val; - }, - - getPriority: function(type) { - if (this._networkTypePriorityList.indexOf(type) == -1) { - // 0 indicates the lowest priority. - return 0; - } - - return this._networkTypePriorityList.length - - this._networkTypePriorityList.indexOf(type); - }, - - get allNetworkInfo() { - let allNetworkInfo = {}; - - for (let networkId in this.networkInterfaces) { - if (this.networkInterfaces.hasOwnProperty(networkId)) { - allNetworkInfo[networkId] = this.networkInterfaces[networkId].info; - } - } - - return allNetworkInfo; - }, - - _preferredNetworkType: DEFAULT_PREFERRED_NETWORK_TYPE, - get preferredNetworkType() { - return this._preferredNetworkType; - }, - set preferredNetworkType(val) { - if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, - Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) { - throw "Invalid network type"; - } - this._preferredNetworkType = val; - }, - - _activeNetwork: null, - - get activeNetworkInfo() { - return this._activeNetwork && this._activeNetwork.info; - }, - - _overriddenActive: null, - - overrideActive: function(network) { - if ([Ci.nsINetworkInterface.NETWORK_TYPE_WIFI, - Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE, - Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET].indexOf(val) == -1) { - throw "Invalid network type"; - } - - this._overriddenActive = network; - this.setAndConfigureActive(); - }, - - _updateRoutes: function(oldLinks, newLinks, gateways, interfaceName) { - // Returns items that are in base but not in target. - function getDifference(base, target) { - return base.filter(function(i) { return target.indexOf(i) < 0; }); - } - - let addedLinks = getDifference(newLinks, oldLinks); - let removedLinks = getDifference(oldLinks, newLinks); - - if (addedLinks.length === 0 && removedLinks.length === 0) { - return Promise.resolve(); - } - - return this._setHostRoutes(false, removedLinks, interfaceName, gateways) - .then(this._setHostRoutes(true, addedLinks, interfaceName, gateways)); - }, - - _setHostRoutes: function(doAdd, ipAddresses, networkName, gateways) { - let getMaxPrefixLength = (aIp) => { - return aIp.match(this.REGEXP_IPV4) ? IPV4_MAX_PREFIX_LENGTH : IPV6_MAX_PREFIX_LENGTH; - } - - let promises = []; - - ipAddresses.forEach((aIpAddress) => { - let gateway = this.selectGateway(gateways, aIpAddress); - if (gateway) { - promises.push((doAdd) - ? gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_ADD, - networkName, aIpAddress, - getMaxPrefixLength(aIpAddress), gateway) - : gNetworkService.modifyRoute(Ci.nsINetworkService.MODIFY_ROUTE_REMOVE, - networkName, aIpAddress, - getMaxPrefixLength(aIpAddress), gateway)); - } - }); - - return Promise.all(promises); - }, - - isValidatedNetwork: function(aNetworkInfo) { - let isValid = false; - try { - isValid = (this.getNetworkId(aNetworkInfo) in this.networkInterfaces); - } catch (e) { - debug("Invalid network interface: " + e); - } - - return isValid; - }, - - addHostRoute: function(aNetworkInfo, aHost) { - if (!this.isValidatedNetwork(aNetworkInfo)) { - return Promise.reject("Invalid network info."); - } - - return this.resolveHostname(aNetworkInfo, aHost) - .then((ipAddresses) => { - let promises = []; - let networkId = this.getNetworkId(aNetworkInfo); - - ipAddresses.forEach((aIpAddress) => { - let promise = - this._setHostRoutes(true, [aIpAddress], aNetworkInfo.name, aNetworkInfo.getGateways()) - .then(() => this.networkInterfaceLinks[networkId].extraRoutes.push(aIpAddress)); - - promises.push(promise); - }); - - return Promise.all(promises); - }); - }, - - removeHostRoute: function(aNetworkInfo, aHost) { - if (!this.isValidatedNetwork(aNetworkInfo)) { - return Promise.reject("Invalid network info."); - } - - return this.resolveHostname(aNetworkInfo, aHost) - .then((ipAddresses) => { - let promises = []; - let networkId = this.getNetworkId(aNetworkInfo); - - ipAddresses.forEach((aIpAddress) => { - let found = this.networkInterfaceLinks[networkId].extraRoutes.indexOf(aIpAddress); - if (found < 0) { - return; // continue - } - - let promise = - this._setHostRoutes(false, [aIpAddress], aNetworkInfo.name, aNetworkInfo.getGateways()) - .then(() => { - this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1); - }, () => { - // We should remove it even if the operation failed. - this.networkInterfaceLinks[networkId].extraRoutes.splice(found, 1); - }); - promises.push(promise); - }); - - return Promise.all(promises); - }); - }, - - isNetworkTypeSecondaryMobile: function(type) { - return (type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN || - type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA); - }, - - isNetworkTypeMobile: function(type) { - return (type == Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE || - this.isNetworkTypeSecondaryMobile(type)); - }, - - _handleGateways: function(networkId, gateways) { - let currentNetworkLinks = this.networkInterfaceLinks[networkId]; - if (currentNetworkLinks.gateways.length == 0 || - currentNetworkLinks.compareGateways(gateways)) { - return Promise.resolve(); - } - - let currentExtraRoutes = currentNetworkLinks.extraRoutes; - return this._cleanupAllHostRoutes(networkId) - .then(() => { - // If gateways have changed, re-add extra host routes with new gateways. - if (currentExtraRoutes.length > 0) { - this._setHostRoutes(true, - currentExtraRoutes, - currentNetworkLinks.interfaceName, - gateways) - .then(() => { - currentNetworkLinks.extraRoutes = currentExtraRoutes; - }); - } - }); - }, - - _cleanupAllHostRoutes: function(networkId) { - let currentNetworkLinks = this.networkInterfaceLinks[networkId]; - let hostRoutes = currentNetworkLinks.linkRoutes.concat( - currentNetworkLinks.extraRoutes); - - if (hostRoutes.length === 0) { - return Promise.resolve(); - } - - return this._setHostRoutes(false, - hostRoutes, - currentNetworkLinks.interfaceName, - currentNetworkLinks.gateways) - .catch((aError) => { - debug("Error (" + aError + ") on _cleanupAllHostRoutes, keep proceeding."); - }) - .then(() => currentNetworkLinks.resetLinks()); - }, - - selectGateway: function(gateways, host) { - for (let i = 0; i < gateways.length; i++) { - let gateway = gateways[i]; - if (gateway.match(this.REGEXP_IPV4) && host.match(this.REGEXP_IPV4) || - gateway.indexOf(":") != -1 && host.indexOf(":") != -1) { - return gateway; - } - } - return null; - }, - - _setSecondaryRoute: function(aDoAdd, aInterfaceName, aRoute) { - return new Promise((aResolve, aReject) => { - if (aDoAdd) { - gNetworkService.addSecondaryRoute(aInterfaceName, aRoute, - (aSuccess) => { - if (!aSuccess) { - aReject("addSecondaryRoute failed"); - return; - } - aResolve(); - }); - } else { - gNetworkService.removeSecondaryRoute(aInterfaceName, aRoute, - (aSuccess) => { - if (!aSuccess) { - debug("removeSecondaryRoute failed") - } - // Always resolve. - aResolve(); - }); - } - }); - }, - - setSecondaryDefaultRoute: function(network) { - let gateways = network.getGateways(); - let promises = []; - - for (let i = 0; i < gateways.length; i++) { - let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false; - // First, we need to add a host route to the gateway in the secondary - // routing table to make the gateway reachable. Host route takes the max - // prefix and gateway address 'any'. - let hostRoute = { - ip: gateways[i], - prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH, - gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY - }; - // Now we can add the default route through gateway. Default route takes the - // min prefix and destination ip 'any'. - let defaultRoute = { - ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY, - prefix: 0, - gateway: gateways[i] - }; - - let promise = this._setSecondaryRoute(true, network.name, hostRoute) - .then(() => this._setSecondaryRoute(true, network.name, defaultRoute)); - - promises.push(promise); - } - - return Promise.all(promises); - }, - - removeSecondaryDefaultRoute: function(network) { - let gateways = network.getGateways(); - let promises = []; - - for (let i = 0; i < gateways.length; i++) { - let isIPv6 = (gateways[i].indexOf(":") != -1) ? true : false; - // Remove both default route and host route. - let defaultRoute = { - ip: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY, - prefix: 0, - gateway: gateways[i] - }; - let hostRoute = { - ip: gateways[i], - prefix: isIPv6 ? IPV6_MAX_PREFIX_LENGTH : IPV4_MAX_PREFIX_LENGTH, - gateway: isIPv6 ? IPV6_ADDRESS_ANY : IPV4_ADDRESS_ANY - }; - - let promise = this._setSecondaryRoute(false, network.name, defaultRoute) - .then(() => this._setSecondaryRoute(false, network.name, hostRoute)); - - promises.push(promise); - } - - return Promise.all(promises); - }, - - /** - * Determine the active interface and configure it. - */ - setAndConfigureActive: function() { - debug("Evaluating whether active network needs to be changed."); - let oldActive = this._activeNetwork; - - if (this._overriddenActive) { - debug("We have an override for the active network: " + - this._overriddenActive.info.name); - // The override was just set, so reconfigure the network. - if (this._activeNetwork != this._overriddenActive) { - this._activeNetwork = this._overriddenActive; - this._setDefaultRouteAndProxy(this._activeNetwork, oldActive); - Services.obs.notifyObservers(this.activeNetworkInfo, - TOPIC_ACTIVE_CHANGED, null); - } - return; - } - - // The active network is already our preferred type. - if (this.activeNetworkInfo && - this.activeNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED && - this.activeNetworkInfo.type == this._preferredNetworkType) { - debug("Active network is already our preferred type."); - return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive); - } - - // Find a suitable network interface to activate. - this._activeNetwork = null; - let anyConnected = false; - - for (let key in this.networkInterfaces) { - let network = this.networkInterfaces[key]; - if (network.info.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - continue; - } - anyConnected = true; - - // Set active only for default connections. - if (network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_WIFI && - network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE && - network.info.type != Ci.nsINetworkInfo.NETWORK_TYPE_ETHERNET) { - continue; - } - - if (network.info.type == this.preferredNetworkType) { - this._activeNetwork = network; - debug("Found our preferred type of network: " + network.info.name); - break; - } - - // Initialize the active network with the first connected network. - if (!this._activeNetwork) { - this._activeNetwork = network; - continue; - } - - // Compare the prioriy between two network types. If found incoming - // network with higher priority, replace the active network. - if (this.getPriority(this._activeNetwork.type) < this.getPriority(network.type)) { - this._activeNetwork = network; - } - } - - return Promise.resolve() - .then(() => { - if (!this._activeNetwork) { - return Promise.resolve(); - } - - return this._setDefaultRouteAndProxy(this._activeNetwork, oldActive); - }) - .then(() => { - if (this._activeNetwork != oldActive) { - Services.obs.notifyObservers(this.activeNetworkInfo, - TOPIC_ACTIVE_CHANGED, null); - } - - if (this._manageOfflineStatus) { - Services.io.offline = !anyConnected && - (gTetheringService.state === - Ci.nsITetheringService.TETHERING_STATE_INACTIVE); - } - }); - }, - - resolveHostname: function(aNetworkInfo, aHostname) { - // Sanity check for null, undefined and empty string... etc. - if (!aHostname) { - return Promise.reject(new Error("hostname is empty: " + aHostname)); - } - - if (aHostname.match(this.REGEXP_IPV4) || - aHostname.match(this.REGEXP_IPV6)) { - return Promise.resolve([aHostname]); - } - - // Wrap gDNSService.asyncResolveExtended to a promise, which - // resolves with an array of ip addresses or rejects with - // the reason otherwise. - let hostResolveWrapper = aNetId => { - return new Promise((aResolve, aReject) => { - // Callback for gDNSService.asyncResolveExtended. - let onLookupComplete = (aRequest, aRecord, aStatus) => { - if (!Components.isSuccessCode(aStatus)) { - aReject(new Error("Failed to resolve '" + aHostname + - "', with status: " + aStatus)); - return; - } - - let retval = []; - while (aRecord.hasMore()) { - retval.push(aRecord.getNextAddrAsString()); - } - - if (!retval.length) { - aReject(new Error("No valid address after DNS lookup!")); - return; - } - - debug("hostname is resolved: " + aHostname); - debug("Addresses: " + JSON.stringify(retval)); - - aResolve(retval); - }; - - debug('Calling gDNSService.asyncResolveExtended: ' + aNetId + ', ' + aHostname); - gDNSService.asyncResolveExtended(aHostname, - 0, - aNetId, - onLookupComplete, - Services.tm.mainThread); - }); - }; - - // TODO: |getNetId| will be implemented as a sync call in nsINetworkManager - // once Bug 1141903 is landed. - return gNetworkService.getNetId(aNetworkInfo.name) - .then(aNetId => hostResolveWrapper(aNetId)); - }, - - convertConnectionType: function(aNetworkInfo) { - // If there is internal interface change (e.g., MOBILE_MMS, MOBILE_SUPL), - // the function will return null so that it won't trigger type change event - // in NetworkInformation API. - if (aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_WIFI && - aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_MOBILE && - aNetworkInfo.type != Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET) { - return null; - } - - if (aNetworkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED) { - return CONNECTION_TYPE_NONE; - } - - switch (aNetworkInfo.type) { - case Ci.nsINetworkInfo.NETWORK_TYPE_WIFI: - return CONNECTION_TYPE_WIFI; - case Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE: - return CONNECTION_TYPE_CELLULAR; - case Ci.nsINetworkInterface.NETWORK_TYPE_ETHERNET: - return CONNECTION_TYPE_ETHERNET; - } - }, - - _setDNS: function(aNetworkInfo) { - return new Promise((aResolve, aReject) => { - let dnses = aNetworkInfo.getDnses(); - let gateways = aNetworkInfo.getGateways(); - gNetworkService.setDNS(aNetworkInfo.name, dnses.length, dnses, - gateways.length, gateways, (aError) => { - if (aError) { - aReject("setDNS failed"); - return; - } - aResolve(); - }); - }); - }, - - _setMtu: function(aNetworkInfo) { - return new Promise((aResolve, aReject) => { - gNetworkService.setMtu(aNetworkInfo.name, aNetworkInfo.mtu, (aSuccess) => { - if (!aSuccess) { - debug("setMtu failed"); - } - // Always resolve. - aResolve(); - }); - }); - }, - - _createNetwork: function(aInterfaceName) { - return new Promise((aResolve, aReject) => { - gNetworkService.createNetwork(aInterfaceName, (aSuccess) => { - if (!aSuccess) { - aReject("createNetwork failed"); - return; - } - aResolve(); - }); - }); - }, - - _destroyNetwork: function(aInterfaceName) { - return new Promise((aResolve, aReject) => { - gNetworkService.destroyNetwork(aInterfaceName, (aSuccess) => { - if (!aSuccess) { - debug("destroyNetwork failed") - } - // Always resolve. - aResolve(); - }); - }); - }, - - _resetRoutingTable: function(aInterfaceName) { - return new Promise((aResolve, aReject) => { - gNetworkService.resetRoutingTable(aInterfaceName, (aSuccess) => { - if (!aSuccess) { - debug("resetRoutingTable failed"); - } - // Always resolve. - aResolve(); - }); - }); - }, - - _removeDefaultRoute: function(aNetworkInfo) { - return new Promise((aResolve, aReject) => { - let gateways = aNetworkInfo.getGateways(); - gNetworkService.removeDefaultRoute(aNetworkInfo.name, gateways.length, - gateways, (aSuccess) => { - if (!aSuccess) { - debug("removeDefaultRoute failed"); - } - // Always resolve. - aResolve(); - }); - }); - }, - - _setDefaultRouteAndProxy: function(aNetwork, aOldNetwork) { - if (aOldNetwork) { - return this._removeDefaultRoute(aOldNetwork.info) - .then(() => this._setDefaultRouteAndProxy(aNetwork, null)); - } - - return new Promise((aResolve, aReject) => { - let networkInfo = aNetwork.info; - let gateways = networkInfo.getGateways(); - - gNetworkService.setDefaultRoute(networkInfo.name, gateways.length, gateways, - (aSuccess) => { - if (!aSuccess) { - gNetworkService.destroyNetwork(networkInfo.name, function() { - aReject("setDefaultRoute failed"); - }); - return; - } - this.setNetworkProxy(aNetwork); - aResolve(); - }); - }); - }, - - setNetworkProxy: function(aNetwork) { - try { - if (!aNetwork.httpProxyHost || aNetwork.httpProxyHost === "") { - // Sets direct connection to internet. - this.clearNetworkProxy(); - - debug("No proxy support for " + aNetwork.info.name + " network interface."); - return; - } - - debug("Going to set proxy settings for " + aNetwork.info.name + " network interface."); - // Sets manual proxy configuration. - Services.prefs.setIntPref("network.proxy.type", MANUAL_PROXY_CONFIGURATION); - - // Do not use this proxy server for all protocols. - Services.prefs.setBoolPref("network.proxy.share_proxy_settings", false); - Services.prefs.setCharPref("network.proxy.http", aNetwork.httpProxyHost); - Services.prefs.setCharPref("network.proxy.ssl", aNetwork.httpProxyHost); - let port = aNetwork.httpProxyPort === 0 ? 8080 : aNetwork.httpProxyPort; - Services.prefs.setIntPref("network.proxy.http_port", port); - Services.prefs.setIntPref("network.proxy.ssl_port", port); - } catch(ex) { - debug("Exception " + ex + ". Unable to set proxy setting for " + - aNetwork.info.name + " network interface."); - } - }, - - clearNetworkProxy: function() { - debug("Going to clear all network proxy."); - - Services.prefs.clearUserPref("network.proxy.type"); - Services.prefs.clearUserPref("network.proxy.share_proxy_settings"); - Services.prefs.clearUserPref("network.proxy.http"); - Services.prefs.clearUserPref("network.proxy.http_port"); - Services.prefs.clearUserPref("network.proxy.ssl"); - Services.prefs.clearUserPref("network.proxy.ssl_port"); - }, -}; - -var CaptivePortalDetectionHelper = (function() { - - const EVENT_CONNECT = "Connect"; - const EVENT_DISCONNECT = "Disconnect"; - let _ongoingInterface = null; - let _available = ("nsICaptivePortalDetector" in Ci); - let getService = function() { - return Cc['@mozilla.org/toolkit/captive-detector;1'] - .getService(Ci.nsICaptivePortalDetector); - }; - - let _performDetection = function(interfaceName, callback) { - let capService = getService(); - let capCallback = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsICaptivePortalCallback]), - prepare: function() { - capService.finishPreparation(interfaceName); - }, - complete: function(success) { - _ongoingInterface = null; - callback(success); - } - }; - - // Abort any unfinished captive portal detection. - if (_ongoingInterface != null) { - capService.abort(_ongoingInterface); - _ongoingInterface = null; - } - try { - capService.checkCaptivePortal(interfaceName, capCallback); - _ongoingInterface = interfaceName; - } catch (e) { - debug('Fail to detect captive portal due to: ' + e.message); - } - }; - - let _abort = function(interfaceName) { - if (_ongoingInterface !== interfaceName) { - return; - } - - let capService = getService(); - capService.abort(_ongoingInterface); - _ongoingInterface = null; - }; - - return { - EVENT_CONNECT: EVENT_CONNECT, - EVENT_DISCONNECT: EVENT_DISCONNECT, - notify: function(eventType, network) { - switch (eventType) { - case EVENT_CONNECT: - // perform captive portal detection on wifi interface - if (_available && network && - network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { - _performDetection(network.name, function() { - // TODO: bug 837600 - // We can disconnect wifi in here if user abort the login procedure. - }); - } - - break; - case EVENT_DISCONNECT: - if (_available && - network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { - _abort(network.name); - } - break; - } - } - }; -}()); - -XPCOMUtils.defineLazyGetter(NetworkManager.prototype, "mRil", function() { - try { - return Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); - } catch (e) {} - - return null; -}); - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkManager]); diff --git a/dom/system/gonk/NetworkManager.manifest b/dom/system/gonk/NetworkManager.manifest deleted file mode 100644 index 995fa6559..000000000 --- a/dom/system/gonk/NetworkManager.manifest +++ /dev/null @@ -1,3 +0,0 @@ -# NetworkManager.js -component {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} NetworkManager.js -contract @mozilla.org/network/manager;1 {1ba9346b-53b5-4660-9dc6-58f0b258d0a6} diff --git a/dom/system/gonk/NetworkService.js b/dom/system/gonk/NetworkService.js deleted file mode 100644 index 7147f40c7..000000000 --- a/dom/system/gonk/NetworkService.js +++ /dev/null @@ -1,862 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/NetUtil.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/Promise.jsm"); - -const NETWORKSERVICE_CONTRACTID = "@mozilla.org/network/service;1"; -const NETWORKSERVICE_CID = Components.ID("{48c13741-aec9-4a86-8962-432011708261}"); - -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkWorker", - "@mozilla.org/network/worker;1", - "nsINetworkWorker"); - -// 1xx - Requested action is proceeding -const NETD_COMMAND_PROCEEDING = 100; -// 2xx - Requested action has been successfully completed -const NETD_COMMAND_OKAY = 200; -// 4xx - The command is accepted but the requested action didn't -// take place. -const NETD_COMMAND_FAIL = 400; -// 5xx - The command syntax or parameters error -const NETD_COMMAND_ERROR = 500; -// 6xx - Unsolicited broadcasts -const NETD_COMMAND_UNSOLICITED = 600; - -const WIFI_CTRL_INTERFACE = "wl0.1"; - -var debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- NetworkService: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -function netdResponseType(aCode) { - return Math.floor(aCode / 100) * 100; -} - -function isError(aCode) { - let type = netdResponseType(aCode); - return (type !== NETD_COMMAND_PROCEEDING && type !== NETD_COMMAND_OKAY); -} - -function Task(aId, aParams, aSetupFunction) { - this.id = aId; - this.params = aParams; - this.setupFunction = aSetupFunction; -} - -function NetworkWorkerRequestQueue(aNetworkService) { - this.networkService = aNetworkService; - this.tasks = []; -} -NetworkWorkerRequestQueue.prototype = { - runQueue: function() { - if (this.tasks.length === 0) { - return; - } - - let task = this.tasks[0]; - debug("run task id: " + task.id); - - if (typeof task.setupFunction === 'function') { - // If setupFunction returns false, skip sending to Network Worker but call - // handleWorkerMessage() directly with task id, as if the response was - // returned from Network Worker. - if (!task.setupFunction()) { - this.networkService.handleWorkerMessage({id: task.id}); - return; - } - } - - gNetworkWorker.postMessage(task.params); - }, - - enqueue: function(aId, aParams, aSetupFunction) { - debug("enqueue id: " + aId); - this.tasks.push(new Task(aId, aParams, aSetupFunction)); - - if (this.tasks.length === 1) { - this.runQueue(); - } - }, - - dequeue: function(aId) { - debug("dequeue id: " + aId); - - if (!this.tasks.length || this.tasks[0].id != aId) { - debug("Id " + aId + " is not on top of the queue"); - return; - } - - this.tasks.shift(); - if (this.tasks.length > 0) { - // Run queue on the next tick. - Services.tm.currentThread.dispatch(() => { - this.runQueue(); - }, Ci.nsIThread.DISPATCH_NORMAL); - } - } -}; - - -/** - * This component watches for network interfaces changing state and then - * adjusts routes etc. accordingly. - */ -function NetworkService() { - debug("Starting NetworkService."); - - let self = this; - - if (gNetworkWorker) { - let networkListener = { - onEvent: function(aEvent) { - self.handleWorkerMessage(aEvent); - } - }; - gNetworkWorker.start(networkListener); - } - // Callbacks to invoke when a reply arrives from the net_worker. - this.controlCallbacks = Object.create(null); - - this.addedRoutes = new Map(); - this.netWorkerRequestQueue = new NetworkWorkerRequestQueue(this); - this.shutdown = false; - - Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false); - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); -} - -NetworkService.prototype = { - classID: NETWORKSERVICE_CID, - classInfo: XPCOMUtils.generateCI({classID: NETWORKSERVICE_CID, - contractID: NETWORKSERVICE_CONTRACTID, - classDescription: "Network Service", - interfaces: [Ci.nsINetworkService]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsINetworkService, - Ci.nsIObserver]), - - addedRoutes: null, - - shutdown: false, - - // nsIObserver - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case TOPIC_PREF_CHANGED: - if (aData === PREF_NETWORK_DEBUG_ENABLED) { - updateDebug(); - } - break; - case TOPIC_XPCOM_SHUTDOWN: - debug("NetworkService shutdown"); - this.shutdown = true; - if (gNetworkWorker) { - gNetworkWorker.shutdown(); - gNetworkWorker = null; - } - - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this); - break; - } - }, - - // Helpers - - idgen: 0, - controlMessage: function(aParams, aCallback, aSetupFunction) { - if (this.shutdown) { - return; - } - - let id = this.idgen++; - aParams.id = id; - if (aCallback) { - this.controlCallbacks[id] = aCallback; - } - - // For now, we use aSetupFunction to determine if this command needs to be - // queued or not. - if (aSetupFunction) { - this.netWorkerRequestQueue.enqueue(id, aParams, aSetupFunction); - return; - } - - if (gNetworkWorker) { - gNetworkWorker.postMessage(aParams); - } - }, - - handleWorkerMessage: function(aResponse) { - debug("NetworkManager received message from worker: " + JSON.stringify(aResponse)); - let id = aResponse.id; - if (aResponse.broadcast === true) { - Services.obs.notifyObservers(null, aResponse.topic, aResponse.reason); - return; - } - let callback = this.controlCallbacks[id]; - if (callback) { - callback.call(this, aResponse); - delete this.controlCallbacks[id]; - } - - this.netWorkerRequestQueue.dequeue(id); - }, - - // nsINetworkService - - getNetworkInterfaceStats: function(aInterfaceName, aCallback) { - debug("getNetworkInterfaceStats for " + aInterfaceName); - - let file = new FileUtils.File("/proc/net/dev"); - if (!file) { - aCallback.networkStatsAvailable(false, 0, 0, Date.now()); - return; - } - - NetUtil.asyncFetch({ - uri: NetUtil.newURI(file), - loadUsingSystemPrincipal: true - }, function(inputStream, status) { - let rxBytes = 0, - txBytes = 0, - now = Date.now(); - - if (Components.isSuccessCode(status)) { - // Find record for corresponding interface. - let statExpr = /(\S+): +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +(\d+) +\d+ +\d+ +\d+ +\d+ +\d+ +\d+ +\d+/; - let data = - NetUtil.readInputStreamToString(inputStream, inputStream.available()) - .split("\n"); - for (let i = 2; i < data.length; i++) { - let parseResult = statExpr.exec(data[i]); - if (parseResult && parseResult[1] === aInterfaceName) { - rxBytes = parseInt(parseResult[2], 10); - txBytes = parseInt(parseResult[3], 10); - break; - } - } - } - - // netd always return success even interface doesn't exist. - aCallback.networkStatsAvailable(true, rxBytes, txBytes, now); - }); - }, - - setNetworkTetheringAlarm(aEnable, aInterface) { - // Method called when enabling disabling tethering, it checks if there is - // some alarm active and move from interfaceAlarm to globalAlarm because - // interfaceAlarm doens't work in tethering scenario due to forwarding. - debug("setNetworkTetheringAlarm for tethering" + aEnable); - - let filename = aEnable ? "/proc/net/xt_quota/" + aInterface + "Alert" : - "/proc/net/xt_quota/globalAlert"; - - let file = new FileUtils.File(filename); - if (!file) { - return; - } - - NetUtil.asyncFetch({ - uri: NetUtil.newURI(file), - loadUsingSystemPrincipal: true - }, (inputStream, status) => { - if (Components.isSuccessCode(status)) { - let data = NetUtil.readInputStreamToString(inputStream, inputStream.available()) - .split("\n"); - if (data) { - let threshold = parseInt(data[0], 10); - - this._setNetworkTetheringAlarm(aEnable, aInterface, threshold); - } - } - }); - }, - - _setNetworkTetheringAlarm(aEnable, aInterface, aThreshold, aCallback) { - debug("_setNetworkTetheringAlarm for tethering" + aEnable); - - let cmd = aEnable ? "setTetheringAlarm" : "removeTetheringAlarm"; - - let params = { - cmd: cmd, - ifname: aInterface, - threshold: aThreshold, - }; - - this.controlMessage(params, function(aData) { - let code = aData.resultCode; - let reason = aData.resultReason; - let enableString = aEnable ? "Enable" : "Disable"; - debug(enableString + " tethering Alarm result: Code " + code + " reason " + reason); - if (aCallback) { - aCallback.networkUsageAlarmResult(null); - } - }); - }, - - setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) { - if (!aInterfaceName) { - aCallback.networkUsageAlarmResult(-1); - return; - } - - let self = this; - this._disableNetworkInterfaceAlarm(aInterfaceName, function(aResult) { - if (aThreshold < 0) { - if (!isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(null); - return; - } - aCallback.networkUsageAlarmResult(aResult.reason); - return - } - - // Check if tethering is enabled - let params = { - cmd: "getTetheringStatus" - }; - - self.controlMessage(params, function(aResult) { - if (isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(aResult.reason); - return; - } - - if (aResult.resultReason.indexOf('started') == -1) { - // Tethering disabled, set interfaceAlarm - self._setNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback); - return; - } - - // Tethering enabled, set globalAlarm - self._setNetworkTetheringAlarm(true, aInterfaceName, aThreshold, aCallback); - }); - }); - }, - - _setNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) { - debug("setNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes"); - - let params = { - cmd: "setNetworkInterfaceAlarm", - ifname: aInterfaceName, - threshold: aThreshold - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - if (!isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(null); - return; - } - - this._enableNetworkInterfaceAlarm(aInterfaceName, aThreshold, aCallback); - }); - }, - - _enableNetworkInterfaceAlarm: function(aInterfaceName, aThreshold, aCallback) { - debug("enableNetworkInterfaceAlarm for " + aInterfaceName + " at " + aThreshold + "bytes"); - - let params = { - cmd: "enableNetworkInterfaceAlarm", - ifname: aInterfaceName, - threshold: aThreshold - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - if (!isError(aResult.resultCode)) { - aCallback.networkUsageAlarmResult(null); - return; - } - aCallback.networkUsageAlarmResult(aResult.reason); - }); - }, - - _disableNetworkInterfaceAlarm: function(aInterfaceName, aCallback) { - debug("disableNetworkInterfaceAlarm for " + aInterfaceName); - - let params = { - cmd: "disableNetworkInterfaceAlarm", - ifname: aInterfaceName, - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - aCallback(aResult); - }); - }, - - setWifiOperationMode: function(aInterfaceName, aMode, aCallback) { - debug("setWifiOperationMode on " + aInterfaceName + " to " + aMode); - - let params = { - cmd: "setWifiOperationMode", - ifname: aInterfaceName, - mode: aMode - }; - - params.report = true; - - this.controlMessage(params, function(aResult) { - if (isError(aResult.resultCode)) { - aCallback.wifiOperationModeResult("netd command error"); - } else { - aCallback.wifiOperationModeResult(null); - } - }); - }, - - resetRoutingTable: function(aInterfaceName, aCallback) { - let options = { - cmd: "removeNetworkRoute", - ifname: aInterfaceName - }; - - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - setDNS: function(aInterfaceName, aDnsesCount, aDnses, aGatewaysCount, - aGateways, aCallback) { - debug("Going to set DNS to " + aInterfaceName); - let options = { - cmd: "setDNS", - ifname: aInterfaceName, - domain: "mozilla." + aInterfaceName + ".domain", - dnses: aDnses, - gateways: aGateways - }; - this.controlMessage(options, function(aResult) { - aCallback.setDnsResult(aResult.success ? null : aResult.reason); - }); - }, - - setDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) { - debug("Going to change default route to " + aInterfaceName); - let options = { - cmd: "setDefaultRoute", - ifname: aInterfaceName, - gateways: aGateways - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - removeDefaultRoute: function(aInterfaceName, aCount, aGateways, aCallback) { - debug("Remove default route for " + aInterfaceName); - let options = { - cmd: "removeDefaultRoute", - ifname: aInterfaceName, - gateways: aGateways - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - _routeToString: function(aInterfaceName, aHost, aPrefixLength, aGateway) { - return aHost + "-" + aPrefixLength + "-" + aGateway + "-" + aInterfaceName; - }, - - modifyRoute: function(aAction, aInterfaceName, aHost, aPrefixLength, aGateway) { - let command; - - switch (aAction) { - case Ci.nsINetworkService.MODIFY_ROUTE_ADD: - command = 'addHostRoute'; - break; - case Ci.nsINetworkService.MODIFY_ROUTE_REMOVE: - command = 'removeHostRoute'; - break; - default: - debug('Unknown action: ' + aAction); - return Promise.reject(); - } - - let route = this._routeToString(aInterfaceName, aHost, aPrefixLength, aGateway); - let setupFunc = () => { - let count = this.addedRoutes.get(route); - debug(command + ": " + route + " -> " + count); - - // Return false if there is no need to send the command to network worker. - if ((aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD && count) || - (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE && - (!count || count > 1))) { - return false; - } - - return true; - }; - - debug(command + " " + aHost + " on " + aInterfaceName); - let options = { - cmd: command, - ifname: aInterfaceName, - gateway: aGateway, - prefixLength: aPrefixLength, - ip: aHost - }; - - return new Promise((aResolve, aReject) => { - this.controlMessage(options, (aData) => { - let count = this.addedRoutes.get(route); - - // Remove route from addedRoutes on success or failure. - if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_REMOVE) { - if (count > 1) { - this.addedRoutes.set(route, count - 1); - } else { - this.addedRoutes.delete(route); - } - } - - if (aData.error) { - aReject(aData.reason); - return; - } - - if (aAction == Ci.nsINetworkService.MODIFY_ROUTE_ADD) { - this.addedRoutes.set(route, count ? count + 1 : 1); - } - - aResolve(); - }, setupFunc); - }); - }, - - addSecondaryRoute: function(aInterfaceName, aRoute, aCallback) { - debug("Going to add route to secondary table on " + aInterfaceName); - let options = { - cmd: "addSecondaryRoute", - ifname: aInterfaceName, - ip: aRoute.ip, - prefix: aRoute.prefix, - gateway: aRoute.gateway - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - removeSecondaryRoute: function(aInterfaceName, aRoute, aCallback) { - debug("Going to remove route from secondary table on " + aInterfaceName); - let options = { - cmd: "removeSecondaryRoute", - ifname: aInterfaceName, - ip: aRoute.ip, - prefix: aRoute.prefix, - gateway: aRoute.gateway - }; - this.controlMessage(options, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - // Enable/Disable DHCP server. - setDhcpServer: function(aEnabled, aConfig, aCallback) { - if (null === aConfig) { - aConfig = {}; - } - - aConfig.cmd = "setDhcpServer"; - aConfig.enabled = aEnabled; - - this.controlMessage(aConfig, function(aResponse) { - if (!aResponse.success) { - aCallback.dhcpServerResult('Set DHCP server error'); - return; - } - aCallback.dhcpServerResult(null); - }); - }, - - // Enable/disable WiFi tethering by sending commands to netd. - setWifiTethering: function(aEnable, aConfig, aCallback) { - // config should've already contained: - // .ifname - // .internalIfname - // .externalIfname - aConfig.wifictrlinterfacename = WIFI_CTRL_INTERFACE; - aConfig.cmd = "setWifiTethering"; - - // The callback function in controlMessage may not be fired immediately. - this.controlMessage(aConfig, (aData) => { - let code = aData.resultCode; - let reason = aData.resultReason; - let enable = aData.enable; - let enableString = aEnable ? "Enable" : "Disable"; - - debug(enableString + " Wifi tethering result: Code " + code + " reason " + reason); - - this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname); - - if (isError(code)) { - aCallback.wifiTetheringEnabledChange("netd command error"); - } else { - aCallback.wifiTetheringEnabledChange(null); - } - }); - }, - - // Enable/disable USB tethering by sending commands to netd. - setUSBTethering: function(aEnable, aConfig, aCallback) { - aConfig.cmd = "setUSBTethering"; - // The callback function in controlMessage may not be fired immediately. - this.controlMessage(aConfig, (aData) => { - let code = aData.resultCode; - let reason = aData.resultReason; - let enable = aData.enable; - let enableString = aEnable ? "Enable" : "Disable"; - - debug(enableString + " USB tethering result: Code " + code + " reason " + reason); - - this.setNetworkTetheringAlarm(aEnable, aConfig.externalIfname); - - if (isError(code)) { - aCallback.usbTetheringEnabledChange("netd command error"); - } else { - aCallback.usbTetheringEnabledChange(null); - } - }); - }, - - // Switch usb function by modifying property of persist.sys.usb.config. - enableUsbRndis: function(aEnable, aCallback) { - debug("enableUsbRndis: " + aEnable); - - let params = { - cmd: "enableUsbRndis", - enable: aEnable - }; - // Ask net work to report the result when this value is set to true. - if (aCallback) { - params.report = true; - } else { - params.report = false; - } - - // The callback function in controlMessage may not be fired immediately. - //this._usbTetheringAction = TETHERING_STATE_ONGOING; - this.controlMessage(params, function(aData) { - aCallback.enableUsbRndisResult(aData.result, aData.enable); - }); - }, - - updateUpStream: function(aPrevious, aCurrent, aCallback) { - let params = { - cmd: "updateUpStream", - preInternalIfname: aPrevious.internalIfname, - preExternalIfname: aPrevious.externalIfname, - curInternalIfname: aCurrent.internalIfname, - curExternalIfname: aCurrent.externalIfname - }; - - this.controlMessage(params, function(aData) { - let code = aData.resultCode; - let reason = aData.resultReason; - debug("updateUpStream result: Code " + code + " reason " + reason); - aCallback.updateUpStreamResult(!isError(code), aData.curExternalIfname); - }); - }, - - getInterfaces: function(callback) { - let params = { - cmd: "getInterfaces", - isAsync: true - }; - - this.controlMessage(params, function(data) { - debug("getInterfaces result: " + JSON.stringify(data)); - let success = !isError(data.resultCode); - callback.getInterfacesResult(success, data.interfaceList); - }); - }, - - getInterfaceConfig: function(ifname, callback) { - let params = { - cmd: "getInterfaceConfig", - ifname: ifname, - isAsync: true - }; - - this.controlMessage(params, function(data) { - debug("getInterfaceConfig result: " + JSON.stringify(data)); - let success = !isError(data.resultCode); - let result = { ip: data.ipAddr, - prefix: data.prefixLength, - link: data.flag, - mac: data.macAddr }; - callback.getInterfaceConfigResult(success, result); - }); - }, - - setInterfaceConfig: function(config, callback) { - config.cmd = "setInterfaceConfig"; - config.isAsync = true; - - this.controlMessage(config, function(data) { - debug("setInterfaceConfig result: " + JSON.stringify(data)); - let success = !isError(data.resultCode); - callback.setInterfaceConfigResult(success); - }); - }, - - configureInterface: function(aConfig, aCallback) { - let params = { - cmd: "configureInterface", - ifname: aConfig.ifname, - ipaddr: aConfig.ipaddr, - mask: aConfig.mask, - gateway_long: aConfig.gateway, - dns1_long: aConfig.dns1, - dns2_long: aConfig.dns2, - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - dhcpRequest: function(aInterfaceName, aCallback) { - let params = { - cmd: "dhcpRequest", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.dhcpRequestResult(!aResult.error, aResult.error ? null : aResult); - }); - }, - - stopDhcp: function(aInterfaceName, aCallback) { - let params = { - cmd: "stopDhcp", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - enableInterface: function(aInterfaceName, aCallback) { - let params = { - cmd: "enableInterface", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - disableInterface: function(aInterfaceName, aCallback) { - let params = { - cmd: "disableInterface", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - resetConnections: function(aInterfaceName, aCallback) { - let params = { - cmd: "resetConnections", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - createNetwork: function(aInterfaceName, aCallback) { - let params = { - cmd: "createNetwork", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - destroyNetwork: function(aInterfaceName, aCallback) { - let params = { - cmd: "destroyNetwork", - ifname: aInterfaceName - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - }, - - getNetId: function(aInterfaceName) { - let params = { - cmd: "getNetId", - ifname: aInterfaceName - }; - - return new Promise((aResolve, aReject) => { - this.controlMessage(params, result => { - if (result.error) { - aReject(result.reason); - return; - } - aResolve(result.netId); - }); - }); - }, - - setMtu: function (aInterfaceName, aMtu, aCallback) { - debug("Set MTU on " + aInterfaceName + ": " + aMtu); - - let params = { - cmd: "setMtu", - ifname: aInterfaceName, - mtu: aMtu - }; - - this.controlMessage(params, function(aResult) { - aCallback.nativeCommandResult(!aResult.error); - }); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NetworkService]); diff --git a/dom/system/gonk/NetworkService.manifest b/dom/system/gonk/NetworkService.manifest deleted file mode 100644 index caf8f2554..000000000 --- a/dom/system/gonk/NetworkService.manifest +++ /dev/null @@ -1,3 +0,0 @@ -# NetworkService.js -component {48c13741-aec9-4a86-8962-432011708261} NetworkService.js -contract @mozilla.org/network/service;1 {48c13741-aec9-4a86-8962-432011708261} diff --git a/dom/system/gonk/NetworkUtils.cpp b/dom/system/gonk/NetworkUtils.cpp deleted file mode 100644 index d661368b8..000000000 --- a/dom/system/gonk/NetworkUtils.cpp +++ /dev/null @@ -1,2973 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "NetworkUtils.h" - -#include "mozilla/Sprintf.h" -#include "SystemProperty.h" - -#include -#include -#include "mozilla/dom/network/NetUtils.h" -#include "mozilla/fallible.h" -#include "base/task.h" - -#include -#include -#include // struct addrinfo -#include // getaddrinfo(), freeaddrinfo() -#include -#include // inet_ntop() - -#define _DEBUG 0 - -#define WARN(args...) __android_log_print(ANDROID_LOG_WARN, "NetworkUtils", ## args) -#define ERROR(args...) __android_log_print(ANDROID_LOG_ERROR, "NetworkUtils", ## args) - -#if _DEBUG -#define NU_DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "NetworkUtils" , ## args) -#else -#define NU_DBG(args...) -#endif - -using namespace mozilla::dom; -using namespace mozilla::ipc; -using mozilla::system::Property; - -static const char* PERSIST_SYS_USB_CONFIG_PROPERTY = "persist.sys.usb.config"; -static const char* SYS_USB_CONFIG_PROPERTY = "sys.usb.config"; -static const char* SYS_USB_STATE_PROPERTY = "sys.usb.state"; - -static const char* USB_FUNCTION_RNDIS = "rndis"; -static const char* USB_FUNCTION_ADB = "adb"; - -// Use this command to continue the function chain. -static const char* DUMMY_COMMAND = "tether status"; - -// IPV6 Tethering is not supported in AOSP, use the property to -// identify vendor specific support in IPV6. We can remove this flag -// once upstream Android support IPV6 in tethering. -static const char* IPV6_TETHERING = "ro.tethering.ipv6"; - -// Retry 20 times (2 seconds) for usb state transition. -static const uint32_t USB_FUNCTION_RETRY_TIMES = 20; -// Check "sys.usb.state" every 100ms. -static const uint32_t USB_FUNCTION_RETRY_INTERVAL = 100; - -// 1xx - Requested action is proceeding -static const uint32_t NETD_COMMAND_PROCEEDING = 100; -// 2xx - Requested action has been successfully completed -static const uint32_t NETD_COMMAND_OKAY = 200; -// 4xx - The command is accepted but the requested action didn't -// take place. -static const uint32_t NETD_COMMAND_FAIL = 400; -// 5xx - The command syntax or parameters error -static const uint32_t NETD_COMMAND_ERROR = 500; -// 6xx - Unsolicited broadcasts -static const uint32_t NETD_COMMAND_UNSOLICITED = 600; - -// Broadcast messages -static const uint32_t NETD_COMMAND_INTERFACE_CHANGE = 600; -static const uint32_t NETD_COMMAND_BANDWIDTH_CONTROLLER = 601; - -static const char* INTERFACE_DELIMIT = ","; -static const char* USB_CONFIG_DELIMIT = ","; -static const char* NETD_MESSAGE_DELIMIT = " "; - -static const uint32_t BUF_SIZE = 1024; - -static const int32_t SUCCESS = 0; - -static uint32_t SDK_VERSION; -static uint32_t SUPPORT_IPV6_TETHERING; - -struct IFProperties { - char gateway[Property::VALUE_MAX_LENGTH]; - char dns1[Property::VALUE_MAX_LENGTH]; - char dns2[Property::VALUE_MAX_LENGTH]; -}; - -struct CurrentCommand { - CommandChain* chain; - CommandCallback callback; - char command[MAX_COMMAND_SIZE]; -}; - -typedef Tuple3 QueueData; - -#define GET_CURRENT_NETD_COMMAND (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a) -#define GET_CURRENT_CHAIN (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].b) -#define GET_CURRENT_CALLBACK (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].c) -#define GET_CURRENT_COMMAND (gCommandQueue.IsEmpty() ? nullptr : gCommandQueue[0].a->mData) - -// A macro for native function call return value check. -// For native function call, non-zero return value means failure. -#define RETURN_IF_FAILED(rv) do { \ - if (SUCCESS != rv) { \ - return rv; \ - } \ -} while (0); - -#define WARN_IF_FAILED(rv) do { \ - if (SUCCESS != rv) { \ - WARN("Error (%d) occurred in %s (%s:%d)", rv, __PRETTY_FUNCTION__, __FILE__, __LINE__); \ - } \ -} while (0); - -static NetworkUtils* gNetworkUtils; -static nsTArray gCommandQueue; -static CurrentCommand gCurrentCommand; -static bool gPending = false; -static nsTArray gReason; -static NetworkParams *gWifiTetheringParms = 0; - -static nsTArray gCommandChainQueue; - -const CommandFunc NetworkUtils::sWifiEnableChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::wifiFirmwareReload, - NetworkUtils::startAccessPointDriver, - NetworkUtils::setAccessPoint, - NetworkUtils::startSoftAP, - NetworkUtils::setConfig, - NetworkUtils::tetherInterface, - NetworkUtils::addInterfaceToLocalNetwork, - NetworkUtils::addRouteToLocalNetwork, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::tetheringStatus, - NetworkUtils::startTethering, - NetworkUtils::setDnsForwarders, - NetworkUtils::enableNat, - NetworkUtils::wifiTetheringSuccess -}; - -const CommandFunc NetworkUtils::sWifiDisableChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::stopSoftAP, - NetworkUtils::stopAccessPointDriver, - NetworkUtils::wifiFirmwareReload, - NetworkUtils::untetherInterface, - NetworkUtils::removeInterfaceFromLocalNetwork, - NetworkUtils::preTetherInterfaceList, - NetworkUtils::postTetherInterfaceList, - NetworkUtils::disableNat, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering, - NetworkUtils::wifiTetheringSuccess -}; - -const CommandFunc NetworkUtils::sWifiFailChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::stopSoftAP, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering -}; - -const CommandFunc NetworkUtils::sWifiRetryChain[] = { - NetworkUtils::clearWifiTetherParms, - NetworkUtils::stopSoftAP, - NetworkUtils::stopTethering, - - // sWifiEnableChain: - NetworkUtils::wifiFirmwareReload, - NetworkUtils::startAccessPointDriver, - NetworkUtils::setAccessPoint, - NetworkUtils::startSoftAP, - NetworkUtils::setConfig, - NetworkUtils::tetherInterface, - NetworkUtils::addInterfaceToLocalNetwork, - NetworkUtils::addRouteToLocalNetwork, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::tetheringStatus, - NetworkUtils::startTethering, - NetworkUtils::setDnsForwarders, - NetworkUtils::enableNat, - NetworkUtils::wifiTetheringSuccess -}; - -const CommandFunc NetworkUtils::sWifiOperationModeChain[] = { - NetworkUtils::wifiFirmwareReload, - NetworkUtils::wifiOperationModeSuccess -}; - -const CommandFunc NetworkUtils::sUSBEnableChain[] = { - NetworkUtils::setConfig, - NetworkUtils::enableNat, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::tetherInterface, - NetworkUtils::addInterfaceToLocalNetwork, - NetworkUtils::addRouteToLocalNetwork, - NetworkUtils::tetheringStatus, - NetworkUtils::startTethering, - NetworkUtils::setDnsForwarders, - NetworkUtils::addUpstreamInterface, - NetworkUtils::usbTetheringSuccess -}; - -const CommandFunc NetworkUtils::sUSBDisableChain[] = { - NetworkUtils::untetherInterface, - NetworkUtils::removeInterfaceFromLocalNetwork, - NetworkUtils::preTetherInterfaceList, - NetworkUtils::postTetherInterfaceList, - NetworkUtils::removeUpstreamInterface, - NetworkUtils::disableNat, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering, - NetworkUtils::usbTetheringSuccess -}; - -const CommandFunc NetworkUtils::sUSBFailChain[] = { - NetworkUtils::stopSoftAP, - NetworkUtils::setIpForwardingEnabled, - NetworkUtils::stopTethering -}; - -const CommandFunc NetworkUtils::sUpdateUpStreamChain[] = { - NetworkUtils::cleanUpStream, - NetworkUtils::removeUpstreamInterface, - NetworkUtils::createUpStream, - NetworkUtils::addUpstreamInterface, - NetworkUtils::updateUpStreamSuccess -}; - -const CommandFunc NetworkUtils::sStartDhcpServerChain[] = { - NetworkUtils::setConfig, - NetworkUtils::startTethering, - NetworkUtils::setDhcpServerSuccess -}; - -const CommandFunc NetworkUtils::sStopDhcpServerChain[] = { - NetworkUtils::stopTethering, - NetworkUtils::setDhcpServerSuccess -}; - -const CommandFunc NetworkUtils::sNetworkInterfaceEnableAlarmChain[] = { - NetworkUtils::enableAlarm, - NetworkUtils::setQuota, - NetworkUtils::setAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sNetworkInterfaceDisableAlarmChain[] = { - NetworkUtils::removeQuota, - NetworkUtils::disableAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sNetworkInterfaceSetAlarmChain[] = { - NetworkUtils::setAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sGetInterfacesChain[] = { - NetworkUtils::getInterfaceList, - NetworkUtils::getInterfacesSuccess -}; - -const CommandFunc NetworkUtils::sGetInterfaceConfigChain[] = { - NetworkUtils::getConfig, - NetworkUtils::getInterfaceConfigSuccess -}; - -const CommandFunc NetworkUtils::sSetInterfaceConfigChain[] = { - NetworkUtils::setConfig, - NetworkUtils::setInterfaceConfigSuccess -}; - -const CommandFunc NetworkUtils::sTetheringInterfaceSetAlarmChain[] = { - NetworkUtils::setGlobalAlarm, - NetworkUtils::removeAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sTetheringInterfaceRemoveAlarmChain[] = { - NetworkUtils::removeGlobalAlarm, - NetworkUtils::setAlarm, - NetworkUtils::networkInterfaceAlarmSuccess -}; - -const CommandFunc NetworkUtils::sTetheringGetStatusChain[] = { - NetworkUtils::tetheringStatus, - NetworkUtils::defaultAsyncSuccessHandler -}; - -/** - * Helper function to get the mask from given prefix length. - */ -static uint32_t makeMask(const uint32_t prefixLength) -{ - uint32_t mask = 0; - for (uint32_t i = 0; i < prefixLength; ++i) { - mask |= (0x80000000 >> i); - } - return ntohl(mask); -} - -/** - * Helper function to get the network part of an ip from prefix. - * param ip must be in network byte order. - */ -static char* getNetworkAddr(const uint32_t ip, const uint32_t prefix) -{ - uint32_t mask = 0, subnet = 0; - - mask = ~mask << (32 - prefix); - mask = htonl(mask); - subnet = ip & mask; - - struct in_addr addr; - addr.s_addr = subnet; - - return inet_ntoa(addr); -} - -/** - * Helper function to split string by seperator, store split result as an nsTArray. - */ -static void split(char* str, const char* sep, nsTArray& result) -{ - char *s = strtok(str, sep); - while (s != nullptr) { - result.AppendElement(s); - s = strtok(nullptr, sep); - } -} - -static void split(char* str, const char* sep, nsTArray& result) -{ - char *s = strtok(str, sep); - while (s != nullptr) { - result.AppendElement(NS_ConvertUTF8toUTF16(s)); - s = strtok(nullptr, sep); - } -} - -/** - * Helper function that implement join function. - */ -static void join(nsTArray& array, - const char* sep, - const uint32_t maxlen, - char* result) -{ -#define CHECK_LENGTH(len, add, max) len += add; \ - if (len > max - 1) \ - return; \ - - uint32_t len = 0; - uint32_t seplen = strlen(sep); - - if (array.Length() > 0) { - CHECK_LENGTH(len, strlen(array[0].get()), maxlen) - strcpy(result, array[0].get()); - - for (uint32_t i = 1; i < array.Length(); i++) { - CHECK_LENGTH(len, seplen, maxlen) - strcat(result, sep); - - CHECK_LENGTH(len, strlen(array[i].get()), maxlen) - strcat(result, array[i].get()); - } - } - -#undef CHECK_LEN -} - -static void convertUTF8toUTF16(nsTArray& narrow, - nsTArray& wide, - uint32_t length) -{ - for (uint32_t i = 0; i < length; i++) { - wide.AppendElement(NS_ConvertUTF8toUTF16(narrow[i].get())); - } -} - -/** - * Helper function to get network interface properties from the system property table. - */ -static void getIFProperties(const char* ifname, IFProperties& prop) -{ - char key[Property::KEY_MAX_LENGTH]; - snprintf(key, Property::KEY_MAX_LENGTH - 1, "net.%s.gw", ifname); - Property::Get(key, prop.gateway, ""); - snprintf(key, Property::KEY_MAX_LENGTH - 1, "net.%s.dns1", ifname); - Property::Get(key, prop.dns1, ""); - snprintf(key, Property::KEY_MAX_LENGTH - 1, "net.%s.dns2", ifname); - Property::Get(key, prop.dns2, ""); -} - -static int getIpType(const char *aIp) { - struct addrinfo hint, *ip_info = NULL; - - memset(&hint, 0, sizeof(hint)); - hint.ai_family = AF_UNSPEC; - hint.ai_flags = AI_NUMERICHOST; - - if (getaddrinfo(aIp, NULL, &hint, &ip_info)) { - return AF_UNSPEC; - } - - int type = ip_info->ai_family; - freeaddrinfo(ip_info); - - return type; -} - -static void postMessage(NetworkResultOptions& aResult) -{ - MOZ_ASSERT(gNetworkUtils); - MOZ_ASSERT(gNetworkUtils->getMessageCallback()); - - if (*(gNetworkUtils->getMessageCallback())) - (*(gNetworkUtils->getMessageCallback()))(aResult); -} - -static void postMessage(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - MOZ_ASSERT(gNetworkUtils); - MOZ_ASSERT(gNetworkUtils->getMessageCallback()); - - aResult.mId = aOptions.mId; - - if (*(gNetworkUtils->getMessageCallback())) - (*(gNetworkUtils->getMessageCallback()))(aResult); -} - -void NetworkUtils::runNextQueuedCommandChain() -{ - if (gCommandChainQueue.IsEmpty()) { - NU_DBG("No command chain left in the queue. Done!"); - return; - } - NU_DBG("Process the queued command chain."); - CommandChain* nextChain = gCommandChainQueue[0]; - NetworkResultOptions newResult; - next(nextChain, false, newResult); -} - -void NetworkUtils::next(CommandChain* aChain, bool aError, NetworkResultOptions& aResult) -{ - if (aError) { - ErrorCallback onError = aChain->getErrorCallback(); - if(onError) { - aResult.mError = true; - (*onError)(aChain->getParams(), aResult); - } - delete aChain; - gCommandChainQueue.RemoveElementAt(0); - runNextQueuedCommandChain(); - return; - } - CommandFunc f = aChain->getNextCommand(); - if (!f) { - delete aChain; - gCommandChainQueue.RemoveElementAt(0); - runNextQueuedCommandChain(); - return; - } - - (*f)(aChain, next, aResult); -} - -CommandResult::CommandResult(int32_t aResultCode) - : mIsPending(false) -{ - // This is usually not a netd command. We treat the return code - // typical linux convention, which uses 0 to indicate success. - mResult.mError = (aResultCode == SUCCESS ? false : true); - mResult.mResultCode = aResultCode; - if (aResultCode != SUCCESS) { - // The returned value is sometimes negative, make sure we pass a positive - // error number to strerror. - enum { STRERROR_R_BUF_SIZE = 1024, }; - char strerrorBuf[STRERROR_R_BUF_SIZE]; - strerror_r(abs(aResultCode), strerrorBuf, STRERROR_R_BUF_SIZE); - mResult.mReason = NS_ConvertUTF8toUTF16(strerrorBuf); - } -} - -CommandResult::CommandResult(const mozilla::dom::NetworkResultOptions& aResult) - : mResult(aResult) - , mIsPending(false) -{ -} - -CommandResult::CommandResult(const Pending&) - : mIsPending(true) -{ -} - -bool CommandResult::isPending() const -{ - return mIsPending; -} - -/** - * Send command to netd. - */ -void NetworkUtils::nextNetdCommand() -{ - if (gCommandQueue.IsEmpty() || gPending) { - return; - } - - gCurrentCommand.chain = GET_CURRENT_CHAIN; - gCurrentCommand.callback = GET_CURRENT_CALLBACK; - snprintf(gCurrentCommand.command, MAX_COMMAND_SIZE - 1, "%s", GET_CURRENT_COMMAND); - - NU_DBG("Sending \'%s\' command to netd.", gCurrentCommand.command); - SendNetdCommand(GET_CURRENT_NETD_COMMAND); - - gCommandQueue.RemoveElementAt(0); - gPending = true; -} - -/** - * Composite NetdCommand sent to netd - * - * @param aCommand Command sent to netd to execute. - * @param aChain Store command chain data, ex. command parameter. - * @param aCallback Callback function to be executed when the result of - * this command is returned from netd. - */ -void NetworkUtils::doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback) -{ - NU_DBG("Preparing to send \'%s\' command...", aCommand); - - NetdCommand* netdCommand = new NetdCommand(); - - // Android JB version adds sequence number to netd command. - if (SDK_VERSION >= 16) { - snprintf((char*)netdCommand->mData, MAX_COMMAND_SIZE - 1, "0 %s", aCommand); - } else { - snprintf((char*)netdCommand->mData, MAX_COMMAND_SIZE - 1, "%s", aCommand); - } - netdCommand->mSize = strlen((char*)netdCommand->mData) + 1; - - gCommandQueue.AppendElement(QueueData(netdCommand, aChain, aCallback)); - - nextNetdCommand(); -} - -/* - * Netd command function - */ -#define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aChain->getParams().prop).get() -#define GET_FIELD(prop) aChain->getParams().prop - -void NetworkUtils::wifiFirmwareReload(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "softap fwreload %s %s", GET_CHAR(mIfname), GET_CHAR(mMode)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::startAccessPointDriver(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version >= 16. - if (SDK_VERSION >= 16) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "softap start %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::stopAccessPointDriver(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version >= 16. - if (SDK_VERSION >= 16) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "softap stop %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -/** - * Command format for sdk version < 16 - * Arguments: - * argv[2] - wlan interface - * argv[3] - SSID - * argv[4] - Security - * argv[5] - Key - * argv[6] - Channel - * argv[7] - Preamble - * argv[8] - Max SCB - * - * Command format for sdk version >= 16 - * Arguments: - * argv[2] - wlan interface - * argv[3] - SSID - * argv[4] - Security - * argv[5] - Key - * - * Command format for sdk version >= 18 - * Arguments: - * argv[2] - wlan interface - * argv[3] - SSID - * argv[4] - Broadcast/Hidden - * argv[5] - Channel - * argv[6] - Security - * argv[7] - Key - */ -void NetworkUtils::setAccessPoint(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - nsCString ssid(GET_CHAR(mSsid)); - nsCString key(GET_CHAR(mKey)); - - escapeQuote(ssid); - escapeQuote(key); - - if (SDK_VERSION >= 19) { - snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s \"%s\" broadcast 6 %s \"%s\"", - GET_CHAR(mIfname), - ssid.get(), - GET_CHAR(mSecurity), - key.get()); - } else if (SDK_VERSION >= 16) { - snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s \"%s\" %s \"%s\"", - GET_CHAR(mIfname), - ssid.get(), - GET_CHAR(mSecurity), - key.get()); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "softap set %s %s \"%s\" %s \"%s\" 6 0 8", - GET_CHAR(mIfname), - GET_CHAR(mWifictrlinterfacename), - ssid.get(), - GET_CHAR(mSecurity), - key.get()); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::cleanUpStream(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 0", GET_CHAR(mPreInternalIfname), GET_CHAR(mPreExternalIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::createUpStream(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 0", GET_CHAR(mCurInternalIfname), GET_CHAR(mCurExternalIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::startSoftAP(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "softap startap"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::stopSoftAP(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "softap stopap"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::clearWifiTetherParms(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - delete gWifiTetheringParms; - gWifiTetheringParms = 0; - next(aChain, false, aResult); -} - -void NetworkUtils::enableAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "bandwidth enable"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::disableAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "bandwidth disable"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setQuota(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setiquota %s % " PRId64, GET_CHAR(mIfname), INT64_MAX); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeQuota(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeiquota %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setinterfacealert %s %lld", - GET_CHAR(mIfname), GET_FIELD(mThreshold)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeinterfacealert %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setGlobalAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth setglobalalert %lld", GET_FIELD(mThreshold)); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeGlobalAlarm(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - snprintf(command, MAX_COMMAND_SIZE - 1, "bandwidth removeglobalalert"); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::tetherInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface add %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addInterfaceToLocalNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version < 20. - if (SDK_VERSION < 20) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network interface add local %s", - GET_CHAR(mInternalIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addRouteToLocalNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version < 20. - if (SDK_VERSION < 20) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - uint32_t prefix = atoi(GET_CHAR(mPrefix)); - uint32_t ip = inet_addr(GET_CHAR(mIp)); - char* networkAddr = getNetworkAddr(ip, prefix); - - snprintf(command, MAX_COMMAND_SIZE - 1, "network route add local %s %s/%s", - GET_CHAR(mInternalIfname), networkAddr, GET_CHAR(mPrefix)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::preTetherInterfaceList(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - if (SDK_VERSION >= 16) { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface list"); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface list 0"); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::postTetherInterfaceList(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Send the dummy command to continue the function chain. - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - - char buf[BUF_SIZE]; - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - - size_t length = reason.Length() + 1 < BUF_SIZE ? reason.Length() + 1 : BUF_SIZE; - memcpy(buf, reason.get(), length); - split(buf, INTERFACE_DELIMIT, GET_FIELD(mInterfaceList)); - - doCommand(command, aChain, aCallback); -} - -bool isCommandChainIPv6(CommandChain* aChain, const char *externalInterface) { - // Check by gateway address - if (getIpType(GET_CHAR(mGateway)) == AF_INET6) { - return true; - } - - uint32_t length = GET_FIELD(mGateways).Length(); - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoGateway(GET_FIELD(mGateways)[i]); - if(getIpType(autoGateway.get()) == AF_INET6) { - return true; - } - } - - // Check by external inteface address - FILE *file = fopen("/proc/net/if_inet6", "r"); - if (!file) { - return false; - } - - bool isIPv6 = false; - char interface[32]; - while(fscanf(file, "%*s %*s %*s %*s %*s %32s", interface)) { - if (strcmp(interface, externalInterface) == 0) { - isIPv6 = true; - break; - } - } - - fclose(file); - return isIPv6; -} - -void NetworkUtils::addUpstreamInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - nsCString interface(GET_CHAR(mExternalIfname)); - if (!interface.get()[0]) { - interface = GET_CHAR(mCurExternalIfname); - } - - if (SUPPORT_IPV6_TETHERING == 0 || !isCommandChainIPv6(aChain, interface.get())) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface add_upstream %s", - interface.get()); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeUpstreamInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - nsCString interface(GET_CHAR(mExternalIfname)); - if (!interface.get()[0]) { - interface = GET_CHAR(mPreExternalIfname); - } - - if (SUPPORT_IPV6_TETHERING == 0 || !isCommandChainIPv6(aChain, interface.get())) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface remove_upstream %s", - interface.get()); - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setIpForwardingEnabled(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (GET_FIELD(mEnable)) { - snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd enable"); - } else { - // Don't disable ip forwarding because others interface still need it. - // Send the dummy command to continue the function chain. - if (GET_FIELD(mInterfaceList).Length() > 1) { - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "ipfwd disable"); - } - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::tetheringStatus(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - const char* command= "tether status"; - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::stopTethering(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - // Don't stop tethering because others interface still need it. - // Send the dummy to continue the function chain. - if (GET_FIELD(mInterfaceList).Length() > 1) { - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether stop"); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::startTethering(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - // We don't need to start tethering again. - // Send the dummy command to continue the function chain. - if (aResult.mResultReason.Find("started") != kNotFound) { - snprintf(command, MAX_COMMAND_SIZE - 1, "%s", DUMMY_COMMAND); - } else { - // If usbStartIp/usbEndIp is not valid, don't append them since - // the trailing white spaces will be parsed to extra empty args - // See: http://androidxref.com/4.3_r2.1/xref/system/core/libsysutils/src/FrameworkListener.cpp#78 - if (!GET_FIELD(mUsbStartIp).IsEmpty() && !GET_FIELD(mUsbEndIp).IsEmpty()) { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s %s %s", - GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp), - GET_CHAR(mUsbStartIp), GET_CHAR(mUsbEndIp)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether start %s %s", - GET_CHAR(mWifiStartIp), GET_CHAR(mWifiEndIp)); - } - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::untetherInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "tether interface remove %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeInterfaceFromLocalNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // Skip the command for sdk version < 20. - if (SDK_VERSION < 20) { - aResult.mResultCode = 0; - aResult.mResultReason = NS_ConvertUTF8toUTF16(""); - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network interface remove local %s", - GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setDnsForwarders(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (SDK_VERSION >= 20) { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether dns set %d %s %s", - GET_FIELD(mNetId), GET_CHAR(mDns1), GET_CHAR(mDns2)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "tether dns set %s %s", - GET_CHAR(mDns1), GET_CHAR(mDns2)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::enableNat(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (!GET_FIELD(mIp).IsEmpty() && !GET_FIELD(mPrefix).IsEmpty()) { - uint32_t prefix = atoi(GET_CHAR(mPrefix)); - uint32_t ip = inet_addr(GET_CHAR(mIp)); - char* networkAddr = getNetworkAddr(ip, prefix); - - // address/prefix will only take effect when secondary routing table exists. - snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 1 %s/%s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname), networkAddr, - GET_CHAR(mPrefix)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "nat enable %s %s 0", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::disableNat(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - - if (!GET_FIELD(mIp).IsEmpty() && !GET_FIELD(mPrefix).IsEmpty()) { - uint32_t prefix = atoi(GET_CHAR(mPrefix)); - uint32_t ip = inet_addr(GET_CHAR(mIp)); - char* networkAddr = getNetworkAddr(ip, prefix); - - snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 1 %s/%s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname), networkAddr, - GET_CHAR(mPrefix)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "nat disable %s %s 0", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setDefaultInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "resolver setdefaultif %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeDefaultRoute(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - nsTArray& gateways = GET_FIELD(mGateways); - NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]); - - int type = getIpType(autoGateway.get()); - snprintf(command, MAX_COMMAND_SIZE - 1, "network route remove %d %s %s/0 %s", - GET_FIELD(mNetId), GET_CHAR(mIfname), - type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get()); - - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - NU_DBG("removeDefaultRoute's reason: %s", reason.get()); - if (aError && !reason.EqualsASCII("removeRoute() failed (No such process)")) { - return aOriginalCallback(aChain, aError, aResult); - } - - GET_FIELD(mLoopIndex)++; - return removeDefaultRoute(aChain, aOriginalCallback, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - doCommand(command, aChain, wrappedCallback); -} - -void NetworkUtils::setInterfaceDns(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - int written; - - if (SDK_VERSION >= 20) { - written = SprintfLiteral(command, "resolver setnetdns %d %s", - GET_FIELD(mNetId), GET_CHAR(mDomain)); - } else { - written = SprintfLiteral(command, "resolver setifdns %s %s", - GET_CHAR(mIfname), GET_CHAR(mDomain)); - } - - nsTArray& dnses = GET_FIELD(mDnses); - uint32_t length = dnses.Length(); - - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoDns(dnses[i]); - - int ret = snprintf(command + written, sizeof(command) - written, " %s", autoDns.get()); - if (ret <= 1) { - command[written] = '\0'; - continue; - } - - if (((size_t)ret + written) >= sizeof(command)) { - command[written] = '\0'; - break; - } - - written += ret; - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::getInterfaceList(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface list"); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::getConfig(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface getcfg %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setConfig(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - if (SDK_VERSION >= 16) { - snprintf(command, MAX_COMMAND_SIZE - 1, "interface setcfg %s %s %s %s", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mLink)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, "interface setcfg %s %s %s [%s]", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mLink)); - } - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::clearAddrForInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface clearaddrs %s", GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::createNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network create %d", GET_FIELD(mNetId)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::destroyNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network destroy %d", GET_FIELD(mNetId)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addInterfaceToNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network interface add %d %s", - GET_FIELD(mNetId), GET_CHAR(mIfname)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addRouteToInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - NU_DBG("addRouteToInterface's reason: %s", reason.get()); - if (aError && reason.EqualsASCII("addRoute() failed (File exists)")) { - NU_DBG("Ignore \"File exists\" error when adding host route."); - return aOriginalCallback(aChain, false, aResult); - } - aOriginalCallback(aChain, aError, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - modifyRouteOnInterface(aChain, wrappedCallback, aResult, true); -} - -void NetworkUtils::removeRouteFromInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - modifyRouteOnInterface(aChain, aCallback, aResult, false); -} - -void NetworkUtils::modifyRouteOnInterface(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult, - bool aDoAdd) -{ - char command[MAX_COMMAND_SIZE]; - - // AOSP adds host route to its interface table but it doesn't work for - // B2G because we cannot set fwmark per application. So, we add - // all host routes to legacy_system table except scope link route. - - nsCString ipOrSubnetIp = NS_ConvertUTF16toUTF8(GET_FIELD(mIp)); - nsCString gatewayOrEmpty; - const char* legacyOrEmpty = "legacy 0 "; // Add to legacy by default. - if (GET_FIELD(mGateway).IsEmpty()) { - ipOrSubnetIp = getSubnetIp(ipOrSubnetIp, GET_FIELD(mPrefixLength)); - legacyOrEmpty = ""; // Add to interface table for scope link route. - } else { - gatewayOrEmpty = nsCString(" ") + NS_ConvertUTF16toUTF8(GET_FIELD(mGateway)); - } - - const char* action = aDoAdd ? "add" : "remove"; - - snprintf(command, MAX_COMMAND_SIZE - 1, "network route %s%s %d %s %s/%d%s", - legacyOrEmpty, action, - GET_FIELD(mNetId), GET_CHAR(mIfname), ipOrSubnetIp.get(), - GET_FIELD(mPrefixLength), gatewayOrEmpty.get()); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addDefaultRouteToNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - if (GET_FIELD(mLoopIndex) >= GET_FIELD(mGateways).Length()) { - aCallback(aChain, false, aResult); - return; - } - - char command[MAX_COMMAND_SIZE]; - nsTArray& gateways = GET_FIELD(mGateways); - NS_ConvertUTF16toUTF8 autoGateway(gateways[GET_FIELD(mLoopIndex)]); - - int type = getIpType(autoGateway.get()); - snprintf(command, MAX_COMMAND_SIZE - 1, "network route add %d %s %s/0 %s", - GET_FIELD(mNetId), GET_CHAR(mIfname), - type == AF_INET6 ? "::" : "0.0.0.0", autoGateway.get()); - - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - NU_DBG("addDefaultRouteToNetwork's reason: %s", reason.get()); - if (aError && !reason.EqualsASCII("addRoute() failed (File exists)")) { - return aOriginalCallback(aChain, aError, aResult); - } - - GET_FIELD(mLoopIndex)++; - return addDefaultRouteToNetwork(aChain, aOriginalCallback, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - doCommand(command, aChain, wrappedCallback); -} - -void NetworkUtils::setDefaultNetwork(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "network default set %d", GET_FIELD(mNetId)); - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::addRouteToSecondaryTable(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) { - - char command[MAX_COMMAND_SIZE]; - - if (SDK_VERSION >= 20) { - snprintf(command, MAX_COMMAND_SIZE - 1, - "network route add %d %s %s/%s %s", - GET_FIELD(mNetId), - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, - "interface route add %s secondary %s %s %s", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::removeRouteFromSecondaryTable(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) { - char command[MAX_COMMAND_SIZE]; - - if (SDK_VERSION >= 20) { - snprintf(command, MAX_COMMAND_SIZE - 1, - "network route remove %d %s %s/%s %s", - GET_FIELD(mNetId), - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } else { - snprintf(command, MAX_COMMAND_SIZE - 1, - "interface route remove %s secondary %s %s %s", - GET_CHAR(mIfname), - GET_CHAR(mIp), - GET_CHAR(mPrefix), - GET_CHAR(mGateway)); - } - - doCommand(command, aChain, aCallback); -} - -void NetworkUtils::setIpv6Enabled(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult, - bool aEnabled) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface ipv6 %s %s", - GET_CHAR(mIfname), aEnabled ? "enable" : "disable"); - - struct MyCallback { - static void callback(CommandCallback::CallbackType aOriginalCallback, - CommandChain* aChain, - bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - aOriginalCallback(aChain, false, aResult); - } - }; - - CommandCallback wrappedCallback(MyCallback::callback, aCallback); - doCommand(command, aChain, wrappedCallback); -} - -void NetworkUtils::enableIpv6(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - setIpv6Enabled(aChain, aCallback, aResult, true); -} - -void NetworkUtils::disableIpv6(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - setIpv6Enabled(aChain, aCallback, aResult, false); -} - -void NetworkUtils::setMtu(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char command[MAX_COMMAND_SIZE]; - snprintf(command, MAX_COMMAND_SIZE - 1, "interface setmtu %s %ld", - GET_CHAR(mIfname), GET_FIELD(mMtu)); - - doCommand(command, aChain, aCallback); -} - -#undef GET_CHAR -#undef GET_FIELD - -/* - * Netd command success/fail function - */ -#define ASSIGN_FIELD(prop) aResult.prop = aChain->getParams().prop; -#define ASSIGN_FIELD_VALUE(prop, value) aResult.prop = value; - -template -void NetworkUtils::runChain(const NetworkParams& aParams, - const CommandFunc (&aCmds)[N], - ErrorCallback aError) -{ - CommandChain* chain = new CommandChain(aParams, aCmds, N, aError); - gCommandChainQueue.AppendElement(chain); - - if (gCommandChainQueue.Length() > 1) { - NU_DBG("%d command chains are queued. Wait!", gCommandChainQueue.Length()); - return; - } - - NetworkResultOptions result; - NetworkUtils::next(gCommandChainQueue[0], false, result); -} - -// Called to clean up the command chain and process the queued command chain if any. -void NetworkUtils::finalizeSuccess(CommandChain* aChain, - NetworkResultOptions& aResult) -{ - next(aChain, false, aResult); -} - -void NetworkUtils::wifiTetheringFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - // Notify the main thread. - postMessage(aOptions, aResult); - - // If one of the stages fails, we try roll back to ensure - // we don't leave the network systems in limbo. - ASSIGN_FIELD_VALUE(mEnable, false) - runChain(aOptions, sWifiFailChain, nullptr); -} - -void NetworkUtils::wifiTetheringSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - ASSIGN_FIELD(mEnable) - - if (aChain->getParams().mEnable) { - MOZ_ASSERT(!gWifiTetheringParms); - gWifiTetheringParms = new NetworkParams(aChain->getParams()); - } - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::usbTetheringFail(NetworkParams& aOptions, - NetworkResultOptions& aResult) -{ - // Notify the main thread. - postMessage(aOptions, aResult); - // Try to roll back to ensure - // we don't leave the network systems in limbo. - // This parameter is used to disable ipforwarding. - { - aOptions.mEnable = false; - runChain(aOptions, sUSBFailChain, nullptr); - } - - // Disable usb rndis function. - { - NetworkParams options; - options.mEnable = false; - options.mReport = false; - gNetworkUtils->enableUsbRndis(options); - } -} - -void NetworkUtils::usbTetheringSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - ASSIGN_FIELD(mEnable) - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::networkInterfaceAlarmFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::networkInterfaceAlarmSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - // TODO : error is not used , and it is conflict with boolean type error. - // params.error = parseFloat(params.resultReason); - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::updateUpStreamFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::updateUpStreamSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - ASSIGN_FIELD(mCurExternalIfname) - ASSIGN_FIELD(mCurInternalIfname) - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::setDhcpServerFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - aResult.mSuccess = false; - postMessage(aOptions, aResult); -} - -void NetworkUtils::setDhcpServerSuccess(CommandChain* aChain, CommandCallback aCallback, NetworkResultOptions& aResult) -{ - aResult.mSuccess = true; - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::wifiOperationModeFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::wifiOperationModeSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::setDnsFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::defaultAsyncSuccessHandler(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - NU_DBG("defaultAsyncSuccessHandler"); - aResult.mRet = true; - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::defaultAsyncFailureHandler(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - aResult.mRet = false; - postMessage(aOptions, aResult); -} - -void NetworkUtils::getInterfacesFail(NetworkParams& aOptions, NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::getInterfacesSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char buf[BUF_SIZE]; - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - memcpy(buf, reason.get(), strlen(reason.get())); - - nsTArray result; - split(buf, INTERFACE_DELIMIT, result); - - nsTArray interfaceList; - uint32_t length = result.Length(); - convertUTF8toUTF16(result, interfaceList, length); - - aResult.mInterfaceList.Construct(); - for (uint32_t i = 0; i < length; i++) { - aResult.mInterfaceList.Value().AppendElement(interfaceList[i], fallible_t()); - } - - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::getInterfaceConfigFail(NetworkParams& aOptions, - NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::getInterfaceConfigSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - char buf[BUF_SIZE]; - NS_ConvertUTF16toUTF8 reason(aResult.mResultReason); - memcpy(buf, reason.get(), strlen(reason.get())); - - nsTArray result; - split(buf, NETD_MESSAGE_DELIMIT, result); - - ASSIGN_FIELD_VALUE(mMacAddr, NS_ConvertUTF8toUTF16(result[0])) - ASSIGN_FIELD_VALUE(mIpAddr, NS_ConvertUTF8toUTF16(result[1])) - ASSIGN_FIELD_VALUE(mPrefixLength, atol(result[2].get())) - - if (result[3].Find("up")) { - ASSIGN_FIELD_VALUE(mFlag, NS_ConvertUTF8toUTF16("up")) - } else { - ASSIGN_FIELD_VALUE(mFlag, NS_ConvertUTF8toUTF16("down")) - } - - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -void NetworkUtils::setInterfaceConfigFail(NetworkParams& aOptions, - NetworkResultOptions& aResult) -{ - postMessage(aOptions, aResult); -} - -void NetworkUtils::setInterfaceConfigSuccess(CommandChain* aChain, - CommandCallback aCallback, - NetworkResultOptions& aResult) -{ - postMessage(aChain->getParams(), aResult); - finalizeSuccess(aChain, aResult); -} - -#undef ASSIGN_FIELD -#undef ASSIGN_FIELD_VALUE - -NetworkUtils::NetworkUtils(MessageCallback aCallback) - : mMessageCallback(aCallback) -{ - mNetUtils = new NetUtils(); - - char value[Property::VALUE_MAX_LENGTH]; - Property::Get("ro.build.version.sdk", value, nullptr); - SDK_VERSION = atoi(value); - - Property::Get(IPV6_TETHERING, value, "0"); - SUPPORT_IPV6_TETHERING = atoi(value); - - gNetworkUtils = this; -} - -NetworkUtils::~NetworkUtils() -{ -} - -#define GET_CHAR(prop) NS_ConvertUTF16toUTF8(aOptions.prop).get() -#define GET_FIELD(prop) aOptions.prop - -// Hoist this type definition to global to avoid template -// instantiation error on gcc 4.4 used by ICS emulator. -typedef CommandResult (NetworkUtils::*CommandHandler)(NetworkParams&); -struct CommandHandlerEntry -{ - const char* mCommandName; - CommandHandler mCommandHandler; -}; - -void NetworkUtils::ExecuteCommand(NetworkParams aOptions) -{ - const static CommandHandlerEntry - COMMAND_HANDLER_TABLE[] = { - - // For command 'testCommand', BUILD_ENTRY(testCommand) will generate - // {"testCommand", NetworkUtils::testCommand} - #define BUILD_ENTRY(c) {#c, &NetworkUtils::c} - - BUILD_ENTRY(removeNetworkRoute), - BUILD_ENTRY(setDNS), - BUILD_ENTRY(setDefaultRoute), - BUILD_ENTRY(removeDefaultRoute), - BUILD_ENTRY(addHostRoute), - BUILD_ENTRY(removeHostRoute), - BUILD_ENTRY(addSecondaryRoute), - BUILD_ENTRY(removeSecondaryRoute), - BUILD_ENTRY(setNetworkInterfaceAlarm), - BUILD_ENTRY(enableNetworkInterfaceAlarm), - BUILD_ENTRY(disableNetworkInterfaceAlarm), - BUILD_ENTRY(setTetheringAlarm), - BUILD_ENTRY(removeTetheringAlarm), - BUILD_ENTRY(getTetheringStatus), - BUILD_ENTRY(setWifiOperationMode), - BUILD_ENTRY(setDhcpServer), - BUILD_ENTRY(setWifiTethering), - BUILD_ENTRY(setUSBTethering), - BUILD_ENTRY(enableUsbRndis), - BUILD_ENTRY(updateUpStream), - BUILD_ENTRY(configureInterface), - BUILD_ENTRY(dhcpRequest), - BUILD_ENTRY(stopDhcp), - BUILD_ENTRY(enableInterface), - BUILD_ENTRY(disableInterface), - BUILD_ENTRY(resetConnections), - BUILD_ENTRY(createNetwork), - BUILD_ENTRY(destroyNetwork), - BUILD_ENTRY(getNetId), - BUILD_ENTRY(getInterfaces), - BUILD_ENTRY(getInterfaceConfig), - BUILD_ENTRY(setInterfaceConfig), - BUILD_ENTRY(setMtu), - - #undef BUILD_ENTRY - }; - - // Loop until we find the command name which matches aOptions.mCmd. - CommandHandler handler = nullptr; - for (size_t i = 0; i < mozilla::ArrayLength(COMMAND_HANDLER_TABLE); i++) { - if (aOptions.mCmd.EqualsASCII(COMMAND_HANDLER_TABLE[i].mCommandName)) { - handler = COMMAND_HANDLER_TABLE[i].mCommandHandler; - break; - } - } - - if (!handler) { - // Command not found in COMMAND_HANDLER_TABLE. - WARN("unknown message: %s", NS_ConvertUTF16toUTF8(aOptions.mCmd).get()); - return; - } - - // The handler would return one of the following 3 values - // to be wrapped to CommandResult: - // - // 1) |int32_t| for mostly synchronous native function calls. - // 2) |NetworkResultOptions| to populate additional results. (e.g. dhcpRequest) - // 3) |CommandResult::Pending| to indicate the result is not - // obtained yet. - // - // If the handler returns "Pending", the handler should take the - // responsibility for posting result to main thread. - CommandResult commandResult = (this->*handler)(aOptions); - if (!commandResult.isPending()) { - postMessage(aOptions, commandResult.mResult); - } -} - -/** - * Handle received data from netd. - */ -void NetworkUtils::onNetdMessage(NetdCommand* aCommand) -{ - char* data = (char*)aCommand->mData; - - // get code & reason. - char* result = strtok(data, NETD_MESSAGE_DELIMIT); - - if (!result) { - nextNetdCommand(); - return; - } - uint32_t code = atoi(result); - - if (!isBroadcastMessage(code) && SDK_VERSION >= 16) { - strtok(nullptr, NETD_MESSAGE_DELIMIT); - } - - char* reason = strtok(nullptr, "\0"); - - if (isBroadcastMessage(code)) { - NU_DBG("Receiving broadcast message from netd."); - NU_DBG(" ==> Code: %d Reason: %s", code, reason); - sendBroadcastMessage(code, reason); - - if (code == NETD_COMMAND_INTERFACE_CHANGE) { - if (gWifiTetheringParms) { - char linkdownReason[MAX_COMMAND_SIZE]; - snprintf(linkdownReason, MAX_COMMAND_SIZE - 1, - "Iface linkstate %s down", - NS_ConvertUTF16toUTF8(gWifiTetheringParms->mIfname).get()); - - if (!strcmp(reason, linkdownReason)) { - NU_DBG("Wifi link down, restarting tethering."); - runChain(*gWifiTetheringParms, sWifiRetryChain, wifiTetheringFail); - } - } - } - - nextNetdCommand(); - return; - } - - // Set pending to false before we handle next command. - NU_DBG("Receiving \"%s\" command response from netd.", gCurrentCommand.command); - NU_DBG(" ==> Code: %d Reason: %s", code, reason); - - gReason.AppendElement(nsCString(reason)); - - // 1xx response code regards as command is proceeding, we need to wait for - // final response code such as 2xx, 4xx and 5xx before sending next command. - if (isProceeding(code)) { - return; - } - - if (isComplete(code)) { - gPending = false; - } - - { - char buf[BUF_SIZE]; - join(gReason, INTERFACE_DELIMIT, BUF_SIZE, buf); - - NetworkResultOptions result; - result.mResultCode = code; - result.mResultReason = NS_ConvertUTF8toUTF16(buf); - (gCurrentCommand.callback)(gCurrentCommand.chain, isError(code), result); - gReason.Clear(); - } - - // Handling pending commands if any. - if (isComplete(code)) { - nextNetdCommand(); - } -} - -/** - * Start/Stop DHCP server. - */ -CommandResult NetworkUtils::setDhcpServer(NetworkParams& aOptions) -{ - if (aOptions.mEnabled) { - aOptions.mWifiStartIp = aOptions.mStartIp; - aOptions.mWifiEndIp = aOptions.mEndIp; - aOptions.mIp = aOptions.mServerIp; - aOptions.mPrefix = aOptions.mMaskLength; - aOptions.mLink = NS_ConvertUTF8toUTF16("up"); - - runChain(aOptions, sStartDhcpServerChain, setDhcpServerFail); - } else { - runChain(aOptions, sStopDhcpServerChain, setDhcpServerFail); - } - return CommandResult::Pending(); -} - -/** - * Set DNS servers for given network interface. - */ -CommandResult NetworkUtils::setDNS(NetworkParams& aOptions) -{ - uint32_t length = aOptions.mDnses.Length(); - - if (length > 0) { - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoDns(aOptions.mDnses[i]); - - char dns_prop_key[Property::VALUE_MAX_LENGTH]; - SprintfLiteral(dns_prop_key, "net.dns%d", i+1); - Property::Set(dns_prop_key, autoDns.get()); - } - } else { - // Set dnses from system properties. - IFProperties interfaceProperties; - getIFProperties(GET_CHAR(mIfname), interfaceProperties); - - Property::Set("net.dns1", interfaceProperties.dns1); - Property::Set("net.dns2", interfaceProperties.dns2); - } - - // Bump the DNS change property. - char dnschange[Property::VALUE_MAX_LENGTH]; - Property::Get("net.dnschange", dnschange, "0"); - - char num[Property::VALUE_MAX_LENGTH]; - snprintf(num, Property::VALUE_MAX_LENGTH - 1, "%d", atoi(dnschange) + 1); - Property::Set("net.dnschange", num); - - // DNS needs to be set through netd since JellyBean (4.3). - if (SDK_VERSION >= 20) { - // Lollipop. - static CommandFunc COMMAND_CHAIN[] = { - setInterfaceDns, - addDefaultRouteToNetwork, - defaultAsyncSuccessHandler - }; - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) { - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, setDnsFail); - return CommandResult::Pending(); - } - if (SDK_VERSION >= 18) { - // JB, KK. - static CommandFunc COMMAND_CHAIN[] = { - #if ANDROID_VERSION == 18 - // Since we don't use per-interface DNS lookup feature on JB, - // we need to set the default DNS interface whenever setting the - // DNS name server. - setDefaultInterface, - #endif - setInterfaceDns, - defaultAsyncSuccessHandler - }; - runChain(aOptions, COMMAND_CHAIN, setDnsFail); - return CommandResult::Pending(); - } - - return SUCCESS; -} - -CommandResult NetworkUtils::configureInterface(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - return mNetUtils->do_ifc_configure( - autoIfname.get(), - aOptions.mIpaddr, - aOptions.mMask, - aOptions.mGateway_long, - aOptions.mDns1_long, - aOptions.mDns2_long - ); -} - -CommandResult NetworkUtils::stopDhcp(NetworkParams& aOptions) -{ - return mNetUtils->do_dhcp_stop(GET_CHAR(mIfname)); -} - -CommandResult NetworkUtils::dhcpRequest(NetworkParams& aOptions) { - mozilla::dom::NetworkResultOptions result; - - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - char ipaddr[Property::VALUE_MAX_LENGTH]; - char gateway[Property::VALUE_MAX_LENGTH]; - uint32_t prefixLength; - char dns1[Property::VALUE_MAX_LENGTH]; - char dns2[Property::VALUE_MAX_LENGTH]; - char server[Property::VALUE_MAX_LENGTH]; - uint32_t lease; - char vendorinfo[Property::VALUE_MAX_LENGTH]; - int32_t ret = mNetUtils->do_dhcp_do_request(autoIfname.get(), - ipaddr, - gateway, - &prefixLength, - dns1, - dns2, - server, - &lease, - vendorinfo); - - RETURN_IF_FAILED(ret); - - result.mIpaddr_str = NS_ConvertUTF8toUTF16(ipaddr); - result.mGateway_str = NS_ConvertUTF8toUTF16(gateway); - result.mDns1_str = NS_ConvertUTF8toUTF16(dns1); - result.mDns2_str = NS_ConvertUTF8toUTF16(dns2); - result.mServer_str = NS_ConvertUTF8toUTF16(server); - result.mVendor_str = NS_ConvertUTF8toUTF16(vendorinfo); - result.mLease = lease; - result.mPrefixLength = prefixLength; - result.mMask = makeMask(prefixLength); - - uint32_t inet4; // only support IPv4 for now. - -#define INET_PTON(var, field) \ - PR_BEGIN_MACRO \ - inet_pton(AF_INET, var, &inet4); \ - result.field = inet4; \ - PR_END_MACRO - - INET_PTON(ipaddr, mIpaddr); - INET_PTON(gateway, mGateway); - - if (dns1[0] != '\0') { - INET_PTON(dns1, mDns1); - } - - if (dns2[0] != '\0') { - INET_PTON(dns2, mDns2); - } - - INET_PTON(server, mServer); - - char inet_str[64]; - if (inet_ntop(AF_INET, &result.mMask, inet_str, sizeof(inet_str))) { - result.mMask_str = NS_ConvertUTF8toUTF16(inet_str); - } - - return result; -} - -CommandResult NetworkUtils::enableInterface(NetworkParams& aOptions) { - return mNetUtils->do_ifc_enable( - NS_ConvertUTF16toUTF8(aOptions.mIfname).get()); -} - -CommandResult NetworkUtils::disableInterface(NetworkParams& aOptions) { - return mNetUtils->do_ifc_disable( - NS_ConvertUTF16toUTF8(aOptions.mIfname).get()); -} - -CommandResult NetworkUtils::resetConnections(NetworkParams& aOptions) { - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - return mNetUtils->do_ifc_reset_connections( - NS_ConvertUTF16toUTF8(aOptions.mIfname).get(), - RESET_ALL_ADDRESSES); -} - -/** - * Set default route and DNS servers for given network interface. - */ -CommandResult NetworkUtils::setDefaultRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return setDefaultRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - addDefaultRouteToNetwork, - setDefaultNetwork, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface"); - return -1; - } - - aOptions.mNetId = netIdInfo.mNetId; - aOptions.mLoopIndex = 0; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Set default route and DNS servers for given network interface by obsoleted libnetutils. - */ -CommandResult NetworkUtils::setDefaultRouteLegacy(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - - uint32_t length = aOptions.mGateways.Length(); - if (length > 0) { - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]); - - int type = getIpType(autoGateway.get()); - if (type != AF_INET && type != AF_INET6) { - continue; - } - - if (type == AF_INET6) { - RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, autoGateway.get())); - } else { /* type == AF_INET */ - RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(autoGateway.get()))); - } - } - } else { - // Set default froute from system properties. - char key[Property::KEY_MAX_LENGTH]; - char gateway[Property::KEY_MAX_LENGTH]; - - snprintf(key, sizeof key - 1, "net.%s.gw", autoIfname.get()); - Property::Get(key, gateway, ""); - - int type = getIpType(gateway); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - if (type == AF_INET6) { - RETURN_IF_FAILED(mNetUtils->do_ifc_add_route(autoIfname.get(), "::", 0, gateway)); - } else { /* type == AF_INET */ - RETURN_IF_FAILED(mNetUtils->do_ifc_set_default_route(autoIfname.get(), inet_addr(gateway))); - } - } - - // Set the default DNS interface. - if (SDK_VERSION >= 18) { - // For JB, KK only. - static CommandFunc COMMAND_CHAIN[] = { - setDefaultInterface, - defaultAsyncSuccessHandler - }; - runChain(aOptions, COMMAND_CHAIN, setDnsFail); - return CommandResult::Pending(); - } - - return SUCCESS; -} - -/** - * Remove default route for given network interface. - */ -CommandResult NetworkUtils::removeDefaultRoute(NetworkParams& aOptions) -{ - NU_DBG("Calling NetworkUtils::removeDefaultRoute"); - - if (SDK_VERSION < 20) { - return removeDefaultRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - removeDefaultRoute, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - aOptions.mLoopIndex = 0; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Remove default route for given network interface by obsoleted libnetutils. - */ -CommandResult NetworkUtils::removeDefaultRouteLegacy(NetworkParams& aOptions) -{ - // Legacy libnetutils calls before Lollipop. - uint32_t length = aOptions.mGateways.Length(); - for (uint32_t i = 0; i < length; i++) { - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateways[i]); - - int type = getIpType(autoGateway.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - WARN_IF_FAILED(mNetUtils->do_ifc_remove_route(GET_CHAR(mIfname), - type == AF_INET ? "0.0.0.0" : "::", - 0, autoGateway.get())); - } - - return SUCCESS; -} - -/** - * Add host route for given network interface. - */ -CommandResult NetworkUtils::addHostRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return addHostRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - addRouteToInterface, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Add host route for given network interface. - */ -CommandResult NetworkUtils::addHostRouteLegacy(NetworkParams& aOptions) -{ - if (aOptions.mGateway.IsEmpty()) { - ERROR("addHostRouteLegacy does not support empty gateway."); - return EINVAL; - } - - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp); - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway); - int type, prefix; - - type = getIpType(autoHostname.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - if (type != getIpType(autoGateway.get())) { - return EINVAL; - } - - prefix = type == AF_INET ? 32 : 128; - return mNetUtils->do_ifc_add_route(autoIfname.get(), autoHostname.get(), - prefix, autoGateway.get()); -} - -/** - * Remove host route for given network interface. - */ -CommandResult NetworkUtils::removeHostRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return removeHostRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - removeRouteFromInterface, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * Remove host route for given network interface. - */ -CommandResult NetworkUtils::removeHostRouteLegacy(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - NS_ConvertUTF16toUTF8 autoHostname(aOptions.mIp); - NS_ConvertUTF16toUTF8 autoGateway(aOptions.mGateway); - int type, prefix; - - type = getIpType(autoHostname.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - if (type != getIpType(autoGateway.get())) { - return EINVAL; - } - - prefix = type == AF_INET ? 32 : 128; - return mNetUtils->do_ifc_remove_route(autoIfname.get(), autoHostname.get(), - prefix, autoGateway.get()); -} - -CommandResult NetworkUtils::removeNetworkRoute(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return removeNetworkRouteLegacy(aOptions); - } - - static CommandFunc COMMAND_CHAIN[] = { - clearAddrForInterface, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("interface %s is not present in any network", GET_CHAR(mIfname)); - return -1; - } - - NU_DBG("Obtained netid %d for interface %s", netIdInfo.mNetId, GET_CHAR(mIfname)); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -nsCString NetworkUtils::getSubnetIp(const nsCString& aIp, int aPrefixLength) -{ - int type = getIpType(aIp.get()); - - if (AF_INET6 == type) { - struct in6_addr in6; - if (inet_pton(AF_INET6, aIp.get(), &in6) != 1) { - return nsCString(); - } - - uint32_t p, i, p1, mask; - p = aPrefixLength; - i = 0; - while (i < 4) { - p1 = p > 32 ? 32 : p; - p -= p1; - mask = p1 ? ~0x0 << (32 - p1) : 0; - in6.s6_addr32[i++] &= htonl(mask); - } - - char subnetStr[INET6_ADDRSTRLEN]; - if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) { - return nsCString(); - } - - return nsCString(subnetStr); - } - - if (AF_INET == type) { - uint32_t ip = inet_addr(aIp.get()); - uint32_t netmask = makeMask(aPrefixLength); - uint32_t subnet = ip & netmask; - struct in_addr addr; - addr.s_addr = subnet; - return nsCString(inet_ntoa(addr)); - } - - return nsCString(); -} - -CommandResult NetworkUtils::removeNetworkRouteLegacy(NetworkParams& aOptions) -{ - NS_ConvertUTF16toUTF8 autoIfname(aOptions.mIfname); - NS_ConvertUTF16toUTF8 autoIp(aOptions.mIp); - - int type = getIpType(autoIp.get()); - if (type != AF_INET && type != AF_INET6) { - return EAFNOSUPPORT; - } - - uint32_t prefixLength = GET_FIELD(mPrefixLength); - - if (type == AF_INET6) { - // Calculate subnet. - struct in6_addr in6; - if (inet_pton(AF_INET6, autoIp.get(), &in6) != 1) { - return EINVAL; - } - - uint32_t p, i, p1, mask; - p = prefixLength; - i = 0; - while (i < 4) { - p1 = p > 32 ? 32 : p; - p -= p1; - mask = p1 ? ~0x0 << (32 - p1) : 0; - in6.s6_addr32[i++] &= htonl(mask); - } - - char subnetStr[INET6_ADDRSTRLEN]; - if (!inet_ntop(AF_INET6, &in6, subnetStr, sizeof subnetStr)) { - return EINVAL; - } - - // Remove default route. - WARN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), "::", 0, NULL)); - - // Remove subnet route. - RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), subnetStr, prefixLength, NULL)); - return SUCCESS; - } - - /* type == AF_INET */ - uint32_t ip = inet_addr(autoIp.get()); - uint32_t netmask = makeMask(prefixLength); - uint32_t subnet = ip & netmask; - const char* gateway = "0.0.0.0"; - struct in_addr addr; - addr.s_addr = subnet; - const char* dst = inet_ntoa(addr); - - RETURN_IF_FAILED(mNetUtils->do_ifc_remove_default_route(autoIfname.get())); - RETURN_IF_FAILED(mNetUtils->do_ifc_remove_route(autoIfname.get(), dst, prefixLength, gateway)); - return SUCCESS; -} - -CommandResult NetworkUtils::addSecondaryRoute(NetworkParams& aOptions) -{ - static CommandFunc COMMAND_CHAIN[] = { - addRouteToSecondaryTable, - defaultAsyncSuccessHandler - }; - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) { - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::removeSecondaryRoute(NetworkParams& aOptions) -{ - static CommandFunc COMMAND_CHAIN[] = { - removeRouteFromSecondaryTable, - defaultAsyncSuccessHandler - }; - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mIfname, &netIdInfo)) { - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setNetworkInterfaceAlarm(NetworkParams& aOptions) -{ - NU_DBG("setNetworkInterfaceAlarms: %s", GET_CHAR(mIfname)); - runChain(aOptions, sNetworkInterfaceSetAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::enableNetworkInterfaceAlarm(NetworkParams& aOptions) -{ - NU_DBG("enableNetworkInterfaceAlarm: %s", GET_CHAR(mIfname)); - runChain(aOptions, sNetworkInterfaceEnableAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::disableNetworkInterfaceAlarm(NetworkParams& aOptions) -{ - NU_DBG("disableNetworkInterfaceAlarms: %s", GET_CHAR(mIfname)); - runChain(aOptions, sNetworkInterfaceDisableAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setTetheringAlarm(NetworkParams& aOptions) -{ - NU_DBG("setTetheringAlarm"); - runChain(aOptions, sTetheringInterfaceSetAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::removeTetheringAlarm(NetworkParams& aOptions) -{ - NU_DBG("removeTetheringAlarm"); - runChain(aOptions, sTetheringInterfaceRemoveAlarmChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::getTetheringStatus(NetworkParams& aOptions) -{ - NU_DBG("getTetheringStatus"); - runChain(aOptions, sTetheringGetStatusChain, networkInterfaceAlarmFail); - return CommandResult::Pending(); -} - -/** - * handling main thread's reload Wifi firmware request - */ -CommandResult NetworkUtils::setWifiOperationMode(NetworkParams& aOptions) -{ - NU_DBG("setWifiOperationMode: %s %s", GET_CHAR(mIfname), GET_CHAR(mMode)); - runChain(aOptions, sWifiOperationModeChain, wifiOperationModeFail); - return CommandResult::Pending(); -} - -/** - * handling main thread's enable/disable WiFi Tethering request - */ -CommandResult NetworkUtils::setWifiTethering(NetworkParams& aOptions) -{ - bool enable = aOptions.mEnable; - IFProperties interfaceProperties; - getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties); - - if (strcmp(interfaceProperties.dns1, "")) { - int type = getIpType(interfaceProperties.dns1); - if (type != AF_INET6) { - aOptions.mDns1 = NS_ConvertUTF8toUTF16(interfaceProperties.dns1); - } - } - if (strcmp(interfaceProperties.dns2, "")) { - int type = getIpType(interfaceProperties.dns2); - if (type != AF_INET6) { - aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2); - } - } - dumpParams(aOptions, "WIFI"); - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mExternalIfname, &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mExternalIfname)); - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - if (enable) { - NU_DBG("Starting Wifi Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sWifiEnableChain, wifiTetheringFail); - } else { - NU_DBG("Stopping Wifi Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sWifiDisableChain, wifiTetheringFail); - } - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setUSBTethering(NetworkParams& aOptions) -{ - bool enable = aOptions.mEnable; - IFProperties interfaceProperties; - getIFProperties(GET_CHAR(mExternalIfname), interfaceProperties); - - if (strcmp(interfaceProperties.dns1, "")) { - int type = getIpType(interfaceProperties.dns1); - if (type != AF_INET6) { - aOptions.mDns1 = NS_ConvertUTF8toUTF16(interfaceProperties.dns1); - } - } - if (strcmp(interfaceProperties.dns2, "")) { - int type = getIpType(interfaceProperties.dns2); - if (type != AF_INET6) { - aOptions.mDns2 = NS_ConvertUTF8toUTF16(interfaceProperties.dns2); - } - } - dumpParams(aOptions, "USB"); - - if (SDK_VERSION >= 20) { - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.lookup(aOptions.mExternalIfname, &netIdInfo)) { - ERROR("No such interface: %s", GET_CHAR(mExternalIfname)); - return -1; - } - aOptions.mNetId = netIdInfo.mNetId; - } - - if (enable) { - NU_DBG("Starting USB Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sUSBEnableChain, usbTetheringFail); - } else { - NU_DBG("Stopping USB Tethering on %s <-> %s", - GET_CHAR(mInternalIfname), GET_CHAR(mExternalIfname)); - runChain(aOptions, sUSBDisableChain, usbTetheringFail); - } - return CommandResult::Pending(); -} - -void NetworkUtils::escapeQuote(nsCString& aString) -{ - aString.ReplaceSubstring("\\", "\\\\"); - aString.ReplaceSubstring("\"", "\\\""); -} - -CommandResult NetworkUtils::checkUsbRndisState(NetworkParams& aOptions) -{ - static uint32_t retry = 0; - - char currentState[Property::VALUE_MAX_LENGTH]; - Property::Get(SYS_USB_STATE_PROPERTY, currentState, nullptr); - - nsTArray stateFuncs; - split(currentState, USB_CONFIG_DELIMIT, stateFuncs); - bool rndisPresent = stateFuncs.Contains(nsCString(USB_FUNCTION_RNDIS)); - - if (aOptions.mEnable == rndisPresent) { - NetworkResultOptions result; - result.mEnable = aOptions.mEnable; - result.mResult = true; - retry = 0; - return result; - } - if (retry < USB_FUNCTION_RETRY_TIMES) { - retry++; - usleep(USB_FUNCTION_RETRY_INTERVAL * 1000); - return checkUsbRndisState(aOptions); - } - - NetworkResultOptions result; - result.mResult = false; - retry = 0; - return result; -} - -/** - * Modify usb function's property to turn on USB RNDIS function - */ -CommandResult NetworkUtils::enableUsbRndis(NetworkParams& aOptions) -{ - bool report = aOptions.mReport; - - // For some reason, rndis doesn't play well with diag,modem,nmea. - // So when turning rndis on, we set sys.usb.config to either "rndis" - // or "rndis,adb". When turning rndis off, we go back to - // persist.sys.usb.config. - // - // On the otoro/unagi, persist.sys.usb.config should be one of: - // - // diag,modem,nmea,mass_storage - // diag,modem,nmea,mass_storage,adb - // - // When rndis is enabled, sys.usb.config should be one of: - // - // rdnis - // rndis,adb - // - // and when rndis is disabled, it should revert to persist.sys.usb.config - - char currentConfig[Property::VALUE_MAX_LENGTH]; - Property::Get(SYS_USB_CONFIG_PROPERTY, currentConfig, nullptr); - - nsTArray configFuncs; - split(currentConfig, USB_CONFIG_DELIMIT, configFuncs); - - char persistConfig[Property::VALUE_MAX_LENGTH]; - Property::Get(PERSIST_SYS_USB_CONFIG_PROPERTY, persistConfig, nullptr); - - nsTArray persistFuncs; - split(persistConfig, USB_CONFIG_DELIMIT, persistFuncs); - - if (aOptions.mEnable) { - configFuncs.Clear(); - configFuncs.AppendElement(nsCString(USB_FUNCTION_RNDIS)); - if (persistFuncs.Contains(nsCString(USB_FUNCTION_ADB))) { - configFuncs.AppendElement(nsCString(USB_FUNCTION_ADB)); - } - } else { - // We're turning rndis off, revert back to the persist setting. - // adb will already be correct there, so we don't need to do any - // further adjustments. - configFuncs = persistFuncs; - } - - char newConfig[Property::VALUE_MAX_LENGTH] = ""; - Property::Get(SYS_USB_CONFIG_PROPERTY, currentConfig, nullptr); - join(configFuncs, USB_CONFIG_DELIMIT, Property::VALUE_MAX_LENGTH, newConfig); - if (strcmp(currentConfig, newConfig)) { - Property::Set(SYS_USB_CONFIG_PROPERTY, newConfig); - } - - // Trigger the timer to check usb state and report the result to NetworkManager. - if (report) { - usleep(USB_FUNCTION_RETRY_INTERVAL * 1000); - return checkUsbRndisState(aOptions); - } - return SUCCESS; -} - -/** - * handling upstream interface change event. - */ -CommandResult NetworkUtils::updateUpStream(NetworkParams& aOptions) -{ - runChain(aOptions, sUpdateUpStreamChain, updateUpStreamFail); - return CommandResult::Pending(); -} - -/** - * handling upstream interface change event. - */ -CommandResult NetworkUtils::createNetwork(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return SUCCESS; - } - - static CommandFunc COMMAND_CHAIN[] = { - createNetwork, - enableIpv6, - addInterfaceToNetwork, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - mNetIdManager.acquire(GET_FIELD(mIfname), &netIdInfo); - if (netIdInfo.mRefCnt > 1) { - // Already created. Just return. - NU_DBG("Interface %s (%d) has been created.", GET_CHAR(mIfname), - netIdInfo.mNetId); - return SUCCESS; - } - - NU_DBG("Request netd to create a network with netid %d", netIdInfo.mNetId); - // Newly created netid. Ask netd to create network. - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - - return CommandResult::Pending(); -} - -/** - * handling upstream interface change event. - */ -CommandResult NetworkUtils::destroyNetwork(NetworkParams& aOptions) -{ - if (SDK_VERSION < 20) { - return SUCCESS; - } - - static CommandFunc COMMAND_CHAIN[] = { - disableIpv6, - destroyNetwork, - defaultAsyncSuccessHandler, - }; - - NetIdManager::NetIdInfo netIdInfo; - if (!mNetIdManager.release(GET_FIELD(mIfname), &netIdInfo)) { - ERROR("No existing netid for %s", GET_CHAR(mIfname)); - return -1; - } - - if (netIdInfo.mRefCnt > 0) { - // Still be referenced. Just return. - NU_DBG("Someone is still using this interface."); - return SUCCESS; - } - - NU_DBG("Interface %s (%d) is no longer used. Tell netd to destroy.", - GET_CHAR(mIfname), netIdInfo.mNetId); - - aOptions.mNetId = netIdInfo.mNetId; - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -/** - * Query the netId associated with the given network interface name. - */ -CommandResult NetworkUtils::getNetId(NetworkParams& aOptions) -{ - NetworkResultOptions result; - - if (SDK_VERSION < 20) { - // For pre-Lollipop, use the interface name as the fallback. - result.mNetId = GET_FIELD(mIfname); - return result; - } - - NetIdManager::NetIdInfo netIdInfo; - if (-1 == mNetIdManager.lookup(GET_FIELD(mIfname), &netIdInfo)) { - return ESRCH; - } - result.mNetId.AppendInt(netIdInfo.mNetId, 10); - return result; -} - -/** - * Get existing network interfaces. - */ -CommandResult NetworkUtils::getInterfaces(NetworkParams& aOptions) -{ - runChain(aOptions, sGetInterfacesChain, getInterfacesFail); - return CommandResult::Pending(); -} - -/** - * Get network config of a specified interface. - */ -CommandResult NetworkUtils::getInterfaceConfig(NetworkParams& aOptions) -{ - runChain(aOptions, sGetInterfaceConfigChain, getInterfaceConfigFail); - return CommandResult::Pending(); -} - -/** - * Set network config for a specified interface. - */ -CommandResult NetworkUtils::setInterfaceConfig(NetworkParams& aOptions) -{ - runChain(aOptions, sSetInterfaceConfigChain, setInterfaceConfigFail); - return CommandResult::Pending(); -} - -CommandResult NetworkUtils::setMtu(NetworkParams& aOptions) -{ - // Setting/getting mtu is supported since Kitkat. - if (SDK_VERSION < 19) { - ERROR("setMtu is not supported in current SDK_VERSION."); - return -1; - } - - static CommandFunc COMMAND_CHAIN[] = { - setMtu, - defaultAsyncSuccessHandler, - }; - - runChain(aOptions, COMMAND_CHAIN, defaultAsyncFailureHandler); - return CommandResult::Pending(); -} - -void NetworkUtils::sendBroadcastMessage(uint32_t code, char* reason) -{ - NetworkResultOptions result; - switch(code) { - case NETD_COMMAND_INTERFACE_CHANGE: - result.mTopic = NS_ConvertUTF8toUTF16("netd-interface-change"); - break; - case NETD_COMMAND_BANDWIDTH_CONTROLLER: - result.mTopic = NS_ConvertUTF8toUTF16("netd-bandwidth-control"); - break; - default: - return; - } - - result.mBroadcast = true; - result.mReason = NS_ConvertUTF8toUTF16(reason); - postMessage(result); -} - -inline uint32_t NetworkUtils::netdResponseType(uint32_t code) -{ - return (code / 100) * 100; -} - -inline bool NetworkUtils::isBroadcastMessage(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type == NETD_COMMAND_UNSOLICITED; -} - -inline bool NetworkUtils::isError(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type != NETD_COMMAND_PROCEEDING && type != NETD_COMMAND_OKAY; -} - -inline bool NetworkUtils::isComplete(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type != NETD_COMMAND_PROCEEDING; -} - -inline bool NetworkUtils::isProceeding(uint32_t code) -{ - uint32_t type = netdResponseType(code); - return type == NETD_COMMAND_PROCEEDING; -} - -void NetworkUtils::dumpParams(NetworkParams& aOptions, const char* aType) -{ -#ifdef _DEBUG - NU_DBG("Dump params:"); - NU_DBG(" ifname: %s", GET_CHAR(mIfname)); - NU_DBG(" ip: %s", GET_CHAR(mIp)); - NU_DBG(" link: %s", GET_CHAR(mLink)); - NU_DBG(" prefix: %s", GET_CHAR(mPrefix)); - NU_DBG(" wifiStartIp: %s", GET_CHAR(mWifiStartIp)); - NU_DBG(" wifiEndIp: %s", GET_CHAR(mWifiEndIp)); - NU_DBG(" usbStartIp: %s", GET_CHAR(mUsbStartIp)); - NU_DBG(" usbEndIp: %s", GET_CHAR(mUsbEndIp)); - NU_DBG(" dnsserver1: %s", GET_CHAR(mDns1)); - NU_DBG(" dnsserver2: %s", GET_CHAR(mDns2)); - NU_DBG(" internalIfname: %s", GET_CHAR(mInternalIfname)); - NU_DBG(" externalIfname: %s", GET_CHAR(mExternalIfname)); - if (!strcmp(aType, "WIFI")) { - NU_DBG(" wifictrlinterfacename: %s", GET_CHAR(mWifictrlinterfacename)); - NU_DBG(" ssid: %s", GET_CHAR(mSsid)); - NU_DBG(" security: %s", GET_CHAR(mSecurity)); - NU_DBG(" key: %s", GET_CHAR(mKey)); - } -#endif -} - -#undef GET_CHAR -#undef GET_FIELD diff --git a/dom/system/gonk/NetworkUtils.h b/dom/system/gonk/NetworkUtils.h deleted file mode 100644 index d1af35f09..000000000 --- a/dom/system/gonk/NetworkUtils.h +++ /dev/null @@ -1,498 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NetworkUtils_h -#define NetworkUtils_h - -#include "nsAutoPtr.h" -#include "nsString.h" -#include "mozilla/dom/NetworkOptionsBinding.h" -#include "mozilla/dom/network/NetUtils.h" -#include "mozilla/ipc/Netd.h" -#include "nsTArray.h" -#include "NetIdManager.h" - -class NetworkParams; -class CommandChain; - -class CommandCallback { -public: - typedef void (*CallbackType)(CommandChain*, bool, - mozilla::dom::NetworkResultOptions& aResult); - - typedef void (*CallbackWrapperType)(CallbackType aOriginalCallback, - CommandChain*, bool, - mozilla::dom::NetworkResultOptions& aResult); - - CommandCallback() - : mCallback(nullptr) - , mCallbackWrapper(nullptr) - { - } - - CommandCallback(CallbackType aCallback) - : mCallback(aCallback) - , mCallbackWrapper(nullptr) - { - } - - CommandCallback(CallbackWrapperType aCallbackWrapper, - CommandCallback aOriginalCallback) - : mCallback(aOriginalCallback.mCallback) - , mCallbackWrapper(aCallbackWrapper) - { - } - - void operator()(CommandChain* aChain, bool aError, - mozilla::dom::NetworkResultOptions& aResult) - { - if (mCallbackWrapper) { - return mCallbackWrapper(mCallback, aChain, aError, aResult); - } - if (mCallback) { - return mCallback(aChain, aError, aResult); - } - } - -private: - CallbackType mCallback; - CallbackWrapperType mCallbackWrapper; -}; - -typedef void (*CommandFunc)(CommandChain*, CommandCallback, - mozilla::dom::NetworkResultOptions& aResult); -typedef void (*MessageCallback)(mozilla::dom::NetworkResultOptions& aResult); -typedef void (*ErrorCallback)(NetworkParams& aOptions, - mozilla::dom::NetworkResultOptions& aResult); - -class NetworkParams -{ -public: - NetworkParams() { - } - - NetworkParams(const mozilla::dom::NetworkCommandOptions& aOther) { - -#define COPY_SEQUENCE_FIELD(prop, type) \ - if (aOther.prop.WasPassed()) { \ - mozilla::dom::Sequence const & currentValue = aOther.prop.InternalValue(); \ - uint32_t length = currentValue.Length(); \ - for (uint32_t idx = 0; idx < length; idx++) { \ - prop.AppendElement(currentValue[idx]); \ - } \ - } - -#define COPY_OPT_STRING_FIELD(prop, defaultValue) \ - if (aOther.prop.WasPassed()) { \ - if (aOther.prop.Value().EqualsLiteral("null")) { \ - prop = defaultValue; \ - } else { \ - prop = aOther.prop.Value(); \ - } \ - } else { \ - prop = defaultValue; \ - } - -#define COPY_OPT_FIELD(prop, defaultValue) \ - if (aOther.prop.WasPassed()) { \ - prop = aOther.prop.Value(); \ - } else { \ - prop = defaultValue; \ - } - -#define COPY_FIELD(prop) prop = aOther.prop; - - COPY_FIELD(mId) - COPY_FIELD(mCmd) - COPY_OPT_STRING_FIELD(mDomain, EmptyString()) - COPY_OPT_STRING_FIELD(mGateway, EmptyString()) - COPY_SEQUENCE_FIELD(mGateways, nsString) - COPY_OPT_STRING_FIELD(mIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mIp, EmptyString()) - COPY_OPT_FIELD(mPrefixLength, 0) - COPY_OPT_STRING_FIELD(mMode, EmptyString()) - COPY_OPT_FIELD(mReport, false) - COPY_OPT_FIELD(mEnabled, false) - COPY_OPT_STRING_FIELD(mWifictrlinterfacename, EmptyString()) - COPY_OPT_STRING_FIELD(mInternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mExternalIfname, EmptyString()) - COPY_OPT_FIELD(mEnable, false) - COPY_OPT_STRING_FIELD(mSsid, EmptyString()) - COPY_OPT_STRING_FIELD(mSecurity, EmptyString()) - COPY_OPT_STRING_FIELD(mKey, EmptyString()) - COPY_OPT_STRING_FIELD(mPrefix, EmptyString()) - COPY_OPT_STRING_FIELD(mLink, EmptyString()) - COPY_SEQUENCE_FIELD(mInterfaceList, nsString) - COPY_OPT_STRING_FIELD(mWifiStartIp, EmptyString()) - COPY_OPT_STRING_FIELD(mWifiEndIp, EmptyString()) - COPY_OPT_STRING_FIELD(mUsbStartIp, EmptyString()) - COPY_OPT_STRING_FIELD(mUsbEndIp, EmptyString()) - COPY_OPT_STRING_FIELD(mDns1, EmptyString()) - COPY_OPT_STRING_FIELD(mDns2, EmptyString()) - COPY_SEQUENCE_FIELD(mDnses, nsString) - COPY_OPT_STRING_FIELD(mStartIp, EmptyString()) - COPY_OPT_STRING_FIELD(mEndIp, EmptyString()) - COPY_OPT_STRING_FIELD(mServerIp, EmptyString()) - COPY_OPT_STRING_FIELD(mMaskLength, EmptyString()) - COPY_OPT_STRING_FIELD(mPreInternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mPreExternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mCurInternalIfname, EmptyString()) - COPY_OPT_STRING_FIELD(mCurExternalIfname, EmptyString()) - COPY_OPT_FIELD(mThreshold, -1) - COPY_OPT_FIELD(mIpaddr, 0) - COPY_OPT_FIELD(mMask, 0) - COPY_OPT_FIELD(mGateway_long, 0) - COPY_OPT_FIELD(mDns1_long, 0) - COPY_OPT_FIELD(mDns2_long, 0) - COPY_OPT_FIELD(mMtu, 0) - - mLoopIndex = 0; - -#undef COPY_SEQUENCE_FIELD -#undef COPY_OPT_STRING_FIELD -#undef COPY_OPT_FIELD -#undef COPY_FIELD - } - - // Followings attributes are 1-to-1 mapping to NetworkCommandOptions. - int32_t mId; - nsString mCmd; - nsString mDomain; - nsString mGateway; - nsTArray mGateways; - nsString mIfname; - nsString mIp; - uint32_t mPrefixLength; - nsString mMode; - bool mReport; - bool mEnabled; - nsString mWifictrlinterfacename; - nsString mInternalIfname; - nsString mExternalIfname; - bool mEnable; - nsString mSsid; - nsString mSecurity; - nsString mKey; - nsString mPrefix; - nsString mLink; - nsTArray mInterfaceList; - nsString mWifiStartIp; - nsString mWifiEndIp; - nsString mUsbStartIp; - nsString mUsbEndIp; - nsString mDns1; - nsString mDns2; - nsTArray mDnses; - nsString mStartIp; - nsString mEndIp; - nsString mServerIp; - nsString mMaskLength; - nsString mPreInternalIfname; - nsString mPreExternalIfname; - nsString mCurInternalIfname; - nsString mCurExternalIfname; - long long mThreshold; - long mIpaddr; - long mMask; - long mGateway_long; - long mDns1_long; - long mDns2_long; - long mMtu; - - // Auxiliary information required to carry accros command chain. - int mNetId; // A locally defined id per interface. - uint32_t mLoopIndex; // Loop index for adding/removing multiple gateways. -}; - -// CommandChain store the necessary information to execute command one by one. -// Including : -// 1. Command parameters. -// 2. Command list. -// 3. Error callback function. -// 4. Index of current execution command. -class CommandChain final -{ -public: - CommandChain(const NetworkParams& aParams, - const CommandFunc aCmds[], - uint32_t aLength, - ErrorCallback aError) - : mIndex(-1) - , mParams(aParams) - , mCommands(aCmds) - , mLength(aLength) - , mError(aError) { - } - - NetworkParams& - getParams() - { - return mParams; - }; - - CommandFunc - getNextCommand() - { - mIndex++; - return mIndex < mLength ? mCommands[mIndex] : nullptr; - }; - - ErrorCallback - getErrorCallback() const - { - return mError; - }; - -private: - uint32_t mIndex; - NetworkParams mParams; - const CommandFunc* mCommands; - uint32_t mLength; - ErrorCallback mError; -}; - -// A helper class to easily construct a resolved -// or a pending result for command execution. -class CommandResult -{ -public: - struct Pending {}; - -public: - CommandResult(int32_t aResultCode); - CommandResult(const mozilla::dom::NetworkResultOptions& aResult); - CommandResult(const Pending&); - bool isPending() const; - - mozilla::dom::NetworkResultOptions mResult; - -private: - bool mIsPending; -}; - -class NetworkUtils final -{ -public: - NetworkUtils(MessageCallback aCallback); - ~NetworkUtils(); - - void ExecuteCommand(NetworkParams aOptions); - void onNetdMessage(mozilla::ipc::NetdCommand* aCommand); - - MessageCallback getMessageCallback() { return mMessageCallback; } - -private: - /** - * Commands supported by NetworkUtils. - */ - CommandResult configureInterface(NetworkParams& aOptions); - CommandResult dhcpRequest(NetworkParams& aOptions); - CommandResult stopDhcp(NetworkParams& aOptions); - CommandResult enableInterface(NetworkParams& aOptions); - CommandResult disableInterface(NetworkParams& aOptions); - CommandResult resetConnections(NetworkParams& aOptions); - CommandResult setDefaultRoute(NetworkParams& aOptions); - CommandResult addHostRoute(NetworkParams& aOptions); - CommandResult removeDefaultRoute(NetworkParams& aOptions); - CommandResult removeHostRoute(NetworkParams& aOptions); - CommandResult removeNetworkRoute(NetworkParams& aOptions); - CommandResult setDNS(NetworkParams& aOptions); - CommandResult addSecondaryRoute(NetworkParams& aOptions); - CommandResult removeSecondaryRoute(NetworkParams& aOptions); - CommandResult setNetworkInterfaceAlarm(NetworkParams& aOptions); - CommandResult enableNetworkInterfaceAlarm(NetworkParams& aOptions); - CommandResult disableNetworkInterfaceAlarm(NetworkParams& aOptions); - CommandResult setTetheringAlarm(NetworkParams& aOptions); - CommandResult removeTetheringAlarm(NetworkParams& aOptions); - CommandResult getTetheringStatus(NetworkParams& aOptions); - CommandResult setWifiOperationMode(NetworkParams& aOptions); - CommandResult setDhcpServer(NetworkParams& aOptions); - CommandResult setWifiTethering(NetworkParams& aOptions); - CommandResult setUSBTethering(NetworkParams& aOptions); - CommandResult enableUsbRndis(NetworkParams& aOptions); - CommandResult updateUpStream(NetworkParams& aOptions); - CommandResult createNetwork(NetworkParams& aOptions); - CommandResult destroyNetwork(NetworkParams& aOptions); - CommandResult getNetId(NetworkParams& aOptions); - CommandResult setMtu(NetworkParams& aOptions); - CommandResult getInterfaces(NetworkParams& aOptions); - CommandResult getInterfaceConfig(NetworkParams& aOptions); - CommandResult setInterfaceConfig(NetworkParams& aOptions); - - CommandResult addHostRouteLegacy(NetworkParams& aOptions); - CommandResult removeHostRouteLegacy(NetworkParams& aOptions); - CommandResult setDefaultRouteLegacy(NetworkParams& aOptions); - CommandResult removeDefaultRouteLegacy(NetworkParams& aOptions); - CommandResult removeNetworkRouteLegacy(NetworkParams& aOptions); - - - /** - * function pointer array holds all netd commands should be executed - * in sequence to accomplish a given command by other module. - */ - static const CommandFunc sWifiEnableChain[]; - static const CommandFunc sWifiDisableChain[]; - static const CommandFunc sWifiFailChain[]; - static const CommandFunc sWifiRetryChain[]; - static const CommandFunc sWifiOperationModeChain[]; - static const CommandFunc sUSBEnableChain[]; - static const CommandFunc sUSBDisableChain[]; - static const CommandFunc sUSBFailChain[]; - static const CommandFunc sUpdateUpStreamChain[]; - static const CommandFunc sStartDhcpServerChain[]; - static const CommandFunc sStopDhcpServerChain[]; - static const CommandFunc sNetworkInterfaceEnableAlarmChain[]; - static const CommandFunc sNetworkInterfaceDisableAlarmChain[]; - static const CommandFunc sNetworkInterfaceSetAlarmChain[]; - static const CommandFunc sTetheringInterfaceSetAlarmChain[]; - static const CommandFunc sTetheringInterfaceRemoveAlarmChain[]; - static const CommandFunc sTetheringGetStatusChain[]; - static const CommandFunc sGetInterfacesChain[]; - static const CommandFunc sGetInterfaceConfigChain[]; - static const CommandFunc sSetInterfaceConfigChain[]; - - /** - * Individual netd command stored in command chain. - */ -#define PARAMS CommandChain* aChain, CommandCallback aCallback, \ - mozilla::dom::NetworkResultOptions& aResult - static void wifiFirmwareReload(PARAMS); - static void startAccessPointDriver(PARAMS); - static void stopAccessPointDriver(PARAMS); - static void setAccessPoint(PARAMS); - static void cleanUpStream(PARAMS); - static void createUpStream(PARAMS); - static void startSoftAP(PARAMS); - static void stopSoftAP(PARAMS); - static void clearWifiTetherParms(PARAMS); - static void enableAlarm(PARAMS); - static void disableAlarm(PARAMS); - static void setQuota(PARAMS); - static void removeQuota(PARAMS); - static void setAlarm(PARAMS); - static void removeAlarm(PARAMS); - static void setGlobalAlarm(PARAMS); - static void removeGlobalAlarm(PARAMS); - static void tetherInterface(PARAMS); - static void addInterfaceToLocalNetwork(PARAMS); - static void addRouteToLocalNetwork(PARAMS); - static void preTetherInterfaceList(PARAMS); - static void postTetherInterfaceList(PARAMS); - static void addUpstreamInterface(PARAMS); - static void removeUpstreamInterface(PARAMS); - static void setIpForwardingEnabled(PARAMS); - static void tetheringStatus(PARAMS); - static void stopTethering(PARAMS); - static void startTethering(PARAMS); - static void untetherInterface(PARAMS); - static void removeInterfaceFromLocalNetwork(PARAMS); - static void setDnsForwarders(PARAMS); - static void enableNat(PARAMS); - static void disableNat(PARAMS); - static void setDefaultInterface(PARAMS); - static void setInterfaceDns(PARAMS); - static void getInterfaceList(PARAMS); - static void getConfig(PARAMS); - static void setConfig(PARAMS); - static void wifiTetheringSuccess(PARAMS); - static void usbTetheringSuccess(PARAMS); - static void networkInterfaceAlarmSuccess(PARAMS); - static void updateUpStreamSuccess(PARAMS); - static void setDhcpServerSuccess(PARAMS); - static void wifiOperationModeSuccess(PARAMS); - static void clearAddrForInterface(PARAMS); - static void createNetwork(PARAMS); - static void destroyNetwork(PARAMS); - static void addInterfaceToNetwork(PARAMS); - static void addDefaultRouteToNetwork(PARAMS); - static void setDefaultNetwork(PARAMS); - static void removeDefaultRoute(PARAMS); - static void removeNetworkRouteSuccess(PARAMS); - static void removeNetworkRoute(PARAMS); - static void addRouteToInterface(PARAMS); - static void removeRouteFromInterface(PARAMS); - static void modifyRouteOnInterface(PARAMS, bool aDoAdd); - static void enableIpv6(PARAMS); - static void disableIpv6(PARAMS); - static void setMtu(PARAMS); - static void setIpv6Enabled(PARAMS, bool aEnabled); - static void addRouteToSecondaryTable(PARAMS); - static void removeRouteFromSecondaryTable(PARAMS); - static void defaultAsyncSuccessHandler(PARAMS); - static void getInterfacesSuccess(PARAMS); - static void getInterfaceConfigSuccess(PARAMS); - static void setInterfaceConfigSuccess(PARAMS); - -#undef PARAMS - - /** - * Error callback function executed when a command is fail. - */ -#define PARAMS NetworkParams& aOptions, \ - mozilla::dom::NetworkResultOptions& aResult - static void wifiTetheringFail(PARAMS); - static void wifiOperationModeFail(PARAMS); - static void usbTetheringFail(PARAMS); - static void updateUpStreamFail(PARAMS); - static void setDhcpServerFail(PARAMS); - static void networkInterfaceAlarmFail(PARAMS); - static void setDnsFail(PARAMS); - static void defaultAsyncFailureHandler(PARAMS); - static void getInterfacesFail(PARAMS); - static void getInterfaceConfigFail(PARAMS); - static void setInterfaceConfigFail(PARAMS); - -#undef PARAMS - - /** - * Command chain processing functions. - */ - static void next(CommandChain* aChain, bool aError, - mozilla::dom::NetworkResultOptions& aResult); - static void nextNetdCommand(); - static void doCommand(const char* aCommand, CommandChain* aChain, CommandCallback aCallback); - - /** - * Notify broadcast message to main thread. - */ - void sendBroadcastMessage(uint32_t code, char* reason); - - /** - * Utility functions. - */ - CommandResult checkUsbRndisState(NetworkParams& aOptions); - void dumpParams(NetworkParams& aOptions, const char* aType); - - static void escapeQuote(nsCString& aString); - inline uint32_t netdResponseType(uint32_t code); - inline bool isBroadcastMessage(uint32_t code); - inline bool isError(uint32_t code); - inline bool isComplete(uint32_t code); - inline bool isProceeding(uint32_t code); - void Shutdown(); - static void runNextQueuedCommandChain(); - static void finalizeSuccess(CommandChain* aChain, - mozilla::dom::NetworkResultOptions& aResult); - - template - static void runChain(const NetworkParams& aParams, - const CommandFunc (&aCmds)[N], - ErrorCallback aError); - - static nsCString getSubnetIp(const nsCString& aIp, int aPrefixLength); - - /** - * Callback function to send netd result to main thread. - */ - MessageCallback mMessageCallback; - - /* - * Utility class to access libnetutils. - */ - nsAutoPtr mNetUtils; - - NetIdManager mNetIdManager; -}; - -#endif diff --git a/dom/system/gonk/NetworkWorker.cpp b/dom/system/gonk/NetworkWorker.cpp deleted file mode 100644 index caf07f375..000000000 --- a/dom/system/gonk/NetworkWorker.cpp +++ /dev/null @@ -1,271 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "NetworkWorker.h" -#include "NetworkUtils.h" -#include -#include "mozilla/ModuleUtils.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/dom/ToJSValue.h" -#include "nsAutoPtr.h" -#include "nsXULAppAPI.h" - -#define NS_NETWORKWORKER_CID \ - { 0x6df093e1, 0x8127, 0x4fa7, {0x90, 0x13, 0xa3, 0xaa, 0xa7, 0x79, 0xbb, 0xdd} } - -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::ipc; - -namespace mozilla { - -nsCOMPtr gWorkerThread; - -// The singleton network worker, to be used on the main thread. -StaticRefPtr gNetworkWorker; - -// The singleton networkutils class, that can be used on any thread. -static nsAutoPtr gNetworkUtils; - -// Runnable used dispatch command result on the main thread. -class NetworkResultDispatcher : public Runnable -{ -public: - NetworkResultDispatcher(const NetworkResultOptions& aResult) - : mResult(aResult) - { - MOZ_ASSERT(!NS_IsMainThread()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - if (gNetworkWorker) { - gNetworkWorker->DispatchNetworkResult(mResult); - } - return NS_OK; - } -private: - NetworkResultOptions mResult; -}; - -// Runnable used dispatch netd command on the worker thread. -class NetworkCommandDispatcher : public Runnable -{ -public: - NetworkCommandDispatcher(const NetworkParams& aParams) - : mParams(aParams) - { - MOZ_ASSERT(NS_IsMainThread()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - if (gNetworkUtils) { - gNetworkUtils->ExecuteCommand(mParams); - } - return NS_OK; - } -private: - NetworkParams mParams; -}; - -// Runnable used dispatch netd result on the worker thread. -class NetdEventRunnable : public Runnable -{ -public: - NetdEventRunnable(NetdCommand* aCommand) - : mCommand(aCommand) - { - MOZ_ASSERT(!NS_IsMainThread()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - if (gNetworkUtils) { - gNetworkUtils->onNetdMessage(mCommand); - } - return NS_OK; - } - -private: - nsAutoPtr mCommand; -}; - -class NetdMessageConsumer : public NetdConsumer -{ -public: - NetdMessageConsumer() - { - MOZ_ASSERT(NS_IsMainThread()); - } - - void MessageReceived(NetdCommand* aCommand) - { - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr runnable = new NetdEventRunnable(aCommand); - if (gWorkerThread) { - gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); - } - } -}; - -NS_IMPL_ISUPPORTS(NetworkWorker, nsINetworkWorker) - -NetworkWorker::NetworkWorker() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!gNetworkWorker); -} - -NetworkWorker::~NetworkWorker() -{ - MOZ_ASSERT(!gNetworkWorker); - MOZ_ASSERT(!mListener); -} - -already_AddRefed -NetworkWorker::FactoryCreate() -{ - if (!XRE_IsParentProcess()) { - return nullptr; - } - - MOZ_ASSERT(NS_IsMainThread()); - - if (!gNetworkWorker) { - gNetworkWorker = new NetworkWorker(); - ClearOnShutdown(&gNetworkWorker); - - gNetworkUtils = new NetworkUtils(NetworkWorker::NotifyResult); - ClearOnShutdown(&gNetworkUtils); - } - - RefPtr worker = gNetworkWorker.get(); - return worker.forget(); -} - -NS_IMETHODIMP -NetworkWorker::Start(nsINetworkEventListener* aListener) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aListener); - - if (mListener) { - return NS_OK; - } - - nsresult rv; - - rv = NS_NewNamedThread("NetworkWorker", getter_AddRefs(gWorkerThread)); - if (NS_FAILED(rv)) { - NS_WARNING("Can't create network control thread"); - return NS_ERROR_FAILURE; - } - - StartNetd(new NetdMessageConsumer()); - mListener = aListener; - - return NS_OK; -} - -NS_IMETHODIMP -NetworkWorker::Shutdown() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!mListener) { - return NS_OK; - } - - StopNetd(); - - gWorkerThread->Shutdown(); - gWorkerThread = nullptr; - - mListener = nullptr; - return NS_OK; -} - -// Receive command from main thread (NetworkService.js). -NS_IMETHODIMP -NetworkWorker::PostMessage(JS::Handle aOptions, JSContext* aCx) -{ - MOZ_ASSERT(NS_IsMainThread()); - - NetworkCommandOptions options; - if (!options.Init(aCx, aOptions)) { - NS_WARNING("Bad dictionary passed to NetworkWorker::SendCommand"); - return NS_ERROR_FAILURE; - } - - // Dispatch the command to the control thread. - NetworkParams NetworkParams(options); - nsCOMPtr runnable = new NetworkCommandDispatcher(NetworkParams); - if (gWorkerThread) { - gWorkerThread->Dispatch(runnable, nsIEventTarget::DISPATCH_NORMAL); - } - return NS_OK; -} - -void -NetworkWorker::DispatchNetworkResult(const NetworkResultOptions& aOptions) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mozilla::AutoSafeJSContext cx; - JS::RootedValue val(cx); - - if (!ToJSValue(cx, aOptions, &val)) { - return; - } - - // Call the listener with a JS value. - if (mListener) { - mListener->OnEvent(val); - } -} - -// Callback function from network worker thread to update result on main thread. -void -NetworkWorker::NotifyResult(NetworkResultOptions& aResult) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr runnable = new NetworkResultDispatcher(aResult); - NS_DispatchToMainThread(runnable); -} - -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(NetworkWorker, - NetworkWorker::FactoryCreate) - -NS_DEFINE_NAMED_CID(NS_NETWORKWORKER_CID); - -static const mozilla::Module::CIDEntry kNetworkWorkerCIDs[] = { - { &kNS_NETWORKWORKER_CID, false, nullptr, NetworkWorkerConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kNetworkWorkerContracts[] = { - { "@mozilla.org/network/worker;1", &kNS_NETWORKWORKER_CID }, - { nullptr } -}; - -static const mozilla::Module kNetworkWorkerModule = { - mozilla::Module::kVersion, - kNetworkWorkerCIDs, - kNetworkWorkerContracts, - nullptr -}; - -} // namespace mozilla - -NSMODULE_DEFN(NetworkWorkerModule) = &kNetworkWorkerModule; diff --git a/dom/system/gonk/NetworkWorker.h b/dom/system/gonk/NetworkWorker.h deleted file mode 100644 index f5c0a8fdd..000000000 --- a/dom/system/gonk/NetworkWorker.h +++ /dev/null @@ -1,37 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef NetworkWorker_h -#define NetworkWorker_h - -#include "mozilla/dom/NetworkOptionsBinding.h" -#include "mozilla/ipc/Netd.h" -#include "nsINetworkWorker.h" -#include "nsCOMPtr.h" -#include "nsThread.h" - -namespace mozilla { - -class NetworkWorker final : public nsINetworkWorker -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSINETWORKWORKER - - static already_AddRefed FactoryCreate(); - - void DispatchNetworkResult(const mozilla::dom::NetworkResultOptions& aOptions); - -private: - NetworkWorker(); - ~NetworkWorker(); - - static void NotifyResult(mozilla::dom::NetworkResultOptions& aResult); - - nsCOMPtr mListener; -}; - -} // namespace mozilla - -#endif // NetworkWorker_h diff --git a/dom/system/gonk/OpenFileFinder.cpp b/dom/system/gonk/OpenFileFinder.cpp deleted file mode 100644 index 388e813e1..000000000 --- a/dom/system/gonk/OpenFileFinder.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "OpenFileFinder.h" - -#include "mozilla/FileUtils.h" -#include "nsPrintfCString.h" - -#include -#include - -#undef USE_DEBUG -#define USE_DEBUG 0 - -#undef LOG -#undef LOGW -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "OpenFileFinder", ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "OpenFileFinder", ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "OpenFileFinder", ## args) - -#undef DBG -#if USE_DEBUG -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, "OpenFileFinder" , ## args) -#else -#define DBG(args...) -#endif - -namespace mozilla { -namespace system { - -OpenFileFinder::OpenFileFinder(const nsACString& aPath, - bool aCheckIsB2gOrDescendant /* = true */) - : mPath(aPath), - mProcDir(nullptr), - mFdDir(nullptr), - mPid(0), - mCheckIsB2gOrDescendant(aCheckIsB2gOrDescendant) -{ - // We assume that we're running in the parent process - mMyPid = getpid(); -} - -OpenFileFinder::~OpenFileFinder() -{ - Close(); -} - -bool -OpenFileFinder::First(OpenFileFinder::Info* aInfo) -{ - Close(); - - mProcDir = opendir("/proc"); - if (!mProcDir) { - return false; - } - mState = NEXT_PID; - return Next(aInfo); -} - -bool -OpenFileFinder::Next(OpenFileFinder::Info* aInfo) -{ - // NOTE: This function calls readdir and readlink, neither of which should - // block since we're using the proc filesystem, which is a purely - // kernel in-memory filesystem and doesn't depend on external driver - // behaviour. - while (mState != DONE) { - switch (mState) { - case NEXT_PID: { - struct dirent *pidEntry; - pidEntry = readdir(mProcDir); - if (!pidEntry) { - mState = DONE; - break; - } - char *endPtr; - mPid = strtol(pidEntry->d_name, &endPtr, 10); - if (mPid == 0 || *endPtr != '\0') { - // Not a +ve number - ignore - continue; - } - // We've found a /proc/PID directory. Scan open file descriptors. - if (mFdDir) { - closedir(mFdDir); - } - nsPrintfCString fdDirPath("/proc/%d/fd", mPid); - mFdDir = opendir(fdDirPath.get()); - if (!mFdDir) { - continue; - } - mState = CHECK_FDS; - } - // Fall through - case CHECK_FDS: { - struct dirent *fdEntry; - while((fdEntry = readdir(mFdDir))) { - if (!strcmp(fdEntry->d_name, ".") || - !strcmp(fdEntry->d_name, "..")) { - continue; - } - nsPrintfCString fdSymLink("/proc/%d/fd/%s", mPid, fdEntry->d_name); - nsCString resolvedPath; - if (ReadSymLink(fdSymLink, resolvedPath) && PathMatches(resolvedPath)) { - // We found an open file contained within the directory tree passed - // into the constructor. - FillInfo(aInfo, resolvedPath); - // If sCheckIsB2gOrDescendant is set false, the caller cares about - // all processes which have open files. If sCheckIsB2gOrDescendant - // is set false, we only care about the b2g proccess or its descendants. - if (!mCheckIsB2gOrDescendant || aInfo->mIsB2gOrDescendant) { - return true; - } - LOG("Ignore process(%d), not a b2g process or its descendant.", - aInfo->mPid); - } - } - // We've checked all of the files for this pid, move onto the next one. - mState = NEXT_PID; - continue; - } - case DONE: - default: - mState = DONE; // covers the default case - break; - } - } - return false; -} - -void -OpenFileFinder::Close() -{ - if (mFdDir) { - closedir(mFdDir); - } - if (mProcDir) { - closedir(mProcDir); - } -} - -void -OpenFileFinder::FillInfo(OpenFileFinder::Info* aInfo, const nsACString& aPath) -{ - aInfo->mFileName = aPath; - aInfo->mPid = mPid; - nsPrintfCString exePath("/proc/%d/exe", mPid); - ReadSymLink(exePath, aInfo->mExe); - aInfo->mComm.Truncate(); - aInfo->mAppName.Truncate(); - nsPrintfCString statPath("/proc/%d/stat", mPid); - nsCString statString; - statString.SetLength(200); - char *stat = statString.BeginWriting(); - if (!stat) { - return; - } - ReadSysFile(statPath.get(), stat, statString.Length()); - // The stat line includes the comm field, surrounded by parenthesis. - // However, the contents of the comm field itself is arbitrary and - // and can include ')', so we search for the rightmost ) as being - // the end of the comm field. - char *closeParen = strrchr(stat, ')'); - if (!closeParen) { - return; - } - char *openParen = strchr(stat, '('); - if (!openParen) { - return; - } - if (openParen >= closeParen) { - return; - } - nsDependentCSubstring comm(&openParen[1], closeParen - openParen - 1); - aInfo->mComm = comm; - // There is a single character field after the comm and then - // the parent pid (the field we're interested in). - // ) X ppid - // 01234 - int ppid = atoi(&closeParen[4]); - - if (mPid == mMyPid) { - // This is chrome process - aInfo->mIsB2gOrDescendant = true; - DBG("Chrome process has open file(s)"); - return; - } - // For the rest (non-chrome process), we recursively check the ppid to know - // it is a descendant of b2g or not. See bug 931456. - while (ppid != mMyPid && ppid != 1) { - DBG("Process(%d) is not forked from b2g(%d) or Init(1), keep looking", - ppid, mMyPid); - nsPrintfCString ppStatPath("/proc/%d/stat", ppid); - ReadSysFile(ppStatPath.get(), stat, statString.Length()); - closeParen = strrchr(stat, ')'); - if (!closeParen) { - return; - } - ppid = atoi(&closeParen[4]); - } - if (ppid == 1) { - // This is a not a b2g process. - DBG("Non-b2g process has open file(s)"); - aInfo->mIsB2gOrDescendant = false; - return; - } - if (ppid == mMyPid) { - // This is a descendant of b2g. - DBG("Child process of chrome process has open file(s)"); - aInfo->mIsB2gOrDescendant = true; - } - - // This looks like a content process. The comm field will be the - // app name. - aInfo->mAppName = aInfo->mComm; -} - -bool -OpenFileFinder::ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath) -{ - aOutPath.Truncate(); - const char *symLink = aSymLink.BeginReading(); - - // Verify that we actually have a symlink. - struct stat st; - if (lstat(symLink, &st)) { - return false; - } - if ((st.st_mode & S_IFMT) != S_IFLNK) { - return false; - } - - // Contrary to the documentation st.st_size doesn't seem to be a reliable - // indication of the length when reading from /proc, so we use a fixed - // size buffer instead. - - char resolvedSymLink[PATH_MAX]; - ssize_t pathLength = readlink(symLink, resolvedSymLink, - sizeof(resolvedSymLink) - 1); - if (pathLength <= 0) { - return false; - } - resolvedSymLink[pathLength] = '\0'; - aOutPath.Assign(resolvedSymLink); - return true; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/OpenFileFinder.h b/dom/system/gonk/OpenFileFinder.h deleted file mode 100644 index 24517965a..000000000 --- a/dom/system/gonk/OpenFileFinder.h +++ /dev/null @@ -1,63 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_openfilefinder_h__ -#define mozilla_system_openfilefinder_h__ - -#include "nsString.h" - -#include - -namespace mozilla { -namespace system { - -class OpenFileFinder -{ -public: - enum State - { - NEXT_PID, - CHECK_FDS, - DONE - }; - class Info - { - public: - nsCString mFileName; // name of the the open file - nsCString mAppName; // App which has the file open (if it's a b2g app) - pid_t mPid; // pid of the process which has the file open - nsCString mComm; // comm associated with pid - nsCString mExe; // executable name associated with pid - bool mIsB2gOrDescendant; // this is b2g/its descendant or not - }; - - OpenFileFinder(const nsACString& aPath, bool aCheckIsB2gOrDescendant = true); - ~OpenFileFinder(); - - bool First(Info* aInfo); // Return the first open file - bool Next(Info* aInfo); // Return the next open file - void Close(); - -private: - - void FillInfo(Info *aInfo, const nsACString& aPath); - bool ReadSymLink(const nsACString& aSymLink, nsACString& aOutPath); - bool PathMatches(const nsACString& aPath) - { - return Substring(aPath, 0, mPath.Length()).Equals(mPath); - } - - State mState; // Keeps track of what we're doing. - nsCString mPath; // Only report files contained within this directory tree - DIR* mProcDir; // Used for scanning /proc - DIR* mFdDir; // Used for scanning /proc/PID/fd - int mPid; // PID currently being processed - pid_t mMyPid; // PID of parent process, we assume we're running on it. - bool mCheckIsB2gOrDescendant; // Do we care about non-b2g process? -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolume_h__ diff --git a/dom/system/gonk/RILSystemMessenger.jsm b/dom/system/gonk/RILSystemMessenger.jsm deleted file mode 100644 index 81373458c..000000000 --- a/dom/system/gonk/RILSystemMessenger.jsm +++ /dev/null @@ -1,338 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "RIL", function () { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -/** - * RILSystemMessenger - */ -this.RILSystemMessenger = function() {}; -RILSystemMessenger.prototype = { - - /** - * Hook of Broadcast function - * - * @param aType - * The type of the message to be sent. - * @param aMessage - * The message object to be broadcasted. - */ - broadcastMessage: function(aType, aMessage) { - // Function stub to be replaced by the owner of this messenger. - }, - - /** - * Hook of the function to create MozStkCommand message. - * @param aStkProactiveCmd - * nsIStkProactiveCmd instance. - * - * @return a JS object which complies the dictionary of MozStkCommand defined - * in MozStkCommandEvent.webidl - */ - createCommandMessage: function(aStkProactiveCmd) { - // Function stub to be replaced by the owner of this messenger. - }, - - /** - * Wrapper to send "telephony-new-call" system message. - */ - notifyNewCall: function() { - this.broadcastMessage("telephony-new-call", {}); - }, - - /** - * Wrapper to send "telephony-call-ended" system message. - */ - notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency, - aDuration, aOutgoing, aHangUpLocal) { - let data = { - serviceId: aServiceId, - number: aNumber, - emergency: aEmergency, - duration: aDuration, - direction: aOutgoing ? "outgoing" : "incoming", - hangUpLocal: aHangUpLocal - }; - - if (aCdmaWaitingNumber != null) { - data.secondNumber = aCdmaWaitingNumber; - } - - this.broadcastMessage("telephony-call-ended", data); - }, - - _convertSmsMessageClass: function(aMessageClass) { - return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null; - }, - - _convertSmsDelivery: function(aDelivery) { - return ["received", "sending", "sent", "error"][aDelivery] || null; - }, - - _convertSmsDeliveryStatus: function(aDeliveryStatus) { - return [ - RIL.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE, - RIL.GECKO_SMS_DELIVERY_STATUS_SUCCESS, - RIL.GECKO_SMS_DELIVERY_STATUS_PENDING, - RIL.GECKO_SMS_DELIVERY_STATUS_ERROR - ][aDeliveryStatus] || null; - }, - - /** - * Wrapper to send 'sms-received', 'sms-delivery-success', 'sms-sent', - * 'sms-failed', 'sms-delivery-error' system message. - */ - notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery, - aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass, - aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) { - let msgType = [ - "sms-received", - "sms-sent", - "sms-delivery-success", - "sms-failed", - "sms-delivery-error" - ][aNotificationType]; - - if (!msgType) { - throw new Error("Invalid Notification Type: " + aNotificationType); - } - - this.broadcastMessage(msgType, { - iccId: aIccId, - type: "sms", - id: aId, - threadId: aThreadId, - delivery: this._convertSmsDelivery(aDelivery), - deliveryStatus: this._convertSmsDeliveryStatus(aDeliveryStatus), - sender: aSender, - receiver: aReceiver, - body: aBody, - messageClass: this._convertSmsMessageClass(aMessageClass), - timestamp: aTimestamp, - sentTimestamp: aSentTimestamp, - deliveryTimestamp: aDeliveryTimestamp, - read: aRead - }); - }, - - _convertCbGsmGeographicalScope: function(aGeographicalScope) { - return RIL.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES[aGeographicalScope] || null; - }, - - _convertCbMessageClass: function(aMessageClass) { - return RIL.GECKO_SMS_MESSAGE_CLASSES[aMessageClass] || null; - }, - - _convertCbEtwsWarningType: function(aWarningType) { - return RIL.CB_ETWS_WARNING_TYPE_NAMES[aWarningType] || null; - }, - - /** - * Wrapper to send 'cellbroadcast-received' system message. - */ - notifyCbMessageReceived: function(aServiceId, aGsmGeographicalScope, aMessageCode, - aMessageId, aLanguage, aBody, aMessageClass, - aTimestamp, aCdmaServiceCategory, aHasEtwsInfo, - aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup) { - // Align the same layout to MozCellBroadcastMessage - let data = { - serviceId: aServiceId, - gsmGeographicalScope: this._convertCbGsmGeographicalScope(aGsmGeographicalScope), - messageCode: aMessageCode, - messageId: aMessageId, - language: aLanguage, - body: aBody, - messageClass: this._convertCbMessageClass(aMessageClass), - timestamp: aTimestamp, - cdmaServiceCategory: null, - etws: null - }; - - if (aHasEtwsInfo) { - data.etws = { - warningType: this._convertCbEtwsWarningType(aEtwsWarningType), - emergencyUserAlert: aEtwsEmergencyUserAlert, - popup: aEtwsPopup - }; - } - - if (aCdmaServiceCategory != - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID) { - data.cdmaServiceCategory = aCdmaServiceCategory; - } - - this.broadcastMessage("cellbroadcast-received", data); - }, - - /** - * Wrapper to send 'ussd-received' system message. - */ - notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) { - this.broadcastMessage("ussd-received", { - serviceId: aServiceId, - message: aMessage, - sessionEnded: aSessionEnded - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Display Info. - */ - notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - display: aDisplay - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Called Party - * Number Info. - */ - notifyCdmaInfoRecCalledPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - calledNumber: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Calling Party - * Number Info. - */ - notifyCdmaInfoRecCallingPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - callingNumber: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Connected Party - * Number Info. - */ - notifyCdmaInfoRecConnectedPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - connectedNumber: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Signal Info. - */ - notifyCdmaInfoRecSignal: function(aServiceId, aType, aAlertPitch, aSignal) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - signal: { - type: aType, - alertPitch: aAlertPitch, - signal: aSignal - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Redirecting - * Number Info. - */ - notifyCdmaInfoRecRedirectingNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi, aReason) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - redirect: { - type: aType, - plan: aPlan, - number: aNumber, - pi: aPi, - si: aSi, - reason: aReason - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Line Control Info. - */ - notifyCdmaInfoRecLineControl: function(aServiceId, aPolarityIncluded, - aToggle, aReverse, aPowerDenial) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - lineControl: { - polarityIncluded: aPolarityIncluded, - toggle: aToggle, - reverse: aReverse, - powerDenial: aPowerDenial - } - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with CLIR Info. - */ - notifyCdmaInfoRecClir: function(aServiceId, aCause) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - clirCause: aCause - }); - }, - - /** - * Wrapper to send 'cdma-info-rec-received' system message with Audio Control Info. - */ - notifyCdmaInfoRecAudioControl: function(aServiceId, aUpLink, aDownLink) { - this.broadcastMessage("cdma-info-rec-received", { - clientId: aServiceId, - audioControl: { - upLink: aUpLink, - downLink: aDownLink - } - }); - }, - - /** - * Wrapper to send 'icc-stkcommand' system message with Audio Control Info. - */ - notifyStkProactiveCommand: function(aIccId, aCommand) { - this.broadcastMessage("icc-stkcommand", { - iccId: aIccId, - command: this.createCommandMessage(aCommand) - }); - } -}; - -this.EXPORTED_SYMBOLS = [ - 'RILSystemMessenger' -]; diff --git a/dom/system/gonk/RILSystemMessengerHelper.js b/dom/system/gonk/RILSystemMessengerHelper.js deleted file mode 100644 index 6ef263b66..000000000 --- a/dom/system/gonk/RILSystemMessengerHelper.js +++ /dev/null @@ -1,169 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -var RSM = {}; -Cu.import("resource://gre/modules/RILSystemMessenger.jsm", RSM); - -const RILSYSTEMMESSENGERHELPER_CONTRACTID = - "@mozilla.org/ril/system-messenger-helper;1"; -const RILSYSTEMMESSENGERHELPER_CID = - Components.ID("{19d9a4ea-580d-11e4-8f6c-37ababfaaea9}"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSystemMessenger", - "@mozilla.org/system-message-internal;1", - "nsISystemMessagesInternal"); - -XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory", - "@mozilla.org/icc/stkcmdfactory;1", - "nsIStkCmdFactory"); - -var DEBUG = false; -function debug(s) { - dump("-@- RILSystemMessenger: " + s + "\n"); -}; - -// Read debug setting from pref. -try { - let debugPref = Services.prefs.getBoolPref("ril.debugging.enabled"); - DEBUG = DEBUG || debugPref; -} catch (e) {} - -/** - * RILSystemMessengerHelper - */ -function RILSystemMessengerHelper() { - this.messenger = new RSM.RILSystemMessenger(); - this.messenger.broadcastMessage = (aType, aMessage) => { - if (DEBUG) { - debug("broadcastMessage: aType: " + aType + - ", aMessage: "+ JSON.stringify(aMessage)); - } - - gSystemMessenger.broadcastMessage(aType, aMessage); - }; - - this.messenger.createCommandMessage = (aStkProactiveCmd) => { - return gStkCmdFactory.createCommandMessage(aStkProactiveCmd); - }; -} -RILSystemMessengerHelper.prototype = { - - classID: RILSYSTEMMESSENGERHELPER_CID, - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyMessenger, - Ci.nsISmsMessenger, - Ci.nsICellbroadcastMessenger, - Ci.nsIMobileConnectionMessenger, - Ci.nsIIccMessenger]), - - /** - * RILSystemMessenger instance. - */ - messenger: null, - - /** - * nsITelephonyMessenger API - */ - notifyNewCall: function() { - this.messenger.notifyNewCall(); - }, - - notifyCallEnded: function(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency, - aDuration, aOutgoing, aHangUpLocal) { - this.messenger.notifyCallEnded(aServiceId, aNumber, aCdmaWaitingNumber, aEmergency, - aDuration, aOutgoing, aHangUpLocal); - }, - - notifyUssdReceived: function(aServiceId, aMessage, aSessionEnded) { - this.messenger.notifyUssdReceived(aServiceId, aMessage, aSessionEnded); - }, - - /** - * nsISmsMessenger API - */ - notifySms: function(aNotificationType, aId, aThreadId, aIccId, aDelivery, - aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass, - aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead) { - this.messenger.notifySms(aNotificationType, aId, aThreadId, aIccId, aDelivery, - aDeliveryStatus, aSender, aReceiver, aBody, aMessageClass, - aTimestamp, aSentTimestamp, aDeliveryTimestamp, aRead); - }, - - /** - * nsICellbroadcastMessenger API - */ - notifyCbMessageReceived: function(aServiceId, aGsmGeographicalScope, aMessageCode, - aMessageId, aLanguage, aBody, aMessageClass, - aTimestamp, aCdmaServiceCategory, aHasEtwsInfo, - aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup) { - this.messenger.notifyCbMessageReceived(aServiceId, aGsmGeographicalScope, aMessageCode, - aMessageId, aLanguage, aBody, aMessageClass, - aTimestamp, aCdmaServiceCategory, aHasEtwsInfo, - aEtwsWarningType, aEtwsEmergencyUserAlert, aEtwsPopup); - }, - - /** - * nsIMobileConnectionMessenger API - */ - notifyCdmaInfoRecDisplay: function(aServiceId, aDisplay) { - this.messenger.notifyCdmaInfoRecDisplay(aServiceId, aDisplay); - }, - - notifyCdmaInfoRecCalledPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.messenger.notifyCdmaInfoRecCalledPartyNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi); - }, - - notifyCdmaInfoRecCallingPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.messenger.notifyCdmaInfoRecCallingPartyNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi); - }, - - notifyCdmaInfoRecConnectedPartyNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi) { - this.messenger.notifyCdmaInfoRecConnectedPartyNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi); - }, - - notifyCdmaInfoRecSignal: function(aServiceId, aType, aAlertPitch, aSignal) { - this.messenger.notifyCdmaInfoRecSignal(aServiceId, aType, aAlertPitch, aSignal); - }, - - notifyCdmaInfoRecRedirectingNumber: function(aServiceId, aType, aPlan, - aNumber, aPi, aSi, aReason) { - this.messenger.notifyCdmaInfoRecRedirectingNumber(aServiceId, aType, aPlan, - aNumber, aPi, aSi, aReason); - }, - - notifyCdmaInfoRecLineControl: function(aServiceId, aPolarityIncluded, - aToggle, aReverse, aPowerDenial) { - this.messenger.notifyCdmaInfoRecLineControl(aServiceId, aPolarityIncluded, - aToggle, aReverse, aPowerDenial); - }, - - notifyCdmaInfoRecClir: function(aServiceId, aCause) { - this.messenger.notifyCdmaInfoRecClir(aServiceId, aCause); - }, - - notifyCdmaInfoRecAudioControl: function(aServiceId, aUpLink, aDownLink) { - this.messenger.notifyCdmaInfoRecAudioControl(aServiceId, aUpLink, aDownLink); - }, - - /** - * nsIIccMessenger API - */ - notifyStkProactiveCommand: function(aIccId, aCommand) { - this.messenger.notifyStkProactiveCommand(aIccId, aCommand); - } -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RILSystemMessengerHelper]); diff --git a/dom/system/gonk/RILSystemMessengerHelper.manifest b/dom/system/gonk/RILSystemMessengerHelper.manifest deleted file mode 100644 index 7d1943702..000000000 --- a/dom/system/gonk/RILSystemMessengerHelper.manifest +++ /dev/null @@ -1,6 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -component {19d9a4ea-580d-11e4-8f6c-37ababfaaea9} RILSystemMessengerHelper.js -contract @mozilla.org/ril/system-messenger-helper;1 {19d9a4ea-580d-11e4-8f6c-37ababfaaea9} \ No newline at end of file diff --git a/dom/system/gonk/RadioInterfaceLayer.js b/dom/system/gonk/RadioInterfaceLayer.js deleted file mode 100644 index f5885db5d..000000000 --- a/dom/system/gonk/RadioInterfaceLayer.js +++ /dev/null @@ -1,1324 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Sntp.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "RIL", function () { - let obj = {}; - Cu.import("resource://gre/modules/ril_consts.js", obj); - return obj; -}); - -// Ril quirk to always turn the radio off for the client without SIM card -// except hw default client. -var RILQUIRKS_RADIO_OFF_WO_CARD = - libcutils.property_get("ro.moz.ril.radio_off_wo_card", "false") == "true"; - -const RADIOINTERFACELAYER_CID = - Components.ID("{2d831c8d-6017-435b-a80c-e5d422810cea}"); -const RADIOINTERFACE_CID = - Components.ID("{6a7c91f0-a2b3-4193-8562-8969296c0b54}"); - -const NS_XPCOM_SHUTDOWN_OBSERVER_ID = "xpcom-shutdown"; -const kNetworkConnStateChangedTopic = "network-connection-state-changed"; -const kMozSettingsChangedObserverTopic = "mozsettings-changed"; -const kSysMsgListenerReadyObserverTopic = "system-message-listener-ready"; -const kSysClockChangeObserverTopic = "system-clock-change"; -const kScreenStateChangedTopic = "screen-state-changed"; - -const kSettingsClockAutoUpdateEnabled = "time.clock.automatic-update.enabled"; -const kSettingsClockAutoUpdateAvailable = "time.clock.automatic-update.available"; -const kSettingsTimezoneAutoUpdateEnabled = "time.timezone.automatic-update.enabled"; -const kSettingsTimezoneAutoUpdateAvailable = "time.timezone.automatic-update.available"; - -const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed"; - -const kPrefRilNumRadioInterfaces = "ril.numRadioInterfaces"; -const kPrefRilDebuggingEnabled = "ril.debugging.enabled"; - -const RADIO_POWER_OFF_TIMEOUT = 30000; -const HW_DEFAULT_CLIENT_ID = 0; - -const NETWORK_TYPE_WIFI = Ci.nsINetworkInfo.NETWORK_TYPE_WIFI; -const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; - -// set to true in ril_consts.js to see debug messages -var DEBUG = RIL.DEBUG_RIL; - -function updateDebugFlag() { - // Read debug setting from pref - let debugPref; - try { - debugPref = Services.prefs.getBoolPref(kPrefRilDebuggingEnabled); - } catch (e) { - debugPref = false; - } - DEBUG = RIL.DEBUG_RIL || debugPref; -} -updateDebugFlag(); - -function debug(s) { - dump("-*- RadioInterfaceLayer: " + s + "\n"); -} - -XPCOMUtils.defineLazyServiceGetter(this, "gIccService", - "@mozilla.org/icc/gonkiccservice;1", - "nsIGonkIccService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileMessageService", - "@mozilla.org/mobilemessage/mobilemessageservice;1", - "nsIMobileMessageService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSmsService", - "@mozilla.org/sms/gonksmsservice;1", - "nsIGonkSmsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "ppmm", - "@mozilla.org/parentprocessmessagemanager;1", - "nsIMessageBroadcaster"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gTimeService", - "@mozilla.org/time/timeservice;1", - "nsITimeService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSystemWorkerManager", - "@mozilla.org/telephony/system-worker-manager;1", - "nsISystemWorkerManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gTelephonyService", - "@mozilla.org/telephony/telephonyservice;1", - "nsIGonkTelephonyService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIGonkMobileConnectionService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gCellBroadcastService", - "@mozilla.org/cellbroadcast/cellbroadcastservice;1", - "nsIGonkCellBroadcastService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gDataCallManager", - "@mozilla.org/datacall/manager;1", - "nsIDataCallManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gDataCallInterfaceService", - "@mozilla.org/datacall/interfaceservice;1", - "nsIGonkDataCallInterfaceService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory", - "@mozilla.org/icc/stkcmdfactory;1", - "nsIStkCmdFactory"); - -XPCOMUtils.defineLazyGetter(this, "gRadioEnabledController", function() { - let _ril = null; - let _pendingMessages = []; // For queueing "setRadioEnabled" message. - let _isProcessingPending = false; - let _timer = null; - let _request = null; - let _deactivatingDeferred = {}; - let _initializedCardState = {}; - let _allCardStateInitialized = !RILQUIRKS_RADIO_OFF_WO_CARD; - - return { - init: function(ril) { - _ril = ril; - }, - - receiveCardState: function(clientId) { - if (_allCardStateInitialized) { - return; - } - - if (DEBUG) debug("RadioControl: receive cardState from " + clientId); - _initializedCardState[clientId] = true; - if (Object.keys(_initializedCardState).length == _ril.numRadioInterfaces) { - _allCardStateInitialized = true; - this._startProcessingPending(); - } - }, - - setRadioEnabled: function(clientId, data, callback) { - if (DEBUG) debug("setRadioEnabled: " + clientId + ": " + JSON.stringify(data)); - let message = { - clientId: clientId, - data: data, - callback: callback - }; - _pendingMessages.push(message); - this._startProcessingPending(); - }, - - notifyRadioStateChanged: function(clientId, radioState) { - gMobileConnectionService.notifyRadioStateChanged(clientId, radioState); - }, - - _startProcessingPending: function() { - if (!_isProcessingPending) { - if (DEBUG) debug("RadioControl: start dequeue"); - _isProcessingPending = true; - this._processNextMessage(); - } - }, - - _processNextMessage: function() { - if (_pendingMessages.length === 0 || !_allCardStateInitialized) { - if (DEBUG) debug("RadioControl: stop dequeue"); - _isProcessingPending = false; - return; - } - - let msg = _pendingMessages.shift(); - this._handleMessage(msg); - }, - - _getNumCards: function() { - let numCards = 0; - for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) { - if (_ril.getRadioInterface(i).isCardPresent()) { - numCards++; - } - } - return numCards; - }, - - _isRadioAbleToEnableAtClient: function(clientId, numCards) { - if (!RILQUIRKS_RADIO_OFF_WO_CARD) { - return true; - } - - // We could only turn on the radio for clientId if - // 1. a SIM card is presented or - // 2. it is the default clientId and there is no any SIM card at any client. - - if (_ril.getRadioInterface(clientId).isCardPresent()) { - return true; - } - - numCards = numCards == null ? this._getNumCards() : numCards; - if (clientId === HW_DEFAULT_CLIENT_ID && numCards === 0) { - return true; - } - - return false; - }, - - _handleMessage: function(message) { - if (DEBUG) debug("RadioControl: handleMessage: " + JSON.stringify(message)); - let clientId = message.clientId || 0; - let connection = - gMobileConnectionService.getItemByServiceId(clientId); - let radioState = connection && connection.radioState; - - if (message.data.enabled) { - if (this._isRadioAbleToEnableAtClient(clientId)) { - this._setRadioEnabledInternal(message); - } else { - // Not really do it but respond success. - message.callback(message.data); - } - - this._processNextMessage(); - } else { - _request = this._setRadioEnabledInternal.bind(this, message); - - // In 2G network, modem takes 35+ seconds to process deactivate data - // call request if device has active voice call (please see bug 964974 - // for more details). Therefore we should hangup all active voice calls - // first. And considering some DSDS architecture, toggling one radio may - // toggle both, so we send hangUpAll to all clients. - let hangUpCallback = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyCallback]), - notifySuccess: function() {}, - notifyError: function() {} - }; - - gTelephonyService.enumerateCalls({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsITelephonyListener]), - enumerateCallState: function(aInfo) { - gTelephonyService.hangUpCall(aInfo.clientId, aInfo.callIndex, - hangUpCallback); - }, - enumerateCallStateComplete: function() {} - }); - - // In some DSDS architecture with only one modem, toggling one radio may - // toggle both. Therefore, for safely turning off, we should first - // explicitly deactivate all data calls from all clients. - this._deactivateDataCalls().then(() => { - if (DEBUG) debug("RadioControl: deactivation done"); - this._executeRequest(); - }); - - this._createTimer(); - } - }, - - _setRadioEnabledInternal: function(message) { - let clientId = message.clientId || 0; - let enabled = message.data.enabled || false; - let radioInterface = _ril.getRadioInterface(clientId); - - radioInterface.workerMessenger.send("setRadioEnabled", message.data, - (function(response) { - if (response.errorMsg) { - // If request fails, set current radio state to unknown, since we will - // handle it in |mobileConnectionService|. - this.notifyRadioStateChanged(clientId, - Ci.nsIMobileConnection.MOBILE_RADIO_STATE_UNKNOWN); - } - return message.callback(response); - }).bind(this)); - }, - - _deactivateDataCalls: function() { - if (DEBUG) debug("RadioControl: deactivating data calls..."); - _deactivatingDeferred = {}; - - let promise = Promise.resolve(); - for (let i = 0, N = _ril.numRadioInterfaces; i < N; ++i) { - promise = promise.then(this._deactivateDataCallsForClient(i)); - } - - return promise; - }, - - _deactivateDataCallsForClient: function(clientId) { - return function() { - let deferred = _deactivatingDeferred[clientId] = Promise.defer(); - let dataCallHandler = gDataCallManager.getDataCallHandler(clientId); - - dataCallHandler.deactivateDataCalls(function() { - deferred.resolve(); - }); - - return deferred.promise; - }; - }, - - _createTimer: function() { - if (!_timer) { - _timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - } - _timer.initWithCallback(this._executeRequest.bind(this), - RADIO_POWER_OFF_TIMEOUT, - Ci.nsITimer.TYPE_ONE_SHOT); - }, - - _cancelTimer: function() { - if (_timer) { - _timer.cancel(); - } - }, - - _executeRequest: function() { - if (typeof _request === "function") { - if (DEBUG) debug("RadioControl: executeRequest"); - this._cancelTimer(); - _request(); - _request = null; - } - this._processNextMessage(); - }, - }; -}); - -// Initialize shared preference "ril.numRadioInterfaces" according to system -// property. -try { - Services.prefs.setIntPref(kPrefRilNumRadioInterfaces, (function() { - // When Gonk property "ro.moz.ril.numclients" is not set, return 1; if - // explicitly set to any number larger-equal than 0, return num; else, return - // 1 for compatibility. - try { - let numString = libcutils.property_get("ro.moz.ril.numclients", "1"); - let num = parseInt(numString, 10); - if (num >= 0) { - return num; - } - } catch (e) {} - - return 1; - })()); -} catch (e) {} - -function DataCall(aAttributes) { - for (let key in aAttributes) { - if (key === "pdpType") { - // Convert pdp type into constant int value. - this[key] = RIL.RIL_DATACALL_PDP_TYPES.indexOf(aAttributes[key]); - continue; - } - - this[key] = aAttributes[key]; - } -} -DataCall.prototype = { - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDataCall]), - - failCause: Ci.nsIDataCallInterface.DATACALL_FAIL_NONE, - suggestedRetryTime: -1, - cid: -1, - active: -1, - pdpType: -1, - ifname: null, - addreses: null, - dnses: null, - gateways: null, - pcscf: null, - mtu: -1 -}; - -function RadioInterfaceLayer() { - let workerMessenger = new WorkerMessenger(); - workerMessenger.init(); - this.setWorkerDebugFlag = workerMessenger.setDebugFlag.bind(workerMessenger); - - let numIfaces = this.numRadioInterfaces; - if (DEBUG) debug(numIfaces + " interfaces"); - this.radioInterfaces = []; - for (let clientId = 0; clientId < numIfaces; clientId++) { - this.radioInterfaces.push(new RadioInterface(clientId, workerMessenger)); - } - - Services.obs.addObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - Services.prefs.addObserver(kPrefRilDebuggingEnabled, this, false); - - gRadioEnabledController.init(this); -} -RadioInterfaceLayer.prototype = { - - classID: RADIOINTERFACELAYER_CID, - classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACELAYER_CID, - classDescription: "RadioInterfaceLayer", - interfaces: [Ci.nsIRadioInterfaceLayer]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterfaceLayer, - Ci.nsIObserver]), - - /** - * nsIObserver interface methods. - */ - - observe: function(subject, topic, data) { - switch (topic) { - case NS_XPCOM_SHUTDOWN_OBSERVER_ID: - for (let radioInterface of this.radioInterfaces) { - radioInterface.shutdown(); - } - this.radioInterfaces = null; - Services.obs.removeObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID); - break; - - case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID: - if (data === kPrefRilDebuggingEnabled) { - updateDebugFlag(); - this.setWorkerDebugFlag(DEBUG); - } - break; - } - }, - - /** - * nsIRadioInterfaceLayer interface methods. - */ - - getRadioInterface: function(clientId) { - return this.radioInterfaces[clientId]; - }, - - setMicrophoneMuted: function(muted) { - for (let clientId = 0; clientId < this.numRadioInterfaces; clientId++) { - let radioInterface = this.radioInterfaces[clientId]; - radioInterface.workerMessenger.send("setMute", { muted: muted }); - } - } -}; - -XPCOMUtils.defineLazyGetter(RadioInterfaceLayer.prototype, - "numRadioInterfaces", function() { - try { - return Services.prefs.getIntPref(kPrefRilNumRadioInterfaces); - } catch(e) {} - - return 1; -}); - -function WorkerMessenger() { - // Initial owning attributes. - this.radioInterfaces = []; - this.tokenCallbackMap = {}; - - this.worker = new ChromeWorker("resource://gre/modules/ril_worker.js"); - this.worker.onerror = this.onerror.bind(this); - this.worker.onmessage = this.onmessage.bind(this); -} -WorkerMessenger.prototype = { - radioInterfaces: null, - worker: null, - - // This gets incremented each time we send out a message. - token: 1, - - // Maps tokens we send out with messages to the message callback. - tokenCallbackMap: null, - - init: function() { - let options = { - debug: DEBUG, - quirks: { - callstateExtraUint32: - libcutils.property_get("ro.moz.ril.callstate_extra_int", "false") === "true", - requestUseDialEmergencyCall: - libcutils.property_get("ro.moz.ril.dial_emergency_call", "false") === "true", - simAppStateExtraFields: - libcutils.property_get("ro.moz.ril.simstate_extra_field", "false") === "true", - extraUint2ndCall: - libcutils.property_get("ro.moz.ril.extra_int_2nd_call", "false") === "true", - haveQueryIccLockRetryCount: - libcutils.property_get("ro.moz.ril.query_icc_count", "false") === "true", - sendStkProfileDownload: - libcutils.property_get("ro.moz.ril.send_stk_profile_dl", "false") === "true", - smscAddressFormat: - libcutils.property_get("ro.moz.ril.smsc_address_format", "text"), - dataRegistrationOnDemand: - libcutils.property_get("ro.moz.ril.data_reg_on_demand", "false") === "true", - subscriptionControl: - libcutils.property_get("ro.moz.ril.subscription_control", "false") === "true", - signalExtraInt: - libcutils.property_get("ro.moz.ril.signal_extra_int", "false") === "true", - availableNetworkExtraStr: - libcutils.property_get("ro.moz.ril.avlbl_nw_extra_str", "false") === "true", - } - }; - - this.send(null, "setInitialOptions", options); - }, - - setDebugFlag: function(aDebug) { - let options = { debug: aDebug }; - this.send(null, "setDebugFlag", options); - }, - - debug: function(aClientId, aMessage) { - // We use the same debug subject with RadioInterface's here. - dump("-*- RadioInterface[" + aClientId + "]: " + aMessage + "\n"); - }, - - onerror: function(event) { - if (DEBUG) { - this.debug("X", "Got an error: " + event.filename + ":" + - event.lineno + ": " + event.message + "\n"); - } - event.preventDefault(); - }, - - /** - * Process the incoming message from the RIL worker. - */ - onmessage: function(event) { - let message = event.data; - let clientId = message.rilMessageClientId; - if (clientId === null) { - return; - } - - if (DEBUG) { - this.debug(clientId, "Received message from worker: " + JSON.stringify(message)); - } - - let token = message.rilMessageToken; - if (token == null) { - // That's an unsolicited message. Pass to RadioInterface directly. - let radioInterface = this.radioInterfaces[clientId]; - radioInterface.handleUnsolicitedWorkerMessage(message); - return; - } - - let callback = this.tokenCallbackMap[message.rilMessageToken]; - if (!callback) { - if (DEBUG) this.debug(clientId, "Ignore orphan token: " + message.rilMessageToken); - return; - } - - let keep = false; - try { - keep = callback(message); - } catch(e) { - if (DEBUG) this.debug(clientId, "callback throws an exception: " + e); - } - - if (!keep) { - delete this.tokenCallbackMap[message.rilMessageToken]; - } - }, - - registerClient: function(aClientId, aRadioInterface) { - if (DEBUG) this.debug(aClientId, "Starting RIL Worker"); - - // Keep a reference so that we can dispatch unsolicited messages to it. - this.radioInterfaces[aClientId] = aRadioInterface; - - this.send(null, "registerClient", { clientId: aClientId }); - gSystemWorkerManager.registerRilWorker(aClientId, this.worker); - }, - - /** - * Send arbitrary message to worker. - * - * @param rilMessageType - * A text message type. - * @param message [optional] - * An optional message object to send. - * @param callback [optional] - * An optional callback function which is called when worker replies - * with an message containing a "rilMessageToken" attribute of the - * same value we passed. This callback function accepts only one - * parameter -- the reply from worker. It also returns a boolean - * value true to keep current token-callback mapping and wait for - * another worker reply, or false to remove the mapping. - */ - send: function(clientId, rilMessageType, message, callback) { - message = message || {}; - - message.rilMessageClientId = clientId; - message.rilMessageToken = this.token; - this.token++; - - if (callback) { - // Only create the map if callback is provided. For sending a request - // and intentionally leaving the callback undefined, that reply will - // be dropped in |this.onmessage| because of that orphan token. - // - // For sending a request that never replied at all, we're fine with this - // because no callback shall be passed and we leave nothing to be cleaned - // up later. - this.tokenCallbackMap[message.rilMessageToken] = callback; - } - - message.rilMessageType = rilMessageType; - this.worker.postMessage(message); - } -}; - -function RadioInterface(aClientId, aWorkerMessenger) { - this.clientId = aClientId; - this.workerMessenger = { - send: aWorkerMessenger.send.bind(aWorkerMessenger, aClientId) - }; - aWorkerMessenger.registerClient(aClientId, this); - - this.operatorInfo = {}; - - let lock = gSettingsService.createLock(); - - // Read the "time.clock.automatic-update.enabled" setting to see if - // we need to adjust the system clock time by NITZ or SNTP. - lock.get(kSettingsClockAutoUpdateEnabled, this); - - // Read the "time.timezone.automatic-update.enabled" setting to see if - // we need to adjust the system timezone by NITZ. - lock.get(kSettingsTimezoneAutoUpdateEnabled, this); - - // Set "time.clock.automatic-update.available" to false when starting up. - this.setClockAutoUpdateAvailable(false); - - // Set "time.timezone.automatic-update.available" to false when starting up. - this.setTimezoneAutoUpdateAvailable(false); - - Services.obs.addObserver(this, kMozSettingsChangedObserverTopic, false); - Services.obs.addObserver(this, kSysClockChangeObserverTopic, false); - Services.obs.addObserver(this, kScreenStateChangedTopic, false); - - Services.obs.addObserver(this, kNetworkConnStateChangedTopic, false); - - this._sntp = new Sntp(this.setClockBySntp.bind(this), - Services.prefs.getIntPref("network.sntp.maxRetryCount"), - Services.prefs.getIntPref("network.sntp.refreshPeriod"), - Services.prefs.getIntPref("network.sntp.timeout"), - Services.prefs.getCharPref("network.sntp.pools").split(";"), - Services.prefs.getIntPref("network.sntp.port")); -} - -RadioInterface.prototype = { - - classID: RADIOINTERFACE_CID, - classInfo: XPCOMUtils.generateCI({classID: RADIOINTERFACE_CID, - classDescription: "RadioInterface", - interfaces: [Ci.nsIRadioInterface]}), - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRadioInterface, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - // A private wrapped WorkerMessenger instance. - workerMessenger: null, - - debug: function(s) { - dump("-*- RadioInterface[" + this.clientId + "]: " + s + "\n"); - }, - - shutdown: function() { - Services.obs.removeObserver(this, kMozSettingsChangedObserverTopic); - Services.obs.removeObserver(this, kSysClockChangeObserverTopic); - Services.obs.removeObserver(this, kScreenStateChangedTopic); - Services.obs.removeObserver(this, kNetworkConnStateChangedTopic); - }, - - isCardPresent: function() { - let icc = gIccService.getIccByServiceId(this.clientId); - let cardState = icc ? icc.cardState : Ci.nsIIcc.CARD_STATE_UNKNOWN; - return cardState !== Ci.nsIIcc.CARD_STATE_UNDETECTED && - cardState !== Ci.nsIIcc.CARD_STATE_UNKNOWN; - }, - - handleUnsolicitedWorkerMessage: function(message) { - switch (message.rilMessageType) { - case "callRing": - gTelephonyService.notifyCallRing(); - break; - case "currentCalls": - gTelephonyService.notifyCurrentCalls(this.clientId, message.calls); - break; - case "cdmaCallWaiting": - gTelephonyService.notifyCdmaCallWaiting(this.clientId, - message.waitingCall); - break; - case "suppSvcNotification": - gTelephonyService.notifySupplementaryService(this.clientId, - message.number, - message.notification); - break; - case "ussdreceived": - gTelephonyService.notifyUssdReceived(this.clientId, message.message, - message.sessionEnded); - break; - case "datacalllistchanged": - let dataCalls = message.datacalls.map(dataCall => new DataCall(dataCall)); - gDataCallInterfaceService.notifyDataCallListChanged(this.clientId, - dataCalls.length, - dataCalls); - break; - case "emergencyCbModeChange": - gMobileConnectionService.notifyEmergencyCallbackModeChanged(this.clientId, - message.active, - message.timeoutMs); - break; - case "networkinfochanged": - gMobileConnectionService.notifyNetworkInfoChanged(this.clientId, - message); - break; - case "networkselectionmodechange": - gMobileConnectionService.notifyNetworkSelectModeChanged(this.clientId, - message.mode); - break; - case "voiceregistrationstatechange": - gMobileConnectionService.notifyVoiceInfoChanged(this.clientId, message); - break; - case "dataregistrationstatechange": - gMobileConnectionService.notifyDataInfoChanged(this.clientId, message); - break; - case "signalstrengthchange": - gMobileConnectionService.notifySignalStrengthChanged(this.clientId, - message); - break; - case "operatorchange": - gMobileConnectionService.notifyOperatorChanged(this.clientId, message); - break; - case "otastatuschange": - gMobileConnectionService.notifyOtaStatusChanged(this.clientId, message.status); - break; - case "deviceidentitieschange": - gMobileConnectionService.notifyDeviceIdentitiesChanged(this.clientId, - message.deviceIdentities.imei, - message.deviceIdentities.imeisv, - message.deviceIdentities.esn, - message.deviceIdentities.meid); - break; - case "radiostatechange": - // gRadioEnabledController should know the radio state for each client, - // so notify gRadioEnabledController here. - gRadioEnabledController.notifyRadioStateChanged(this.clientId, - message.radioState); - break; - case "cardstatechange": - gIccService.notifyCardStateChanged(this.clientId, - message.cardState); - gRadioEnabledController.receiveCardState(this.clientId); - break; - case "sms-received": - this.handleSmsReceived(message); - break; - case "cellbroadcast-received": - this.handleCellbroadcastMessageReceived(message); - break; - case "nitzTime": - this.handleNitzTime(message); - break; - case "iccinfochange": - gIccService.notifyIccInfoChanged(this.clientId, - message.iccid ? message : null); - break; - case "iccimsi": - gIccService.notifyImsiChanged(this.clientId, message.imsi); - break; - case "iccmbdn": - this.handleIccMbdn(message); - break; - case "iccmwis": - this.handleIccMwis(message.mwi); - break; - case "stkcommand": - gIccService.notifyStkCommand(this.clientId, - gStkCmdFactory.createCommand(message)); - break; - case "stksessionend": - gIccService.notifyStkSessionEnd(this.clientId); - break; - case "cdma-info-rec-received": - this.handleCdmaInformationRecords(message.records); - break; - default: - throw new Error("Don't know about this message type: " + - message.rilMessageType); - } - }, - - setDataRegistration: function(attach) { - let deferred = Promise.defer(); - this.workerMessenger.send("setDataRegistration", - {attach: attach}, - (function(response) { - // Always resolve to proceed with the following steps. - deferred.resolve(response.errorMsg ? response.errorMsg : null); - }).bind(this)); - - return deferred.promise; - }, - - /** - * TODO: Bug 911713 - B2G NetworkManager: Move policy control logic to - * NetworkManager - */ - updateRILNetworkInterface: function() { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - connHandler.updateRILNetworkInterface(); - }, - - /** - * handle received SMS. - */ - handleSmsReceived: function(aMessage) { - let header = aMessage.header; - // Concatenation Info: - // - segmentRef: a modulo 256 counter indicating the reference number for a - // particular concatenated short message. '0' is a valid number. - // - The concatenation info will not be available in |header| if - // segmentSeq or segmentMaxSeq is 0. - // See 3GPP TS 23.040, 9.2.3.24.1 Concatenated Short Messages. - let segmentRef = (header && header.segmentRef !== undefined) - ? header.segmentRef : 1; - let segmentSeq = header && header.segmentSeq || 1; - let segmentMaxSeq = header && header.segmentMaxSeq || 1; - // Application Ports: - // The port number ranges from 0 to 49151. - // see 3GPP TS 23.040, 9.2.3.24.3/4 Application Port Addressing. - let originatorPort = (header && header.originatorPort !== undefined) - ? header.originatorPort - : Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID; - let destinationPort = (header && header.destinationPort !== undefined) - ? header.destinationPort - : Ci.nsIGonkSmsService.SMS_APPLICATION_PORT_INVALID; - // MWI info: - let mwiPresent = (aMessage.mwi)? true : false; - let mwiDiscard = (mwiPresent)? aMessage.mwi.discard: false; - let mwiMsgCount = (mwiPresent)? aMessage.mwi.msgCount: 0; - let mwiActive = (mwiPresent)? aMessage.mwi.active: false; - // CDMA related attributes: - let cdmaMessageType = aMessage.messageType || 0; - let cdmaTeleservice = aMessage.teleservice || 0; - let cdmaServiceCategory = aMessage.serviceCategory || 0; - - gSmsService - .notifyMessageReceived(this.clientId, - aMessage.SMSC || null, - aMessage.sentTimestamp, - aMessage.sender, - aMessage.pid, - aMessage.encoding, - RIL.GECKO_SMS_MESSAGE_CLASSES - .indexOf(aMessage.messageClass), - aMessage.language || null, - segmentRef, - segmentSeq, - segmentMaxSeq, - originatorPort, - destinationPort, - mwiPresent, - mwiDiscard, - mwiMsgCount, - mwiActive, - cdmaMessageType, - cdmaTeleservice, - cdmaServiceCategory, - aMessage.body || null, - aMessage.data || [], - (aMessage.data) ? aMessage.data.length : 0); - }, - - /** - * Set the setting value of "time.clock.automatic-update.available". - */ - setClockAutoUpdateAvailable: function(value) { - gSettingsService.createLock().set(kSettingsClockAutoUpdateAvailable, value, null); - }, - - /** - * Set the setting value of "time.timezone.automatic-update.available". - */ - setTimezoneAutoUpdateAvailable: function(value) { - gSettingsService.createLock().set(kSettingsTimezoneAutoUpdateAvailable, value, null); - }, - - /** - * Set the system clock by NITZ. - */ - setClockByNitz: function(message) { - // To set the system clock time. Note that there could be a time diff - // between when the NITZ was received and when the time is actually set. - gTimeService.set( - message.networkTimeInMS + (Date.now() - message.receiveTimeInMS)); - }, - - /** - * Set the system time zone by NITZ. - */ - setTimezoneByNitz: function(message) { - // To set the sytem timezone. Note that we need to convert the time zone - // value to a UTC repesentation string in the format of "UTC(+/-)hh:mm". - // Ex, time zone -480 is "UTC+08:00"; time zone 630 is "UTC-10:30". - // - // We can unapply the DST correction if we want the raw time zone offset: - // message.networkTimeZoneInMinutes -= message.networkDSTInMinutes; - if (message.networkTimeZoneInMinutes != (new Date()).getTimezoneOffset()) { - let absTimeZoneInMinutes = Math.abs(message.networkTimeZoneInMinutes); - let timeZoneStr = "UTC"; - timeZoneStr += (message.networkTimeZoneInMinutes > 0 ? "-" : "+"); - timeZoneStr += ("0" + Math.floor(absTimeZoneInMinutes / 60)).slice(-2); - timeZoneStr += ":"; - timeZoneStr += ("0" + absTimeZoneInMinutes % 60).slice(-2); - gSettingsService.createLock().set("time.timezone", timeZoneStr, null); - } - }, - - /** - * Handle the NITZ message. - */ - handleNitzTime: function(message) { - // Got the NITZ info received from the ril_worker. - this.setClockAutoUpdateAvailable(true); - this.setTimezoneAutoUpdateAvailable(true); - - // Cache the latest NITZ message whenever receiving it. - this._lastNitzMessage = message; - - // Set the received NITZ clock if the setting is enabled. - if (this._clockAutoUpdateEnabled) { - this.setClockByNitz(message); - } - // Set the received NITZ timezone if the setting is enabled. - if (this._timezoneAutoUpdateEnabled) { - this.setTimezoneByNitz(message); - } - }, - - /** - * Set the system clock by SNTP. - */ - setClockBySntp: function(offset) { - // Got the SNTP info. - this.setClockAutoUpdateAvailable(true); - if (!this._clockAutoUpdateEnabled) { - return; - } - if (this._lastNitzMessage) { - if (DEBUG) debug("SNTP: NITZ available, discard SNTP"); - return; - } - gTimeService.set(Date.now() + offset); - }, - - handleIccMbdn: function(message) { - let service = Cc["@mozilla.org/voicemail/voicemailservice;1"] - .getService(Ci.nsIGonkVoicemailService); - service.notifyInfoChanged(this.clientId, message.number, message.alphaId); - }, - - handleIccMwis: function(mwi) { - let service = Cc["@mozilla.org/voicemail/voicemailservice;1"] - .getService(Ci.nsIGonkVoicemailService); - // Note: returnNumber and returnMessage is not available from UICC. - service.notifyStatusChanged(this.clientId, mwi.active, mwi.msgCount, - null, null); - }, - - _convertCbGsmGeographicalScope: function(aGeographicalScope) { - return (aGeographicalScope != null) - ? aGeographicalScope - : Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID; - }, - - _convertCbMessageClass: function(aMessageClass) { - let index = RIL.GECKO_SMS_MESSAGE_CLASSES.indexOf(aMessageClass); - return (index != -1) - ? index - : Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL; - }, - - _convertCbEtwsWarningType: function(aWarningType) { - return (aWarningType != null) - ? aWarningType - : Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID; - }, - - handleCellbroadcastMessageReceived: function(aMessage) { - let etwsInfo = aMessage.etws; - let hasEtwsInfo = etwsInfo != null; - let serviceCategory = (aMessage.serviceCategory) - ? aMessage.serviceCategory - : Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID; - - gCellBroadcastService - .notifyMessageReceived(this.clientId, - this._convertCbGsmGeographicalScope(aMessage.geographicalScope), - aMessage.messageCode, - aMessage.messageId, - aMessage.language, - aMessage.fullBody, - this._convertCbMessageClass(aMessage.messageClass), - Date.now(), - serviceCategory, - hasEtwsInfo, - (hasEtwsInfo) - ? this._convertCbEtwsWarningType(etwsInfo.warningType) - : Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID, - hasEtwsInfo ? etwsInfo.emergencyUserAlert : false, - hasEtwsInfo ? etwsInfo.popup : false); - }, - - handleCdmaInformationRecords: function(aRecords) { - if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(aRecords)); - - let clientId = this.clientId; - - aRecords.forEach(function(aRecord) { - if (aRecord.display) { - gMobileConnectionService - .notifyCdmaInfoRecDisplay(clientId, aRecord.display); - return; - } - - if (aRecord.calledNumber) { - gMobileConnectionService - .notifyCdmaInfoRecCalledPartyNumber(clientId, - aRecord.calledNumber.type, - aRecord.calledNumber.plan, - aRecord.calledNumber.number, - aRecord.calledNumber.pi, - aRecord.calledNumber.si); - return; - } - - if (aRecord.callingNumber) { - gMobileConnectionService - .notifyCdmaInfoRecCallingPartyNumber(clientId, - aRecord.callingNumber.type, - aRecord.callingNumber.plan, - aRecord.callingNumber.number, - aRecord.callingNumber.pi, - aRecord.callingNumber.si); - return; - } - - if (aRecord.connectedNumber) { - gMobileConnectionService - .notifyCdmaInfoRecConnectedPartyNumber(clientId, - aRecord.connectedNumber.type, - aRecord.connectedNumber.plan, - aRecord.connectedNumber.number, - aRecord.connectedNumber.pi, - aRecord.connectedNumber.si); - return; - } - - if (aRecord.signal) { - gMobileConnectionService - .notifyCdmaInfoRecSignal(clientId, - aRecord.signal.type, - aRecord.signal.alertPitch, - aRecord.signal.signal); - return; - } - - if (aRecord.redirect) { - gMobileConnectionService - .notifyCdmaInfoRecRedirectingNumber(clientId, - aRecord.redirect.type, - aRecord.redirect.plan, - aRecord.redirect.number, - aRecord.redirect.pi, - aRecord.redirect.si, - aRecord.redirect.reason); - return; - } - - if (aRecord.lineControl) { - gMobileConnectionService - .notifyCdmaInfoRecLineControl(clientId, - aRecord.lineControl.polarityIncluded, - aRecord.lineControl.toggle, - aRecord.lineControl.reverse, - aRecord.lineControl.powerDenial); - return; - } - - if (aRecord.clirCause) { - gMobileConnectionService - .notifyCdmaInfoRecClir(clientId, - aRecord.clirCause); - return; - } - - if (aRecord.audioControl) { - gMobileConnectionService - .notifyCdmaInfoRecAudioControl(clientId, - aRecord.audioControl.upLink, - aRecord.audioControl.downLink); - return; - } - }); - }, - - // nsIObserver - - observe: function(subject, topic, data) { - switch (topic) { - case kMozSettingsChangedObserverTopic: - if ("wrappedJSObject" in subject) { - subject = subject.wrappedJSObject; - } - this.handleSettingsChange(subject.key, subject.value, subject.isInternalChange); - break; - case kSysClockChangeObserverTopic: - let offset = parseInt(data, 10); - if (this._lastNitzMessage) { - this._lastNitzMessage.receiveTimeInMS += offset; - } - this._sntp.updateOffset(offset); - break; - case kNetworkConnStateChangedTopic: - let networkInfo = subject.QueryInterface(Ci.nsINetworkInfo); - if (networkInfo.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - return; - } - - // SNTP can only update when we have mobile or Wifi connections. - if (networkInfo.type != NETWORK_TYPE_WIFI && - networkInfo.type != NETWORK_TYPE_MOBILE) { - return; - } - - // If the network comes from RIL, make sure the RIL service is matched. - if (subject instanceof Ci.nsIRilNetworkInfo) { - networkInfo = subject.QueryInterface(Ci.nsIRilNetworkInfo); - if (networkInfo.serviceId != this.clientId) { - return; - } - } - - // SNTP won't update unless the SNTP is already expired. - if (this._sntp.isExpired()) { - this._sntp.request(); - } - break; - case kScreenStateChangedTopic: - this.workerMessenger.send("setScreenState", { on: (data === "on") }); - break; - } - }, - - // Flag to determine whether to update system clock automatically. It - // corresponds to the "time.clock.automatic-update.enabled" setting. - _clockAutoUpdateEnabled: null, - - // Flag to determine whether to update system timezone automatically. It - // corresponds to the "time.clock.automatic-update.enabled" setting. - _timezoneAutoUpdateEnabled: null, - - // Remember the last NITZ message so that we can set the time based on - // the network immediately when users enable network-based time. - _lastNitzMessage: null, - - // Object that handles SNTP. - _sntp: null, - - // Cell Broadcast settings values. - _cellBroadcastSearchList: null, - - handleSettingsChange: function(aName, aResult, aIsInternalSetting) { - // Don't allow any content processes to modify the setting - // "time.clock.automatic-update.available" except for the chrome process. - if (aName === kSettingsClockAutoUpdateAvailable && - !aIsInternalSetting) { - let isClockAutoUpdateAvailable = this._lastNitzMessage !== null || - this._sntp.isAvailable(); - if (aResult !== isClockAutoUpdateAvailable) { - if (DEBUG) { - debug("Content processes cannot modify 'time.clock.automatic-update.available'. Restore!"); - } - // Restore the setting to the current value. - this.setClockAutoUpdateAvailable(isClockAutoUpdateAvailable); - } - } - - // Don't allow any content processes to modify the setting - // "time.timezone.automatic-update.available" except for the chrome - // process. - if (aName === kSettingsTimezoneAutoUpdateAvailable && - !aIsInternalSetting) { - let isTimezoneAutoUpdateAvailable = this._lastNitzMessage !== null; - if (aResult !== isTimezoneAutoUpdateAvailable) { - if (DEBUG) { - this.debug("Content processes cannot modify 'time.timezone.automatic-update.available'. Restore!"); - } - // Restore the setting to the current value. - this.setTimezoneAutoUpdateAvailable(isTimezoneAutoUpdateAvailable); - } - } - - this.handle(aName, aResult); - }, - - // nsISettingsServiceCallback - handle: function(aName, aResult) { - switch(aName) { - case kSettingsClockAutoUpdateEnabled: - this._clockAutoUpdateEnabled = aResult; - if (!this._clockAutoUpdateEnabled) { - break; - } - - // Set the latest cached NITZ time if it's available. - if (this._lastNitzMessage) { - this.setClockByNitz(this._lastNitzMessage); - } else if (gNetworkManager.activeNetworkInfo && - gNetworkManager.activeNetworkInfo.state == - Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - // Set the latest cached SNTP time if it's available. - if (!this._sntp.isExpired()) { - this.setClockBySntp(this._sntp.getOffset()); - } else { - // Or refresh the SNTP. - this._sntp.request(); - } - } else { - // Set a sane minimum time. - let buildTime = libcutils.property_get("ro.build.date.utc", "0") * 1000; - let file = FileUtils.File("/system/b2g/b2g"); - if (file.lastModifiedTime > buildTime) { - buildTime = file.lastModifiedTime; - } - if (buildTime > Date.now()) { - gTimeService.set(buildTime); - } - } - break; - case kSettingsTimezoneAutoUpdateEnabled: - this._timezoneAutoUpdateEnabled = aResult; - - if (this._timezoneAutoUpdateEnabled) { - // Apply the latest cached NITZ for timezone if it's available. - if (this._timezoneAutoUpdateEnabled && this._lastNitzMessage) { - this.setTimezoneByNitz(this._lastNitzMessage); - } - } - break; - } - }, - - handleError: function(aErrorMessage) { - if (DEBUG) { - this.debug("There was an error while reading RIL settings."); - } - }, - - // nsIRadioInterface - - // TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function - // for connecting - setupDataCallByType: function(networkType) { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - connHandler.setupDataCallByType(networkType); - }, - - // TODO: Bug 928861 - B2G NetworkManager: Provide a more generic function - // for connecting - deactivateDataCallByType: function(networkType) { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - connHandler.deactivateDataCallByType(networkType); - }, - - // TODO: Bug 904514 - [meta] NetworkManager enhancement - getDataCallStateByType: function(networkType) { - let connHandler = gDataCallManager.getDataCallHandler(this.clientId); - return connHandler.getDataCallStateByType(networkType); - }, - - sendWorkerMessage: function(rilMessageType, message, callback) { - // Special handler for setRadioEnabled. - if (rilMessageType === "setRadioEnabled") { - // Forward it to gRadioEnabledController. - gRadioEnabledController.setRadioEnabled(this.clientId, message, - callback.handleResponse); - return; - } - - if (callback) { - this.workerMessenger.send(rilMessageType, message, function(response) { - return callback.handleResponse(response); - }); - } else { - this.workerMessenger.send(rilMessageType, message); - } - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([RadioInterfaceLayer]); diff --git a/dom/system/gonk/RadioInterfaceLayer.manifest b/dom/system/gonk/RadioInterfaceLayer.manifest deleted file mode 100644 index 3c7c3b808..000000000 --- a/dom/system/gonk/RadioInterfaceLayer.manifest +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2012 Mozilla Foundation and Mozilla contributors -# -# 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. - -# RadioInterfaceLayer.js -component {2d831c8d-6017-435b-a80c-e5d422810cea} RadioInterfaceLayer.js -contract @mozilla.org/ril;1 {2d831c8d-6017-435b-a80c-e5d422810cea} -category profile-after-change RadioInterfaceLayer @mozilla.org/ril;1 diff --git a/dom/system/gonk/SystemProperty.cpp b/dom/system/gonk/SystemProperty.cpp deleted file mode 100644 index 1f874ce90..000000000 --- a/dom/system/gonk/SystemProperty.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "SystemProperty.h" - -#include -#include - -#include "nsDebug.h" -#include "prinit.h" - -namespace mozilla { -namespace system { - -namespace { - -typedef int (*PropertyGet)(const char*, char*, const char*); -typedef int (*PropertySet)(const char*, const char*); - -static void *sLibcUtils; -static PRCallOnceType sInitLibcUtils; - -static int -FakePropertyGet(const char* key, char* value, const char* default_value) -{ - if(!default_value) { - value[0] = '\0'; - return 0; - } - - int len = strlen(default_value); - if (len >= Property::VALUE_MAX_LENGTH) { - len = Property::VALUE_MAX_LENGTH - 1; - } - memcpy(value, default_value, len); - value[len] = '\0'; - - return len; -} - -static int -FakePropertySet(const char* key, const char* value) -{ - return 0; -} - -static PRStatus -InitLibcUtils() -{ - sLibcUtils = dlopen("/system/lib/libcutils.so", RTLD_LAZY); - // We will fallback to the fake getter/setter when sLibcUtils is not valid. - return PR_SUCCESS; -} - -static void* -GetLibcUtils() -{ - PR_CallOnce(&sInitLibcUtils, InitLibcUtils); - return sLibcUtils; -} - -} // anonymous namespace - -/*static*/ int -Property::Get(const char* key, char* value, const char* default_value) -{ - void *libcutils = GetLibcUtils(); - if (libcutils) { - PropertyGet getter = (PropertyGet) dlsym(libcutils, "property_get"); - if (getter) { - return getter(key, value, default_value); - } - NS_WARNING("Failed to get property_get() from libcutils!"); - } - NS_WARNING("Fallback to the FakePropertyGet()"); - return FakePropertyGet(key, value, default_value); -} - -/*static*/ int -Property::Set(const char* key, const char* value) -{ - void *libcutils = GetLibcUtils(); - if (libcutils) { - PropertySet setter = (PropertySet) dlsym(libcutils, "property_set"); - if (setter) { - return setter(key, value); - } - NS_WARNING("Failed to get property_set() from libcutils!"); - } - NS_WARNING("Fallback to the FakePropertySet()"); - return FakePropertySet(key, value); -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/SystemProperty.h b/dom/system/gonk/SystemProperty.h deleted file mode 100644 index 2b5ceae8b..000000000 --- a/dom/system/gonk/SystemProperty.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_Property_h -#define mozilla_system_Property_h - -namespace mozilla { -namespace system { - -/** -* Abstraction of property_get/property_get in libcutils from AOSP. -*/ -class Property -{ -public: - // Constants defined in system_properties.h from AOSP. - enum { - KEY_MAX_LENGTH = 32, - VALUE_MAX_LENGTH = 92 - }; - - static int - Get(const char* key, char* value, const char* default_value); - - static int - Set(const char* key, const char* value); - -private: - Property() {} - virtual ~Property() {} -}; - -} // namespace system -} // namespace mozilla - - #endif // mozilla_system_Property_h diff --git a/dom/system/gonk/SystemWorkerManager.cpp b/dom/system/gonk/SystemWorkerManager.cpp deleted file mode 100644 index ee3fc8de3..000000000 --- a/dom/system/gonk/SystemWorkerManager.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "SystemWorkerManager.h" - -#include "nsINetworkService.h" -#include "nsIWifi.h" -#include "nsIWorkerHolder.h" -#include "nsIXPConnect.h" - -#include "jsfriendapi.h" -#include "mozilla/dom/workers/Workers.h" -#include "AutoMounter.h" -#include "TimeZoneSettingObserver.h" -#include "AudioManager.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/ipc/KeyStore.h" -#include "nsIObserverService.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "WifiWorker.h" -#include "mozilla/Services.h" - -USING_WORKERS_NAMESPACE - -using namespace mozilla::dom::gonk; -using namespace mozilla::ipc; -using namespace mozilla::system; - -namespace { - -NS_DEFINE_CID(kWifiWorkerCID, NS_WIFIWORKER_CID); - -// Doesn't carry a reference, we're owned by services. -SystemWorkerManager *gInstance = nullptr; - -} // namespace - -SystemWorkerManager::SystemWorkerManager() - : mShutdown(false) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(!gInstance, "There should only be one instance!"); -} - -SystemWorkerManager::~SystemWorkerManager() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - NS_ASSERTION(!gInstance || gInstance == this, - "There should only be one instance!"); - gInstance = nullptr; -} - -nsresult -SystemWorkerManager::Init() -{ - if (!XRE_IsParentProcess()) { - return NS_ERROR_NOT_AVAILABLE; - } - - NS_ASSERTION(NS_IsMainThread(), "We can only initialize on the main thread"); - NS_ASSERTION(!mShutdown, "Already shutdown!"); - - nsresult rv = InitWifi(); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to initialize WiFi Networking!"); - return rv; - } - - InitKeyStore(); - - InitAutoMounter(); - InitializeTimeZoneSettingObserver(); - nsCOMPtr audioManager = - do_GetService(NS_AUDIOMANAGER_CONTRACTID); - - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (!obs) { - NS_WARNING("Failed to get observer service!"); - return NS_ERROR_FAILURE; - } - - rv = obs->AddObserver(this, WORKERS_SHUTDOWN_TOPIC, false); - if (NS_FAILED(rv)) { - NS_WARNING("Failed to initialize worker shutdown event!"); - return rv; - } - - return NS_OK; -} - -void -SystemWorkerManager::Shutdown() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - mShutdown = true; - - ShutdownAutoMounter(); - - nsCOMPtr wifi(do_QueryInterface(mWifiWorker)); - if (wifi) { - wifi->Shutdown(); - wifi = nullptr; - } - mWifiWorker = nullptr; - - if (mKeyStore) { - mKeyStore->Shutdown(); - mKeyStore = nullptr; - } - - nsCOMPtr obs = mozilla::services::GetObserverService(); - if (obs) { - obs->RemoveObserver(this, WORKERS_SHUTDOWN_TOPIC); - } -} - -// static -already_AddRefed -SystemWorkerManager::FactoryCreate() -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - RefPtr instance(gInstance); - - if (!instance) { - instance = new SystemWorkerManager(); - if (NS_FAILED(instance->Init())) { - instance->Shutdown(); - return nullptr; - } - - gInstance = instance; - } - - return instance.forget(); -} - -// static -nsIInterfaceRequestor* -SystemWorkerManager::GetInterfaceRequestor() -{ - return gInstance; -} - -NS_IMETHODIMP -SystemWorkerManager::GetInterface(const nsIID &aIID, void **aResult) -{ - NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); - - if (aIID.Equals(NS_GET_IID(nsIWifi))) { - return CallQueryInterface(mWifiWorker, - reinterpret_cast(aResult)); - } - - NS_WARNING("Got nothing for the requested IID!"); - return NS_ERROR_NO_INTERFACE; -} - -nsresult -SystemWorkerManager::RegisterRilWorker(unsigned int aClientId, - JS::Handle aWorker, - JSContext *aCx) -{ - return NS_ERROR_NOT_IMPLEMENTED; -} - -nsresult -SystemWorkerManager::InitWifi() -{ - nsCOMPtr worker = do_CreateInstance(kWifiWorkerCID); - NS_ENSURE_TRUE(worker, NS_ERROR_FAILURE); - - mWifiWorker = worker; - return NS_OK; -} - -nsresult -SystemWorkerManager::InitKeyStore() -{ - mKeyStore = new KeyStore(); - return NS_OK; -} - -NS_IMPL_ISUPPORTS(SystemWorkerManager, - nsIObserver, - nsIInterfaceRequestor, - nsISystemWorkerManager) - -NS_IMETHODIMP -SystemWorkerManager::Observe(nsISupports *aSubject, const char *aTopic, - const char16_t *aData) -{ - if (!strcmp(aTopic, WORKERS_SHUTDOWN_TOPIC)) { - Shutdown(); - } - - return NS_OK; -} diff --git a/dom/system/gonk/SystemWorkerManager.h b/dom/system/gonk/SystemWorkerManager.h deleted file mode 100644 index 625cda261..000000000 --- a/dom/system/gonk/SystemWorkerManager.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=40: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef mozilla_dom_system_b2g_systemworkermanager_h__ -#define mozilla_dom_system_b2g_systemworkermanager_h__ - -#include "nsIInterfaceRequestor.h" -#include "nsISystemWorkerManager.h" -#include "nsIObserver.h" -#include "nsCOMPtr.h" -#include "nsXULAppAPI.h" // For XRE_GetProcessType - -class nsIWorkerHolder; - -namespace mozilla { - -namespace ipc { - class KeyStore; -} - -namespace dom { -namespace gonk { - -class SystemWorkerManager final : public nsIObserver, - public nsIInterfaceRequestor, - public nsISystemWorkerManager -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_NSIINTERFACEREQUESTOR - NS_DECL_NSISYSTEMWORKERMANAGER - - nsresult Init(); - void Shutdown(); - - static already_AddRefed - FactoryCreate(); - - static nsIInterfaceRequestor* - GetInterfaceRequestor(); - -private: - SystemWorkerManager(); - ~SystemWorkerManager(); - - nsresult InitWifi(); - nsresult InitKeyStore(); - - nsCOMPtr mWifiWorker; - - RefPtr mKeyStore; - - bool mShutdown; -}; - -} -} -} - -#endif // mozilla_dom_system_b2g_systemworkermanager_h__ diff --git a/dom/system/gonk/TetheringService.js b/dom/system/gonk/TetheringService.js deleted file mode 100644 index c5c478180..000000000 --- a/dom/system/gonk/TetheringService.js +++ /dev/null @@ -1,891 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -const TETHERINGSERVICE_CONTRACTID = "@mozilla.org/tethering/service;1"; -const TETHERINGSERVICE_CID = - Components.ID("{527a4121-ee5a-4651-be9c-f46f59cf7c01}"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkManager", - "@mozilla.org/network/manager;1", - "nsINetworkManager"); - -XPCOMUtils.defineLazyServiceGetter(this, "gNetworkService", - "@mozilla.org/network/service;1", - "nsINetworkService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService", - "@mozilla.org/settingsService;1", - "nsISettingsService"); - -XPCOMUtils.defineLazyServiceGetter(this, "gMobileConnectionService", - "@mozilla.org/mobileconnection/mobileconnectionservice;1", - "nsIMobileConnectionService"); - -XPCOMUtils.defineLazyGetter(this, "gRil", function() { - try { - return Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); - } catch (e) {} - - return null; -}); - -const TOPIC_MOZSETTINGS_CHANGED = "mozsettings-changed"; -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const TOPIC_PREF_CHANGED = "nsPref:changed"; -const TOPIC_XPCOM_SHUTDOWN = "xpcom-shutdown"; -const PREF_MANAGE_OFFLINE_STATUS = "network.gonk.manage-offline-status"; -const PREF_NETWORK_DEBUG_ENABLED = "network.debugging.enabled"; - -const POSSIBLE_USB_INTERFACE_NAME = "rndis0,usb0"; -const DEFAULT_USB_INTERFACE_NAME = "rndis0"; -const DEFAULT_3G_INTERFACE_NAME = "rmnet0"; -const DEFAULT_WIFI_INTERFACE_NAME = "wlan0"; - -// The kernel's proc entry for network lists. -const KERNEL_NETWORK_ENTRY = "/sys/class/net"; - -const TETHERING_TYPE_WIFI = "WiFi"; -const TETHERING_TYPE_USB = "USB"; - -const WIFI_FIRMWARE_AP = "AP"; -const WIFI_FIRMWARE_STATION = "STA"; -const WIFI_SECURITY_TYPE_NONE = "open"; -const WIFI_SECURITY_TYPE_WPA_PSK = "wpa-psk"; -const WIFI_SECURITY_TYPE_WPA2_PSK = "wpa2-psk"; -const WIFI_CTRL_INTERFACE = "wl0.1"; - -const NETWORK_INTERFACE_UP = "up"; -const NETWORK_INTERFACE_DOWN = "down"; - -const TETHERING_STATE_ONGOING = "ongoing"; -const TETHERING_STATE_IDLE = "idle"; -const TETHERING_STATE_ACTIVE = "active"; - -// Settings DB path for USB tethering. -const SETTINGS_USB_ENABLED = "tethering.usb.enabled"; -const SETTINGS_USB_IP = "tethering.usb.ip"; -const SETTINGS_USB_PREFIX = "tethering.usb.prefix"; -const SETTINGS_USB_DHCPSERVER_STARTIP = "tethering.usb.dhcpserver.startip"; -const SETTINGS_USB_DHCPSERVER_ENDIP = "tethering.usb.dhcpserver.endip"; -const SETTINGS_USB_DNS1 = "tethering.usb.dns1"; -const SETTINGS_USB_DNS2 = "tethering.usb.dns2"; - -// Settings DB path for WIFI tethering. -const SETTINGS_WIFI_DHCPSERVER_STARTIP = "tethering.wifi.dhcpserver.startip"; -const SETTINGS_WIFI_DHCPSERVER_ENDIP = "tethering.wifi.dhcpserver.endip"; - -// Settings DB patch for dun required setting. -const SETTINGS_DUN_REQUIRED = "tethering.dun.required"; - -// Default value for USB tethering. -const DEFAULT_USB_IP = "192.168.0.1"; -const DEFAULT_USB_PREFIX = "24"; -const DEFAULT_USB_DHCPSERVER_STARTIP = "192.168.0.10"; -const DEFAULT_USB_DHCPSERVER_ENDIP = "192.168.0.30"; - -const DEFAULT_DNS1 = "8.8.8.8"; -const DEFAULT_DNS2 = "8.8.4.4"; - -const DEFAULT_WIFI_DHCPSERVER_STARTIP = "192.168.1.10"; -const DEFAULT_WIFI_DHCPSERVER_ENDIP = "192.168.1.30"; - -const SETTINGS_DATA_DEFAULT_SERVICE_ID = "ril.data.defaultServiceId"; -const MOBILE_DUN_CONNECT_TIMEOUT = 30000; -const MOBILE_DUN_RETRY_INTERVAL = 5000; -const MOBILE_DUN_MAX_RETRIES = 5; - -var debug; -function updateDebug() { - let debugPref = false; // set default value here. - try { - debugPref = debugPref || Services.prefs.getBoolPref(PREF_NETWORK_DEBUG_ENABLED); - } catch (e) {} - - if (debugPref) { - debug = function(s) { - dump("-*- TetheringService: " + s + "\n"); - }; - } else { - debug = function(s) {}; - } -} -updateDebug(); - -function TetheringService() { - Services.obs.addObserver(this, TOPIC_XPCOM_SHUTDOWN, false); - Services.obs.addObserver(this, TOPIC_MOZSETTINGS_CHANGED, false); - Services.obs.addObserver(this, TOPIC_CONNECTION_STATE_CHANGED, false); - Services.prefs.addObserver(PREF_NETWORK_DEBUG_ENABLED, this, false); - Services.prefs.addObserver(PREF_MANAGE_OFFLINE_STATUS, this, false); - - try { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - } catch(ex) { - // Ignore. - } - - this._dataDefaultServiceId = 0; - - // Possible usb tethering interfaces for different gonk platform. - this.possibleInterface = POSSIBLE_USB_INTERFACE_NAME.split(","); - - // Default values for internal and external interfaces. - this._tetheringInterface = {}; - this._tetheringInterface[TETHERING_TYPE_USB] = { - externalInterface: DEFAULT_3G_INTERFACE_NAME, - internalInterface: DEFAULT_USB_INTERFACE_NAME - }; - this._tetheringInterface[TETHERING_TYPE_WIFI] = { - externalInterface: DEFAULT_3G_INTERFACE_NAME, - internalInterface: DEFAULT_WIFI_INTERFACE_NAME - }; - - this.tetheringSettings = {}; - this.initTetheringSettings(); - - let settingsLock = gSettingsService.createLock(); - // Read the default service id for data call. - settingsLock.get(SETTINGS_DATA_DEFAULT_SERVICE_ID, this); - - // Read usb tethering data from settings DB. - settingsLock.get(SETTINGS_USB_IP, this); - settingsLock.get(SETTINGS_USB_PREFIX, this); - settingsLock.get(SETTINGS_USB_DHCPSERVER_STARTIP, this); - settingsLock.get(SETTINGS_USB_DHCPSERVER_ENDIP, this); - settingsLock.get(SETTINGS_USB_DNS1, this); - settingsLock.get(SETTINGS_USB_DNS2, this); - settingsLock.get(SETTINGS_USB_ENABLED, this); - - // Read wifi tethering data from settings DB. - settingsLock.get(SETTINGS_WIFI_DHCPSERVER_STARTIP, this); - settingsLock.get(SETTINGS_WIFI_DHCPSERVER_ENDIP, this); - - this._usbTetheringSettingsToRead = [SETTINGS_USB_IP, - SETTINGS_USB_PREFIX, - SETTINGS_USB_DHCPSERVER_STARTIP, - SETTINGS_USB_DHCPSERVER_ENDIP, - SETTINGS_USB_DNS1, - SETTINGS_USB_DNS2, - SETTINGS_USB_ENABLED, - SETTINGS_WIFI_DHCPSERVER_STARTIP, - SETTINGS_WIFI_DHCPSERVER_ENDIP]; - - this.wantConnectionEvent = null; - - this.dunConnectTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - this.dunRetryTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - - this._pendingTetheringRequests = []; -} -TetheringService.prototype = { - classID: TETHERINGSERVICE_CID, - classInfo: XPCOMUtils.generateCI({classID: TETHERINGSERVICE_CID, - contractID: TETHERINGSERVICE_CONTRACTID, - classDescription: "Tethering Service", - interfaces: [Ci.nsITetheringService]}), - QueryInterface: XPCOMUtils.generateQI([Ci.nsITetheringService, - Ci.nsISupportsWeakReference, - Ci.nsIObserver, - Ci.nsISettingsServiceCallback]), - - // Flag to record the default client id for data call. - _dataDefaultServiceId: null, - - // Number of usb tehering requests to be processed. - _usbTetheringRequestCount: 0, - - // Usb tethering state. - _usbTetheringAction: TETHERING_STATE_IDLE, - - // Tethering settings. - tetheringSettings: null, - - // Tethering settings need to be read from settings DB. - _usbTetheringSettingsToRead: null, - - // Previous usb tethering enabled state. - _oldUsbTetheringEnabledState: null, - - // External and internal interface name. - _tetheringInterface: null, - - // Dun connection timer. - dunConnectTimer: null, - - // Dun connection retry times. - dunRetryTimes: 0, - - // Dun retry timer. - dunRetryTimer: null, - - // Pending tethering request to handle after dun is connected. - _pendingTetheringRequests: null, - - // Flag to indicate wether wifi tethering is being processed. - _wifiTetheringRequestOngoing: false, - - // Arguments for pending wifi tethering request. - _pendingWifiTetheringRequestArgs: null, - - // The state of tethering. - state: Ci.nsITetheringService.TETHERING_STATE_INACTIVE, - - // Flag to check if we can modify the Services.io.offline. - _manageOfflineStatus: true, - - // nsIObserver - - observe: function(aSubject, aTopic, aData) { - let network; - - switch(aTopic) { - case TOPIC_PREF_CHANGED: - if (aData === PREF_NETWORK_DEBUG_ENABLED) { - updateDebug(); - } - break; - case TOPIC_MOZSETTINGS_CHANGED: - if ("wrappedJSObject" in aSubject) { - aSubject = aSubject.wrappedJSObject; - } - this.handle(aSubject.key, aSubject.value); - break; - case TOPIC_CONNECTION_STATE_CHANGED: - network = aSubject.QueryInterface(Ci.nsINetworkInfo); - debug("Network " + network.type + "/" + network.name + - " changed state to " + network.state); - this.onConnectionChanged(network); - break; - case TOPIC_XPCOM_SHUTDOWN: - Services.obs.removeObserver(this, TOPIC_XPCOM_SHUTDOWN); - Services.obs.removeObserver(this, TOPIC_MOZSETTINGS_CHANGED); - Services.obs.removeObserver(this, TOPIC_CONNECTION_STATE_CHANGED); - Services.prefs.removeObserver(PREF_NETWORK_DEBUG_ENABLED, this); - Services.prefs.removeObserver(PREF_MANAGE_OFFLINE_STATUS, this); - - this.dunConnectTimer.cancel(); - this.dunRetryTimer.cancel(); - break; - case PREF_MANAGE_OFFLINE_STATUS: - try { - this._manageOfflineStatus = - Services.prefs.getBoolPref(PREF_MANAGE_OFFLINE_STATUS); - } catch(ex) { - // Ignore. - } - break; - } - }, - - // nsISettingsServiceCallback - - handle: function(aName, aResult) { - switch(aName) { - case SETTINGS_DATA_DEFAULT_SERVICE_ID: - this._dataDefaultServiceId = aResult || 0; - debug("'_dataDefaultServiceId' is now " + this._dataDefaultServiceId); - break; - case SETTINGS_USB_ENABLED: - this._oldUsbTetheringEnabledState = this.tetheringSettings[SETTINGS_USB_ENABLED]; - case SETTINGS_USB_IP: - case SETTINGS_USB_PREFIX: - case SETTINGS_USB_DHCPSERVER_STARTIP: - case SETTINGS_USB_DHCPSERVER_ENDIP: - case SETTINGS_USB_DNS1: - case SETTINGS_USB_DNS2: - case SETTINGS_WIFI_DHCPSERVER_STARTIP: - case SETTINGS_WIFI_DHCPSERVER_ENDIP: - if (aResult !== null) { - this.tetheringSettings[aName] = aResult; - } - debug("'" + aName + "'" + " is now " + this.tetheringSettings[aName]); - let index = this._usbTetheringSettingsToRead.indexOf(aName); - - if (index != -1) { - this._usbTetheringSettingsToRead.splice(index, 1); - } - - if (this._usbTetheringSettingsToRead.length) { - debug("We haven't read completely the usb Tethering data from settings db."); - break; - } - - if (this._oldUsbTetheringEnabledState === this.tetheringSettings[SETTINGS_USB_ENABLED]) { - debug("No changes for SETTINGS_USB_ENABLED flag. Nothing to do."); - this.handlePendingWifiTetheringRequest(); - break; - } - - this._usbTetheringRequestCount++; - if (this._usbTetheringRequestCount === 1) { - if (this._wifiTetheringRequestOngoing) { - debug('USB tethering request is blocked by ongoing wifi tethering request.'); - } else { - this.handleLastUsbTetheringRequest(); - } - } - break; - }; - }, - - handleError: function(aErrorMessage) { - debug("There was an error while reading Tethering settings."); - this.tetheringSettings = {}; - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - }, - - initTetheringSettings: function() { - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - this.tetheringSettings[SETTINGS_USB_IP] = DEFAULT_USB_IP; - this.tetheringSettings[SETTINGS_USB_PREFIX] = DEFAULT_USB_PREFIX; - this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP] = DEFAULT_USB_DHCPSERVER_STARTIP; - this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP] = DEFAULT_USB_DHCPSERVER_ENDIP; - this.tetheringSettings[SETTINGS_USB_DNS1] = DEFAULT_DNS1; - this.tetheringSettings[SETTINGS_USB_DNS2] = DEFAULT_DNS2; - - this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP] = DEFAULT_WIFI_DHCPSERVER_STARTIP; - this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP] = DEFAULT_WIFI_DHCPSERVER_ENDIP; - - this.tetheringSettings[SETTINGS_DUN_REQUIRED] = - libcutils.property_get("ro.tethering.dun_required") === "1"; - }, - - getNetworkInfo: function(aType, aServiceId) { - for (let networkId in gNetworkManager.allNetworkInfo) { - let networkInfo = gNetworkManager.allNetworkInfo[networkId]; - if (networkInfo.type == aType) { - try { - if (networkInfo instanceof Ci.nsIRilNetworkInfo) { - let rilNetwork = networkInfo.QueryInterface(Ci.nsIRilNetworkInfo); - if (rilNetwork.serviceId != aServiceId) { - continue; - } - } - } catch (e) {} - return networkInfo; - } - } - return null; - }, - - handleLastUsbTetheringRequest: function() { - debug('handleLastUsbTetheringRequest... ' + this._usbTetheringRequestCount); - - if (this._usbTetheringRequestCount === 0) { - if (this.wantConnectionEvent) { - if (this.tetheringSettings[SETTINGS_USB_ENABLED]) { - this.wantConnectionEvent.call(this); - } - this.wantConnectionEvent = null; - } - this.handlePendingWifiTetheringRequest(); - return; - } - - // Cancel the accumlated count to 1 since we only care about the - // last state. - this._usbTetheringRequestCount = 1; - this.handleUSBTetheringToggle(this.tetheringSettings[SETTINGS_USB_ENABLED]); - this.wantConnectionEvent = null; - }, - - handlePendingWifiTetheringRequest: function() { - if (this._pendingWifiTetheringRequestArgs) { - this.setWifiTethering.apply(this, this._pendingWifiTetheringRequestArgs); - this._pendingWifiTetheringRequestArgs = null; - } - }, - - /** - * Callback when dun connection fails to connect within timeout. - */ - onDunConnectTimerTimeout: function() { - while (this._pendingTetheringRequests.length > 0) { - debug("onDunConnectTimerTimeout: callback without network info."); - let callback = this._pendingTetheringRequests.shift(); - if (typeof callback === 'function') { - callback(); - } - } - }, - - setupDunConnection: function() { - this.dunRetryTimer.cancel(); - let connection = - gMobileConnectionService.getItemByServiceId(this._dataDefaultServiceId); - let data = connection && connection.data; - if (data && data.state === "registered") { - let ril = gRil.getRadioInterface(this._dataDefaultServiceId); - - this.dunRetryTimes = 0; - ril.setupDataCallByType(Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN); - this.dunConnectTimer.cancel(); - this.dunConnectTimer. - initWithCallback(this.onDunConnectTimerTimeout.bind(this), - MOBILE_DUN_CONNECT_TIMEOUT, Ci.nsITimer.TYPE_ONE_SHOT); - return; - } - - if (this.dunRetryTimes++ >= this.MOBILE_DUN_MAX_RETRIES) { - debug("setupDunConnection: max retries reached."); - this.dunRetryTimes = 0; - // same as dun connect timeout. - this.onDunConnectTimerTimeout(); - return; - } - - debug("Data not ready, retry dun after " + MOBILE_DUN_RETRY_INTERVAL + " ms."); - this.dunRetryTimer. - initWithCallback(this.setupDunConnection.bind(this), - MOBILE_DUN_RETRY_INTERVAL, Ci.nsITimer.TYPE_ONE_SHOT); - }, - - _dunActiveUsers: 0, - handleDunConnection: function(aEnable, aCallback) { - debug("handleDunConnection: " + aEnable); - let dun = this.getNetworkInfo( - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN, this._dataDefaultServiceId); - - if (!aEnable) { - this._dunActiveUsers--; - if (this._dunActiveUsers > 0) { - debug("Dun still needed by others, do not disconnect.") - return; - } - - this.dunRetryTimes = 0; - this.dunRetryTimer.cancel(); - this.dunConnectTimer.cancel(); - this._pendingTetheringRequests = []; - - if (dun && (dun.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED)) { - gRil.getRadioInterface(this._dataDefaultServiceId) - .deactivateDataCallByType(Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN); - } - return; - } - - this._dunActiveUsers++; - if (!dun || (dun.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED)) { - debug("DUN data call inactive, setup dun data call!") - this._pendingTetheringRequests.push(aCallback); - this.dunRetryTimes = 0; - this.setupDunConnection(); - - return; - } - - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = dun.name; - aCallback(dun); - }, - - handleUSBTetheringToggle: function(aEnable) { - debug("handleUSBTetheringToggle: " + aEnable); - if (aEnable && - (this._usbTetheringAction === TETHERING_STATE_ONGOING || - this._usbTetheringAction === TETHERING_STATE_ACTIVE)) { - debug("Usb tethering already connecting/connected."); - this._usbTetheringRequestCount = 0; - this.handlePendingWifiTetheringRequest(); - return; - } - - if (!aEnable && - this._usbTetheringAction === TETHERING_STATE_IDLE) { - debug("Usb tethering already disconnected."); - this._usbTetheringRequestCount = 0; - this.handlePendingWifiTetheringRequest(); - return; - } - - if (!aEnable) { - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - gNetworkService.enableUsbRndis(false, this.enableUsbRndisResult.bind(this)); - return; - } - - this.tetheringSettings[SETTINGS_USB_ENABLED] = true; - this._usbTetheringAction = TETHERING_STATE_ONGOING; - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(true, (aNetworkInfo) => { - if (!aNetworkInfo){ - this.usbTetheringResultReport(aEnable, "Dun connection failed"); - return; - } - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = - aNetworkInfo.name; - gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this)); - }); - return; - } - - if (gNetworkManager.activeNetworkInfo) { - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = - gNetworkManager.activeNetworkInfo.name; - } else { - let mobile = this.getNetworkInfo( - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE, this._dataDefaultServiceId); - if (mobile && mobile.name) { - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = mobile.name; - } - } - gNetworkService.enableUsbRndis(true, this.enableUsbRndisResult.bind(this)); - }, - - getUSBTetheringParameters: function(aEnable, aTetheringInterface) { - let interfaceIp = this.tetheringSettings[SETTINGS_USB_IP]; - let prefix = this.tetheringSettings[SETTINGS_USB_PREFIX]; - let wifiDhcpStartIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_STARTIP]; - let wifiDhcpEndIp = this.tetheringSettings[SETTINGS_WIFI_DHCPSERVER_ENDIP]; - let usbDhcpStartIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_STARTIP]; - let usbDhcpEndIp = this.tetheringSettings[SETTINGS_USB_DHCPSERVER_ENDIP]; - let dns1 = this.tetheringSettings[SETTINGS_USB_DNS1]; - let dns2 = this.tetheringSettings[SETTINGS_USB_DNS2]; - let internalInterface = aTetheringInterface.internalInterface; - let externalInterface = aTetheringInterface.externalInterface; - - // Using the default values here until application support these settings. - if (interfaceIp == "" || prefix == "" || - wifiDhcpStartIp == "" || wifiDhcpEndIp == "" || - usbDhcpStartIp == "" || usbDhcpEndIp == "") { - debug("Invalid subnet information."); - return null; - } - - return { - ifname: internalInterface, - ip: interfaceIp, - prefix: prefix, - wifiStartIp: wifiDhcpStartIp, - wifiEndIp: wifiDhcpEndIp, - usbStartIp: usbDhcpStartIp, - usbEndIp: usbDhcpEndIp, - dns1: dns1, - dns2: dns2, - internalIfname: internalInterface, - externalIfname: externalInterface, - enable: aEnable, - link: aEnable ? NETWORK_INTERFACE_UP : NETWORK_INTERFACE_DOWN - }; - }, - - notifyError: function(aResetSettings, aCallback, aMsg) { - if (aResetSettings) { - let settingsLock = gSettingsService.createLock(); - // Disable wifi tethering with a useful error message for the user. - settingsLock.set("tethering.wifi.enabled", false, null, aMsg); - } - - debug("setWifiTethering: " + (aMsg ? aMsg : "success")); - - if (aCallback) { - // Callback asynchronously to avoid netsted toggling. - Services.tm.currentThread.dispatch(() => { - aCallback.wifiTetheringEnabledChange(aMsg); - }, Ci.nsIThread.DISPATCH_NORMAL); - } - }, - - enableWifiTethering: function(aEnable, aConfig, aCallback) { - // Fill in config's required fields. - aConfig.ifname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface; - aConfig.internalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface; - aConfig.externalIfname = this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface; - - this._wifiTetheringRequestOngoing = true; - gNetworkService.setWifiTethering(aEnable, aConfig, (aError) => { - // Change the tethering state to WIFI if there is no error. - if (aEnable && !aError) { - this.state = Ci.nsITetheringService.TETHERING_STATE_WIFI; - } else { - // If wifi thethering is disable, or any error happens, - // then consider the following statements. - - // Check whether the state is USB now or not. If no then just change - // it to INACTIVE, if yes then just keep it. - // It means that don't let the disable or error of WIFI affect - // the original active state. - if (this.state != Ci.nsITetheringService.TETHERING_STATE_USB) { - this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE; - } - - // Disconnect dun on error or when wifi tethering is disabled. - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(false); - } - } - - if (this._manageOfflineStatus) { - Services.io.offline = !this.isAnyConnected() && - (this.state === - Ci.nsITetheringService.TETHERING_STATE_INACTIVE); - } - - let resetSettings = aError; - debug('gNetworkService.setWifiTethering finished'); - this.notifyError(resetSettings, aCallback, aError); - this._wifiTetheringRequestOngoing = false; - if (this._usbTetheringRequestCount > 0) { - debug('Perform pending USB tethering requests.'); - this.handleLastUsbTetheringRequest(); - } - }); - }, - - // Enable/disable WiFi tethering by sending commands to netd. - setWifiTethering: function(aEnable, aInterfaceName, aConfig, aCallback) { - debug("setWifiTethering: " + aEnable); - if (!aInterfaceName) { - this.notifyError(true, aCallback, "invalid network interface name"); - return; - } - - if (!aConfig) { - this.notifyError(true, aCallback, "invalid configuration"); - return; - } - - if (this._usbTetheringRequestCount > 0) { - // If there's still pending usb tethering request, save - // the request params and redo |setWifiTethering| on - // usb tethering task complete. - debug('USB tethering request is being processed. Queue this wifi tethering request.'); - this._pendingWifiTetheringRequestArgs = Array.prototype.slice.call(arguments); - debug('Pending args: ' + JSON.stringify(this._pendingWifiTetheringRequestArgs)); - return; - } - - // Re-check again, test cases set this property later. - this.tetheringSettings[SETTINGS_DUN_REQUIRED] = - libcutils.property_get("ro.tethering.dun_required") === "1"; - - if (!aEnable) { - this.enableWifiTethering(false, aConfig, aCallback); - return; - } - - this._tetheringInterface[TETHERING_TYPE_WIFI].internalInterface = - aInterfaceName; - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(true, (aNetworkInfo) => { - if (!aNetworkInfo) { - this.notifyError(true, aCallback, "Dun connection failed"); - return; - } - this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = - aNetworkInfo.name; - this.enableWifiTethering(true, aConfig, aCallback); - }); - return; - } - - let mobile = this.getNetworkInfo( - Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE, this._dataDefaultServiceId); - // Update the real interface name - if (mobile && mobile.name) { - this._tetheringInterface[TETHERING_TYPE_WIFI].externalInterface = mobile.name; - } - - this.enableWifiTethering(true, aConfig, aCallback); - }, - - // Enable/disable USB tethering by sending commands to netd. - setUSBTethering: function(aEnable, aTetheringInterface, aCallback) { - let params = this.getUSBTetheringParameters(aEnable, aTetheringInterface); - - if (params === null) { - gNetworkService.enableUsbRndis(false, function() { - this.usbTetheringResultReport(aEnable, "Invalid parameters"); - }); - return; - } - - gNetworkService.setUSBTethering(aEnable, params, aCallback); - }, - - getUsbInterface: function() { - // Find the rndis interface. - for (let i = 0; i < this.possibleInterface.length; i++) { - try { - let file = new FileUtils.File(KERNEL_NETWORK_ENTRY + "/" + - this.possibleInterface[i]); - if (file.exists()) { - return this.possibleInterface[i]; - } - } catch (e) { - debug("Not " + this.possibleInterface[i] + " interface."); - } - } - debug("Can't find rndis interface in possible lists."); - return DEFAULT_USB_INTERFACE_NAME; - }, - - enableUsbRndisResult: function(aSuccess, aEnable) { - if (aSuccess) { - // If enable is false, don't find usb interface cause it is already down, - // just use the internal interface in settings. - if (aEnable) { - this._tetheringInterface[TETHERING_TYPE_USB].internalInterface = - this.getUsbInterface(); - } - this.setUSBTethering(aEnable, - this._tetheringInterface[TETHERING_TYPE_USB], - this.usbTetheringResultReport.bind(this, aEnable)); - } else { - this.usbTetheringResultReport(aEnable, "enableUsbRndisResult failure"); - throw new Error("failed to set USB Function to adb"); - } - }, - - usbTetheringResultReport: function(aEnable, aError) { - this._usbTetheringRequestCount--; - - let settingsLock = gSettingsService.createLock(); - - debug('usbTetheringResultReport callback. enable: ' + aEnable + - ', error: ' + aError); - - // Disable tethering settings when fail to enable it. - if (aError) { - this.tetheringSettings[SETTINGS_USB_ENABLED] = false; - settingsLock.set("tethering.usb.enabled", false, null); - // Skip others request when we found an error. - this._usbTetheringRequestCount = 0; - this._usbTetheringAction = TETHERING_STATE_IDLE; - // If the thethering state is WIFI now, then just keep it, - // if not, just change the state to INACTIVE. - // It means that don't let the error of USB affect the original active state. - if (this.state != Ci.nsITetheringService.TETHERING_STATE_WIFI) { - this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE; - } - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(false); - } - } else { - if (aEnable) { - this._usbTetheringAction = TETHERING_STATE_ACTIVE; - this.state = Ci.nsITetheringService.TETHERING_STATE_USB; - } else { - this._usbTetheringAction = TETHERING_STATE_IDLE; - // If the state is now WIFI, don't let the disable of USB affect it. - if (this.state != Ci.nsITetheringService.TETHERING_STATE_WIFI) { - this.state = Ci.nsITetheringService.TETHERING_STATE_INACTIVE; - } - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED]) { - this.handleDunConnection(false); - } - } - - if (this._manageOfflineStatus) { - Services.io.offline = !this.isAnyConnected() && - (this.state === - Ci.nsITetheringService.TETHERING_STATE_INACTIVE); - } - - this.handleLastUsbTetheringRequest(); - } - }, - - onConnectionChangedReport: function(aSuccess, aExternalIfname) { - debug("onConnectionChangedReport result: success " + aSuccess); - - if (aSuccess) { - // Update the external interface. - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface = - aExternalIfname; - debug("Change the interface name to " + aExternalIfname); - } - }, - - onConnectionChanged: function(aNetworkInfo) { - if (aNetworkInfo.state != Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - debug("We are only interested in CONNECTED event"); - return; - } - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] && - aNetworkInfo.type === Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN) { - this.dunConnectTimer.cancel(); - debug("DUN data call connected, process callbacks."); - while (this._pendingTetheringRequests.length > 0) { - let callback = this._pendingTetheringRequests.shift(); - if (typeof callback === 'function') { - callback(aNetworkInfo); - } - } - return; - } - - if (!this.tetheringSettings[SETTINGS_USB_ENABLED]) { - debug("Usb tethering settings is not enabled"); - return; - } - - if (this.tetheringSettings[SETTINGS_DUN_REQUIRED] && - aNetworkInfo.type === Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN && - this._tetheringInterface[TETHERING_TYPE_USB].externalInterface === - aNetworkInfo.name) { - debug("Dun required and dun interface is the same"); - return; - } - - if (this._tetheringInterface[TETHERING_TYPE_USB].externalInterface === - gNetworkManager.activeNetworkInfo.name) { - debug("The active interface is the same"); - return; - } - - let previous = { - internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface, - externalIfname: this._tetheringInterface[TETHERING_TYPE_USB].externalInterface - }; - - let current = { - internalIfname: this._tetheringInterface[TETHERING_TYPE_USB].internalInterface, - externalIfname: aNetworkInfo.name - }; - - let callback = (() => { - // Update external network interface. - debug("Update upstream interface to " + aNetworkInfo.name); - gNetworkService.updateUpStream(previous, current, - this.onConnectionChangedReport.bind(this)); - }); - - if (this._usbTetheringAction === TETHERING_STATE_ONGOING) { - debug("Postpone the event and handle it when state is idle."); - this.wantConnectionEvent = callback; - return; - } - this.wantConnectionEvent = null; - - callback.call(this); - }, - - isAnyConnected: function() { - let allNetworkInfo = gNetworkManager.allNetworkInfo; - for (let networkId in allNetworkInfo) { - if (allNetworkInfo.hasOwnProperty(networkId) && - allNetworkInfo[networkId].state === Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - return true; - } - } - return false; - }, -}; - -this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TetheringService]); diff --git a/dom/system/gonk/TetheringService.manifest b/dom/system/gonk/TetheringService.manifest deleted file mode 100644 index b8f18dec1..000000000 --- a/dom/system/gonk/TetheringService.manifest +++ /dev/null @@ -1,4 +0,0 @@ -# TetheringService.js -component {527a4121-ee5a-4651-be9c-f46f59cf7c01} TetheringService.js -contract @mozilla.org/tethering/service;1 {527a4121-ee5a-4651-be9c-f46f59cf7c01} -category profile-after-change TetheringService @mozilla.org/tethering/service;1 diff --git a/dom/system/gonk/TimeZoneSettingObserver.cpp b/dom/system/gonk/TimeZoneSettingObserver.cpp deleted file mode 100644 index 512f79908..000000000 --- a/dom/system/gonk/TimeZoneSettingObserver.cpp +++ /dev/null @@ -1,239 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "base/message_loop.h" -#include "jsapi.h" -#include "mozilla/dom/ScriptSettings.h" -#include "mozilla/Attributes.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Hal.h" -#include "mozilla/Services.h" -#include "mozilla/StaticPtr.h" -#include "nsCOMPtr.h" -#include "nsDebug.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsISettingsService.h" -#include "nsJSUtils.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "TimeZoneSettingObserver.h" -#include "xpcpublic.h" -#include "nsContentUtils.h" -#include "nsPrintfCString.h" -#include "mozilla/dom/BindingUtils.h" -#include "mozilla/dom/SettingChangeNotificationBinding.h" - -#undef LOG -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Time Zone Setting" , ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, "Time Zone Setting" , ## args) - -#define TIME_TIMEZONE "time.timezone" -#define MOZSETTINGS_CHANGED "mozsettings-changed" - -using namespace mozilla; -using namespace mozilla::dom; - -namespace { - -class TimeZoneSettingObserver : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - TimeZoneSettingObserver(); - static nsresult SetTimeZone(const JS::Value &aValue, JSContext *aContext); - -protected: - virtual ~TimeZoneSettingObserver(); -}; - -class TimeZoneSettingCb final : public nsISettingsServiceCallback -{ -public: - NS_DECL_ISUPPORTS - - TimeZoneSettingCb() {} - - NS_IMETHOD Handle(const nsAString &aName, JS::Handle aResult) { - - JSContext *cx = nsContentUtils::GetCurrentJSContext(); - NS_ENSURE_TRUE(cx, NS_OK); - - // If we don't have time.timezone value in the settings, we need - // to initialize the settings based on the current system timezone - // to make settings consistent with system. This usually happens - // at the very first boot. After that, settings must have a value. - if (aResult.isNull()) { - // Get the current system time zone offset. Note that we need to - // convert the value to a UTC representation in the format of - // "UTC{+,-}hh:mm", so that the Gaia end can know how to interpret. - // E.g., -480 is "UTC+08:00"; 630 is "UTC-10:30". - int32_t timeZoneOffset = hal::GetTimezoneOffset(); - nsPrintfCString curTimeZone("UTC%+03d:%02d", - -timeZoneOffset / 60, - abs(timeZoneOffset) % 60); - - // Convert it to a JS string. - NS_ConvertUTF8toUTF16 utf16Str(curTimeZone); - - JS::Rooted jsStr(cx, JS_NewUCStringCopyN(cx, - utf16Str.get(), - utf16Str.Length())); - if (!jsStr) { - return NS_ERROR_OUT_OF_MEMORY; - } - - // Set the settings based on the current system timezone. - nsCOMPtr lock; - nsCOMPtr settingsService = - do_GetService("@mozilla.org/settingsService;1"); - if (!settingsService) { - ERR("Failed to get settingsLock service!"); - return NS_OK; - } - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - JS::Rooted value(cx, JS::StringValue(jsStr)); - lock->Set(TIME_TIMEZONE, value, nullptr, nullptr); - return NS_OK; - } - - // Set the system timezone based on the current settings. - if (aResult.isString()) { - return TimeZoneSettingObserver::SetTimeZone(aResult, cx); - } - - return NS_OK; - } - - NS_IMETHOD HandleError(const nsAString &aName) { - ERR("TimeZoneSettingCb::HandleError: %s\n", NS_LossyConvertUTF16toASCII(aName).get()); - return NS_OK; - } - -protected: - ~TimeZoneSettingCb() {} -}; - -NS_IMPL_ISUPPORTS(TimeZoneSettingCb, nsISettingsServiceCallback) - -TimeZoneSettingObserver::TimeZoneSettingObserver() -{ - // Setup an observer to watch changes to the setting. - nsCOMPtr observerService = services::GetObserverService(); - if (!observerService) { - ERR("GetObserverService failed"); - return; - } - nsresult rv; - rv = observerService->AddObserver(this, MOZSETTINGS_CHANGED, false); - if (NS_FAILED(rv)) { - ERR("AddObserver failed"); - return; - } - - // Read the 'time.timezone' setting in order to start with a known - // value at boot time. The handle() will be called after reading. - nsCOMPtr lock; - nsCOMPtr settingsService = - do_GetService("@mozilla.org/settingsService;1"); - if (!settingsService) { - ERR("Failed to get settingsLock service!"); - return; - } - settingsService->CreateLock(nullptr, getter_AddRefs(lock)); - nsCOMPtr callback = new TimeZoneSettingCb(); - lock->Get(TIME_TIMEZONE, callback); -} - -nsresult TimeZoneSettingObserver::SetTimeZone(const JS::Value &aValue, JSContext *aContext) -{ - // Convert the JS value to a nsCString type. - // The value should be a JS string like "America/Chicago" or "UTC-05:00". - nsAutoJSString valueStr; - if (!valueStr.init(aContext, aValue.toString())) { - ERR("Failed to convert JS value to nsCString"); - return NS_ERROR_FAILURE; - } - NS_ConvertUTF16toUTF8 newTimezone(valueStr); - - // Hal expects opposite sign from general notations, - // so we need to flip it. - if (newTimezone.Find(NS_LITERAL_CSTRING("UTC+")) == 0) { - if (!newTimezone.SetCharAt('-', 3)) { - return NS_ERROR_FAILURE; - } - } else if (newTimezone.Find(NS_LITERAL_CSTRING("UTC-")) == 0) { - if (!newTimezone.SetCharAt('+', 3)) { - return NS_ERROR_FAILURE; - } - } - - // Set the timezone only when the system timezone is not identical. - nsCString curTimezone = hal::GetTimezone(); - if (!curTimezone.Equals(newTimezone)) { - hal::SetTimezone(newTimezone); - } - - return NS_OK; -} - -TimeZoneSettingObserver::~TimeZoneSettingObserver() -{ - nsCOMPtr observerService = services::GetObserverService(); - if (observerService) { - observerService->RemoveObserver(this, MOZSETTINGS_CHANGED); - } -} - -NS_IMPL_ISUPPORTS(TimeZoneSettingObserver, nsIObserver) - -NS_IMETHODIMP -TimeZoneSettingObserver::Observe(nsISupports *aSubject, - const char *aTopic, - const char16_t *aData) -{ - if (strcmp(aTopic, MOZSETTINGS_CHANGED) != 0) { - return NS_OK; - } - - // Note that this function gets called for any and all settings changes, - // so we need to carefully check if we have the one we're interested in. - // - // The string that we're interested in will be a JSON string that looks like: - // {"key":"time.timezone","value":"America/Chicago"} or - // {"key":"time.timezone","value":"UTC-05:00"} - - AutoSafeJSContext cx; - RootedDictionary setting(cx); - if (!WrappedJSToDictionary(cx, aSubject, setting)) { - return NS_OK; - } - if (!setting.mKey.EqualsASCII(TIME_TIMEZONE)) { - return NS_OK; - } - if (!setting.mValue.isString()) { - return NS_OK; - } - - // Set the system timezone. - return SetTimeZone(setting.mValue, cx); -} - -} // namespace - -static mozilla::StaticRefPtr sTimeZoneSettingObserver; -namespace mozilla { -namespace system { -void -InitializeTimeZoneSettingObserver() -{ - sTimeZoneSettingObserver = new TimeZoneSettingObserver(); - ClearOnShutdown(&sTimeZoneSettingObserver); -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/TimeZoneSettingObserver.h b/dom/system/gonk/TimeZoneSettingObserver.h deleted file mode 100644 index 08b7cebb3..000000000 --- a/dom/system/gonk/TimeZoneSettingObserver.h +++ /dev/null @@ -1,20 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_timesetting_h__ -#define mozilla_system_timesetting_h__ - -namespace mozilla { -namespace system { - -// Initialize TimeZoneSettingObserver which observes the time zone change -// event from settings service. When receiving the event, it modifies the -// system time zone. -void InitializeTimeZoneSettingObserver(); - -} // namespace system -} // namespace mozilla - -#endif // mozilla_system_timesetting_h__ - diff --git a/dom/system/gonk/Volume.cpp b/dom/system/gonk/Volume.cpp deleted file mode 100644 index f90c7b693..000000000 --- a/dom/system/gonk/Volume.cpp +++ /dev/null @@ -1,596 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManager.h" -#include "VolumeManagerLog.h" -#include "nsIVolume.h" -#include "nsXULAppAPI.h" - -#include - -namespace mozilla { -namespace system { - -#if DEBUG_VOLUME_OBSERVER -void -VolumeObserverList::Broadcast(Volume* const& aVolume) -{ - uint32_t size = mObservers.Length(); - for (uint32_t i = 0; i < size; ++i) { - LOG("VolumeObserverList::Broadcast to [%u] %p volume '%s'", - i, mObservers[i], aVolume->NameStr()); - mObservers[i]->Notify(aVolume); - } -} -#endif - -VolumeObserverList Volume::sEventObserverList; - -// We have a feature where volumes can be locked when mounted. This -// is used to prevent a volume from being shared with the PC while -// it is actively being used (say for storing an update image) -// -// We use WakeLocks (a poor choice of name, but it does what we want) -// from the PowerManagerService to determine when we're locked. -// In particular we'll create a wakelock called volume-NAME-GENERATION -// (where NAME is the volume name, and GENERATION is its generation -// number), and if this wakelock is locked, then we'll prevent a volume -// from being shared. -// -// Implementation Details: -// -// Since the AutoMounter can only control when something gets mounted -// and not when it gets unmounted (for example: a user pulls the SDCard) -// and because Volume and nsVolume data structures are maintained on -// separate threads, we have the potential for some race conditions. -// We eliminate the race conditions by introducing the concept of a -// generation number. Every time a volume transitions to the Mounted -// state, it gets assigned a new generation number. Whenever the state -// of a Volume changes, we send the updated state and current generation -// number to the main thread where it gets updated in the nsVolume. -// -// Since WakeLocks can only be queried from the main-thread, the -// nsVolumeService looks for WakeLock status changes, and forwards -// the results to the IOThread. -// -// If the Volume (IOThread) receives a volume update where the generation -// number mismatches, then the update is simply ignored. -// -// When a Volume (IOThread) initially becomes mounted, we assume it to -// be locked until we get our first update from nsVolume (MainThread). -static int32_t sMountGeneration = 0; - -static uint32_t sNextId = 1; - -// We don't get media inserted/removed events at startup. So we -// assume it's present, and we'll be told that it's missing. -Volume::Volume(const nsCSubstring& aName) - : mMediaPresent(true), - mState(nsIVolume::STATE_INIT), - mName(aName), - mMountGeneration(-1), - mMountLocked(true), // Needs to agree with nsVolume::nsVolume - mSharingEnabled(false), - mFormatRequested(false), - mMountRequested(false), - mUnmountRequested(false), - mCanBeShared(true), - mIsSharing(false), - mIsFormatting(false), - mIsUnmounting(false), - mIsRemovable(false), - mIsHotSwappable(false), - mId(sNextId++) -{ - DBG("Volume %s: created", NameStr()); -} - -void -Volume::Dump(const char* aLabel) const -{ - LOG("%s: Volume: %s (%d) is %s and %s @ %s gen %d locked %d", - aLabel, - NameStr(), - Id(), - StateStr(), - MediaPresent() ? "inserted" : "missing", - MountPoint().get(), - MountGeneration(), - (int)IsMountLocked()); - LOG("%s: Sharing %s Mounting %s Formating %s Unmounting %s", - aLabel, - CanBeShared() ? (IsSharingEnabled() ? (IsSharing() ? "en-y" : "en-n") - : "dis") - : "x", - IsMountRequested() ? "req" : "n", - IsFormatRequested() ? (IsFormatting() ? "req-y" : "req-n") - : (IsFormatting() ? "y" : "n"), - IsUnmountRequested() ? (IsUnmounting() ? "req-y" : "req-n") - : (IsUnmounting() ? "y" : "n")); -} - -void -Volume::ResolveAndSetMountPoint(const nsCSubstring& aMountPoint) -{ - nsCString mountPoint(aMountPoint); - char realPathBuf[PATH_MAX]; - - // Call realpath so that we wind up with a path which is compatible with - // functions like nsVolumeService::GetVolumeByPath. - - if (realpath(mountPoint.get(), realPathBuf) < 0) { - // The path we were handed doesn't exist. Warn about it, but use it - // anyways assuming that the user knows what they're doing. - - ERR("ResolveAndSetMountPoint: realpath on '%s' failed: %d", - mountPoint.get(), errno); - mMountPoint = mountPoint; - } else { - mMountPoint = realPathBuf; - } - DBG("Volume %s: Setting mountpoint to '%s'", NameStr(), mMountPoint.get()); -} - -void Volume::SetFakeVolume(const nsACString& aMountPoint) -{ - this->mMountLocked = false; - this->mCanBeShared = false; - ResolveAndSetMountPoint(aMountPoint); - SetState(nsIVolume::STATE_MOUNTED); -} - -void -Volume::SetIsSharing(bool aIsSharing) -{ - if (aIsSharing == mIsSharing) { - return; - } - mIsSharing = aIsSharing; - LOG("Volume %s: IsSharing set to %d state %s", - NameStr(), (int)mIsSharing, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsFormatting(bool aIsFormatting) -{ - if (aIsFormatting == mIsFormatting) { - return; - } - mIsFormatting = aIsFormatting; - LOG("Volume %s: IsFormatting set to %d state %s", - NameStr(), (int)mIsFormatting, StateStr(mState)); - if (mIsFormatting) { - sEventObserverList.Broadcast(this); - } -} - -void -Volume::SetIsUnmounting(bool aIsUnmounting) -{ - if (aIsUnmounting == mIsUnmounting) { - return; - } - mIsUnmounting = aIsUnmounting; - LOG("Volume %s: IsUnmounting set to %d state %s", - NameStr(), (int)mIsUnmounting, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsRemovable(bool aIsRemovable) -{ - if (aIsRemovable == mIsRemovable) { - return; - } - mIsRemovable = aIsRemovable; - if (!mIsRemovable) { - mIsHotSwappable = false; - } - LOG("Volume %s: IsRemovable set to %d state %s", - NameStr(), (int)mIsRemovable, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetIsHotSwappable(bool aIsHotSwappable) -{ - if (aIsHotSwappable == mIsHotSwappable) { - return; - } - mIsHotSwappable = aIsHotSwappable; - if (mIsHotSwappable) { - mIsRemovable = true; - } - LOG("Volume %s: IsHotSwappable set to %d state %s", - NameStr(), (int)mIsHotSwappable, StateStr(mState)); - sEventObserverList.Broadcast(this); -} - -bool -Volume::BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue) -{ - if (aConfigValue.EqualsLiteral("1") || - aConfigValue.LowerCaseEqualsLiteral("true")) { - aBoolValue = true; - return true; - } - if (aConfigValue.EqualsLiteral("0") || - aConfigValue.LowerCaseEqualsLiteral("false")) { - aBoolValue = false; - return true; - } - return false; -} - -void -Volume::SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue) -{ - if (aConfigName.LowerCaseEqualsLiteral("removable")) { - bool value = false; - if (BoolConfigValue(aConfigValue, value)) { - SetIsRemovable(value); - } else { - ERR("Volume %s: invalid value '%s' for configuration '%s'", - NameStr(), aConfigValue.get(), aConfigName.get()); - } - return; - } - if (aConfigName.LowerCaseEqualsLiteral("hotswappable")) { - bool value = false; - if (BoolConfigValue(aConfigValue, value)) { - SetIsHotSwappable(value); - } else { - ERR("Volume %s: invalid value '%s' for configuration '%s'", - NameStr(), aConfigValue.get(), aConfigName.get()); - } - return; - } - ERR("Volume %s: invalid config '%s'", NameStr(), aConfigName.get()); -} - -void -Volume::SetMediaPresent(bool aMediaPresent) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // mMediaPresent is slightly redunant to the state, however - // when media is removed (while Idle), we get the following: - // 631 Volume sdcard /mnt/sdcard disk removed (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media) - // - // And on media insertion, we get: - // 630 Volume sdcard /mnt/sdcard disk inserted (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 0 (No-Media) to 2 (Pending) - // 605 Volume sdcard /mnt/sdcard state changed from 2 (Pending) to 1 (Idle-Unmounted) - // - // On media removal while the media is mounted: - // 632 Volume sdcard /mnt/sdcard bad removal (179:1) - // 605 Volume sdcard /mnt/sdcard state changed from 4 (Mounted) to 5 (Unmounting) - // 605 Volume sdcard /mnt/sdcard state changed from 5 (Unmounting) to 1 (Idle-Unmounted) - // 631 Volume sdcard /mnt/sdcard disk removed (179:0) - // 605 Volume sdcard /mnt/sdcard state changed from 1 (Idle-Unmounted) to 0 (No-Media) - // - // When sharing with a PC, it goes Mounted -> Idle -> Shared - // When unsharing with a PC, it goes Shared -> Idle -> Mounted - // - // The AutoMounter needs to know whether the media is present or not when - // processing the Idle state. - - if (mMediaPresent == aMediaPresent) { - return; - } - - LOG("Volume: %s media %s", NameStr(), aMediaPresent ? "inserted" : "removed"); - mMediaPresent = aMediaPresent; - sEventObserverList.Broadcast(this); -} - -void -Volume::SetSharingEnabled(bool aSharingEnabled) -{ - mSharingEnabled = aSharingEnabled; - - LOG("SetSharingMode for volume %s to %d canBeShared = %d", - NameStr(), (int)mSharingEnabled, (int)mCanBeShared); - sEventObserverList.Broadcast(this); -} - -void -Volume::SetFormatRequested(bool aFormatRequested) -{ - mFormatRequested = aFormatRequested; - - LOG("SetFormatRequested for volume %s to %d CanBeFormatted = %d", - NameStr(), (int)mFormatRequested, (int)CanBeFormatted()); -} - -void -Volume::SetMountRequested(bool aMountRequested) -{ - mMountRequested = aMountRequested; - - LOG("SetMountRequested for volume %s to %d CanBeMounted = %d", - NameStr(), (int)mMountRequested, (int)CanBeMounted()); -} - -void -Volume::SetUnmountRequested(bool aUnmountRequested) -{ - mUnmountRequested = aUnmountRequested; - - LOG("SetUnmountRequested for volume %s to %d CanBeMounted = %d", - NameStr(), (int)mUnmountRequested, (int)CanBeMounted()); -} - -void -Volume::SetState(Volume::STATE aNewState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (aNewState == mState) { - return; - } - if (aNewState == nsIVolume::STATE_MOUNTED) { - mMountGeneration = ++sMountGeneration; - LOG("Volume %s (%u): changing state from %s to %s @ '%s' (%d observers) " - "mountGeneration = %d, locked = %d", - NameStr(), mId, StateStr(mState), - StateStr(aNewState), mMountPoint.get(), sEventObserverList.Length(), - mMountGeneration, (int)mMountLocked); - } else { - LOG("Volume %s (%u): changing state from %s to %s (%d observers)", - NameStr(), mId, StateStr(mState), - StateStr(aNewState), sEventObserverList.Length()); - } - - switch (aNewState) { - case nsIVolume::STATE_NOMEDIA: - // Cover the startup case where we don't get insertion/removal events - mMediaPresent = false; - mIsSharing = false; - mUnmountRequested = false; - mMountRequested = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_MOUNTED: - case nsIVolume::STATE_MOUNT_FAIL: - mMountRequested = false; - mIsFormatting = false; - mIsSharing = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_FORMATTING: - mFormatRequested = false; - mIsFormatting = true; - mIsSharing = false; - mIsUnmounting = false; - break; - - case nsIVolume::STATE_SHARED: - case nsIVolume::STATE_SHAREDMNT: - // Covers startup cases. Normally, mIsSharing would be set to true - // when we issue the command to initiate the sharing process, but - // it's conceivable that a volume could already be in a shared state - // when b2g starts. - mIsSharing = true; - mIsUnmounting = false; - mIsFormatting = false; - break; - - case nsIVolume::STATE_UNMOUNTING: - mIsUnmounting = true; - mIsFormatting = false; - mIsSharing = false; - break; - - case nsIVolume::STATE_IDLE: // Fall through - case nsIVolume::STATE_CHECKMNT: // Fall through - default: - break; - } - mState = aNewState; - sEventObserverList.Broadcast(this); -} - -void -Volume::SetMountPoint(const nsCSubstring& aMountPoint) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (mMountPoint.Equals(aMountPoint)) { - return; - } - ResolveAndSetMountPoint(aMountPoint); -} - -void -Volume::StartMount(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "mount", "", aCallback)); -} - -void -Volume::StartUnmount(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "unmount", "force", aCallback)); -} - -void -Volume::StartFormat(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "format", "", aCallback)); -} - -void -Volume::StartShare(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "share", "ums", aCallback)); -} - -void -Volume::StartUnshare(VolumeResponseCallback* aCallback) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - StartCommand(new VolumeActionCommand(this, "unshare", "ums", aCallback)); -} - -void -Volume::StartCommand(VolumeCommand* aCommand) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - VolumeManager::PostCommand(aCommand); -} - -//static -void -Volume::RegisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sEventObserverList.AddObserver(aObserver); - - DBG("Added Volume Observer '%s' @%p, length = %u", - aName, aObserver, sEventObserverList.Length()); - - // Send an initial event to the observer (for each volume) - size_t numVolumes = VolumeManager::NumVolumes(); - for (size_t volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = VolumeManager::GetVolume(volIndex); - aObserver->Notify(vol); - } -} - -//static -void -Volume::UnregisterVolumeObserver(Volume::EventObserver* aObserver, const char* aName) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sEventObserverList.RemoveObserver(aObserver); - - DBG("Removed Volume Observer '%s' @%p, length = %u", - aName, aObserver, sEventObserverList.Length()); -} - -//static -void -Volume::UpdateMountLock(const nsACString& aVolumeName, - const int32_t& aMountGeneration, - const bool& aMountLocked) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - RefPtr vol = VolumeManager::FindVolumeByName(aVolumeName); - if (!vol || (vol->mMountGeneration != aMountGeneration)) { - return; - } - if (vol->mMountLocked != aMountLocked) { - vol->mMountLocked = aMountLocked; - DBG("Volume::UpdateMountLock for '%s' to %d\n", vol->NameStr(), (int)aMountLocked); - sEventObserverList.Broadcast(vol); - } -} - -void -Volume::HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // The volume name will have already been parsed, and the tokenizer will point - // to the token after the volume name - switch (aResponseCode) { - case ::ResponseCode::VolumeListResult: { - // Each line will look something like: - // - // sdcard /mnt/sdcard 1 - // - nsDependentCSubstring mntPoint(aTokenizer.nextToken()); - SetMountPoint(mntPoint); - nsresult errCode; - nsCString state(aTokenizer.nextToken()); - if (state.EqualsLiteral("X")) { - // Special state for creating fake volumes which can't be shared. - mCanBeShared = false; - SetState(nsIVolume::STATE_MOUNTED); - } else { - SetState((STATE)state.ToInteger(&errCode)); - } - break; - } - - case ::ResponseCode::VolumeStateChange: { - // Format of the line looks something like: - // - // Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) - // - // So we parse out the state after the string " to " - while (aTokenizer.hasMoreTokens()) { - nsAutoCString token(aTokenizer.nextToken()); - if (token.EqualsLiteral("to")) { - nsresult errCode; - token = aTokenizer.nextToken(); - STATE newState = (STATE)(token.ToInteger(&errCode)); - if (newState == nsIVolume::STATE_MOUNTED) { - // We set the state to STATE_CHECKMNT here, and the once the - // AutoMounter detects that the volume is actually accessible - // then the AutoMounter will set the volume as STATE_MOUNTED. - SetState(nsIVolume::STATE_CHECKMNT); - } else { - if (State() == nsIVolume::STATE_CHECKING && newState == nsIVolume::STATE_IDLE) { - LOG("Mount of volume '%s' failed", NameStr()); - SetState(nsIVolume::STATE_MOUNT_FAIL); - } else { - SetState(newState); - } - } - break; - } - } - break; - } - - case ::ResponseCode::VolumeDiskInserted: - SetMediaPresent(true); - break; - - case ::ResponseCode::VolumeDiskRemoved: // fall-thru - case ::ResponseCode::VolumeBadRemoval: - SetMediaPresent(false); - break; - - default: - LOG("Volume: %s unrecognized reponse code (ignored)", NameStr()); - break; - } -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/Volume.h b/dom/system/gonk/Volume.h deleted file mode 100644 index 821292a9a..000000000 --- a/dom/system/gonk/Volume.h +++ /dev/null @@ -1,157 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volume_h__ -#define mozilla_system_volume_h__ - -#include "VolumeCommand.h" -#include "nsIVolume.h" -#include "nsString.h" -#include "mozilla/Observer.h" -#include "nsISupportsImpl.h" -#include "nsWhitespaceTokenizer.h" - -namespace mozilla { -namespace system { - -/*************************************************************************** -* -* There is an instance of the Volume class for each volume reported -* from vold. -* -* Each volume originates from the /system/etv/vold.fstab file. -* -***************************************************************************/ - -class Volume; - -#define DEBUG_VOLUME_OBSERVER 0 - -#if DEBUG_VOLUME_OBSERVER -class VolumeObserverList : public mozilla::ObserverList -{ -public: - void Broadcast(Volume* const& aVolume); -}; -#else -typedef mozilla::ObserverList VolumeObserverList; -#endif - -class Volume final -{ -public: - NS_INLINE_DECL_REFCOUNTING(Volume) - - Volume(const nsCSubstring& aVolumeName); - - typedef long STATE; // States are now defined in nsIVolume.idl - - static const char* StateStr(STATE aState) { return NS_VolumeStateStr(aState); } - const char* StateStr() const { return StateStr(mState); } - STATE State() const { return mState; } - - const nsCString& Name() const { return mName; } - const char* NameStr() const { return mName.get(); } - - void Dump(const char* aLabel) const; - - // The mount point is the name of the directory where the volume is mounted. - // (i.e. path that leads to the files stored on the volume). - const nsCString& MountPoint() const { return mMountPoint; } - - uint32_t Id() const { return mId; } - - int32_t MountGeneration() const { return mMountGeneration; } - bool IsMountLocked() const { return mMountLocked; } - bool MediaPresent() const { return mMediaPresent; } - bool CanBeShared() const { return mCanBeShared; } - bool CanBeFormatted() const { return CanBeShared(); } - bool CanBeMounted() const { return CanBeShared(); } - bool IsSharingEnabled() const { return mCanBeShared && mSharingEnabled; } - bool IsFormatRequested() const { return CanBeFormatted() && mFormatRequested; } - bool IsMountRequested() const { return CanBeMounted() && mMountRequested; } - bool IsUnmountRequested() const { return CanBeMounted() && mUnmountRequested; } - bool IsSharing() const { return mIsSharing; } - bool IsFormatting() const { return mIsFormatting; } - bool IsUnmounting() const { return mIsUnmounting; } - bool IsRemovable() const { return mIsRemovable; } - bool IsHotSwappable() const { return mIsHotSwappable; } - - void SetFakeVolume(const nsACString& aMountPoint); - - void SetSharingEnabled(bool aSharingEnabled); - void SetFormatRequested(bool aFormatRequested); - void SetMountRequested(bool aMountRequested); - void SetUnmountRequested(bool aUnmountRequested); - - typedef mozilla::Observer EventObserver; - - // NOTE: that observers must live in the IOThread. - static void RegisterVolumeObserver(EventObserver* aObserver, const char* aName); - static void UnregisterVolumeObserver(EventObserver* aObserver, const char* aName); - -protected: - ~Volume() {} - -private: - friend class AutoMounter; // Calls StartXxx - friend class nsVolume; // Calls UpdateMountLock - friend class VolumeManager; // Calls HandleVoldResponse - friend class VolumeListCallback; // Calls SetMountPoint, SetState - - // The StartXxx functions will queue up a command to the VolumeManager. - // You can queue up as many commands as you like, and aCallback will - // be called as each one completes. - void StartMount(VolumeResponseCallback* aCallback); - void StartUnmount(VolumeResponseCallback* aCallback); - void StartFormat(VolumeResponseCallback* aCallback); - void StartShare(VolumeResponseCallback* aCallback); - void StartUnshare(VolumeResponseCallback* aCallback); - - void SetIsSharing(bool aIsSharing); - void SetIsFormatting(bool aIsFormatting); - void SetIsUnmounting(bool aIsUnmounting); - void SetIsRemovable(bool aIsRemovable); - void SetIsHotSwappable(bool aIsHotSwappable); - void SetState(STATE aNewState); - void SetMediaPresent(bool aMediaPresent); - void SetMountPoint(const nsCSubstring& aMountPoint); - void StartCommand(VolumeCommand* aCommand); - - void ResolveAndSetMountPoint(const nsCSubstring& aMountPoint); - - bool BoolConfigValue(const nsCString& aConfigValue, bool& aBoolValue); - void SetConfig(const nsCString& aConfigName, const nsCString& aConfigValue); - - void HandleVoldResponse(int aResponseCode, nsCWhitespaceTokenizer& aTokenizer); - - static void UpdateMountLock(const nsACString& aVolumeName, - const int32_t& aMountGeneration, - const bool& aMountLocked); - - bool mMediaPresent; - STATE mState; - const nsCString mName; - nsCString mMountPoint; - int32_t mMountGeneration; - bool mMountLocked; - bool mSharingEnabled; - bool mFormatRequested; - bool mMountRequested; - bool mUnmountRequested; - bool mCanBeShared; - bool mIsSharing; - bool mIsFormatting; - bool mIsUnmounting; - bool mIsRemovable; - bool mIsHotSwappable; - uint32_t mId; // Unique ID (used by MTP) - - static VolumeObserverList sEventObserverList; -}; - -} // system -} // mozilla - -#endif // mozilla_system_volumemanager_h__ diff --git a/dom/system/gonk/VolumeCommand.cpp b/dom/system/gonk/VolumeCommand.cpp deleted file mode 100644 index 8095956a7..000000000 --- a/dom/system/gonk/VolumeCommand.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsString.h" -#include "nsWhitespaceTokenizer.h" - -#include "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManager.h" -#include "VolumeManagerLog.h" - -namespace mozilla { -namespace system { - -/*************************************************************************** -* -* The VolumeActionCommand class is used to send commands which apply -* to a particular volume. -* -* The following commands would fit into this category: -* -* volume mount -* volume unmount [force] -* volume format -* volume share -* volume unshare -* volume shared -* -* A typical response looks like: -* -* # vdc volume unshare sdcard ums -* 605 Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) -* 200 volume operation succeeded -* -* Note that the 600 series of responses are considered unsolicited and -* are dealt with directly by the VolumeManager. This command will only -* see the terminating response code (200 in the example above). -* -***************************************************************************/ - -VolumeActionCommand::VolumeActionCommand(Volume* aVolume, - const char* aAction, - const char* aExtraArgs, - VolumeResponseCallback* aCallback) - : VolumeCommand(aCallback), - mVolume(aVolume) -{ - nsAutoCString cmd; - - cmd = "volume "; - cmd += aAction; - cmd += " "; - cmd += aVolume->Name().get(); - - // vold doesn't like trailing white space, so only add it if we really need to. - if (aExtraArgs && (*aExtraArgs != '\0')) { - cmd += " "; - cmd += aExtraArgs; - } - SetCmd(cmd); -} - -/*************************************************************************** -* -* The VolumeListCommand class is used to send the "volume list" command to -* vold. -* -* A typical response looks like: -* -* # vdc volume list -* 110 sdcard /mnt/sdcard 4 -* 110 sdcard1 /mnt/sdcard/external_sd 4 -* 200 Volumes listed. -* -***************************************************************************/ - -VolumeListCommand::VolumeListCommand(VolumeResponseCallback* aCallback) - : VolumeCommand(NS_LITERAL_CSTRING("volume list"), aCallback) -{ -} - -} // system -} // mozilla - diff --git a/dom/system/gonk/VolumeCommand.h b/dom/system/gonk/VolumeCommand.h deleted file mode 100644 index 022965b5e..000000000 --- a/dom/system/gonk/VolumeCommand.h +++ /dev/null @@ -1,204 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumecommand_h__ -#define mozilla_system_volumecommand_h__ - -#include "nsString.h" -#include "nsISupportsImpl.h" -#include "mozilla/RefPtr.h" -#include -#include - -namespace mozilla { -namespace system { - -class Volume; -class VolumeCommand; - -/*************************************************************************** -* -* The VolumeResponseCallback class is an abstract base class. The ResponseReceived -* method will be called for each response received. -* -* Depending on the command, there may be multiple responses for the -* command. Done() will return true if this is the last response. -* -* The responses from vold are all of the form: -* -* -* -* Valid Response codes can be found in the vold/ResponseCode.h header. -* -***************************************************************************/ - -class VolumeResponseCallback -{ -protected: - virtual ~VolumeResponseCallback() {} - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeResponseCallback) - VolumeResponseCallback() - : mResponseCode(0), mPending(false) {} - - bool Done() const - { - // Response codes from the 200, 400, and 500 series all indicated that - // the command has completed. - - return (mResponseCode >= ::ResponseCode::CommandOkay) - && (mResponseCode < ::ResponseCode::UnsolicitedInformational); - } - - bool WasSuccessful() const - { - return mResponseCode == ::ResponseCode::CommandOkay; - } - - bool IsPending() const { return mPending; } - int ResponseCode() const { return mResponseCode; } - const nsCString &ResponseStr() const { return mResponseStr; } - -protected: - virtual void ResponseReceived(const VolumeCommand* aCommand) = 0; - -private: - friend class VolumeCommand; // Calls HandleResponse and SetPending - - void HandleResponse(const VolumeCommand* aCommand, - int aResponseCode, - nsACString& aResponseStr) - { - mResponseCode = aResponseCode; -#if ANDROID_VERSION >= 17 - // There's a sequence number here that we don't care about - // We expect it to be 0. See VolumeCommand::SetCmd - mResponseStr = Substring(aResponseStr, 2); -#else - mResponseStr = aResponseStr; -#endif - if (mResponseCode >= ::ResponseCode::CommandOkay) { - // This is a final response. - mPending = false; - } - ResponseReceived(aCommand); - } - - void SetPending(bool aPending) { mPending = aPending; } - - int mResponseCode; // The response code parsed from vold - nsCString mResponseStr; // The rest of the line. - bool mPending; // Waiting for response? -}; - -/*************************************************************************** -* -* The VolumeCommand class is an abstract base class used to encapsulate -* volume commands send to vold. -* -* See VolumeManager.h for a list of the volume commands. -* -* Commands sent to vold need an explicit null character so we add one -* to the command to ensure that it's included in the length. -* -* All of these commands are asynchronous in nature, and the -* ResponseReceived callback will be called when a response is available. -* -***************************************************************************/ - -class VolumeCommand -{ -protected: - virtual ~VolumeCommand() {} - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeCommand) - - VolumeCommand(VolumeResponseCallback* aCallback) - : mBytesConsumed(0), - mCallback(aCallback) - { - SetCmd(NS_LITERAL_CSTRING("")); - } - - VolumeCommand(const nsACString& aCommand, VolumeResponseCallback* aCallback) - : mBytesConsumed(0), - mCallback(aCallback) - { - SetCmd(aCommand); - } - - void SetCmd(const nsACString& aCommand) - { - mCmd.Truncate(); -#if ANDROID_VERSION >= 17 - // JB requires a sequence number at the beginning of messages. - // It doesn't matter what we use, so we use 0. - mCmd = "0 "; -#endif - mCmd.Append(aCommand); - // Add a null character. We want this to be included in the length since - // vold uses it to determine the end of the command. - mCmd.Append('\0'); - } - - const char* CmdStr() const { return mCmd.get(); } - const char* Data() const { return mCmd.Data() + mBytesConsumed; } - size_t BytesConsumed() const { return mBytesConsumed; } - - size_t BytesRemaining() const - { - return mCmd.Length() - std::min(mCmd.Length(), mBytesConsumed); - } - - void ConsumeBytes(size_t aNumBytes) - { - mBytesConsumed += std::min(BytesRemaining(), aNumBytes); - } - -private: - friend class VolumeManager; // Calls SetPending & HandleResponse - - void SetPending(bool aPending) - { - if (mCallback) { - mCallback->SetPending(aPending); - } - } - - void HandleResponse(int aResponseCode, nsACString& aResponseStr) - { - if (mCallback) { - mCallback->HandleResponse(this, aResponseCode, aResponseStr); - } - } - - nsCString mCmd; // Command being sent - size_t mBytesConsumed; // How many bytes have been sent - - // Called when a response to the command is received. - RefPtr mCallback; -}; - -class VolumeActionCommand : public VolumeCommand -{ -public: - VolumeActionCommand(Volume* aVolume, const char* aAction, - const char* aExtraArgs, VolumeResponseCallback* aCallback); - -private: - RefPtr mVolume; -}; - -class VolumeListCommand : public VolumeCommand -{ -public: - VolumeListCommand(VolumeResponseCallback* aCallback); -}; - -} // system -} // mozilla - -#endif // mozilla_system_volumecommand_h__ diff --git a/dom/system/gonk/VolumeManager.cpp b/dom/system/gonk/VolumeManager.cpp deleted file mode 100644 index ddfa7af09..000000000 --- a/dom/system/gonk/VolumeManager.cpp +++ /dev/null @@ -1,591 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "VolumeManager.h" - -#include "Volume.h" -#include "VolumeCommand.h" -#include "VolumeManagerLog.h" -#include "VolumeServiceTest.h" - -#include "nsWhitespaceTokenizer.h" -#include "nsXULAppAPI.h" - -#include "base/message_loop.h" -#include "base/task.h" -#include "mozilla/Scoped.h" -#include "mozilla/StaticPtr.h" - -#include -#include -#include -#include - -namespace mozilla { -namespace system { - -static StaticRefPtr sVolumeManager; - -VolumeManager::STATE VolumeManager::mState = VolumeManager::UNINITIALIZED; -VolumeManager::StateObserverList VolumeManager::mStateObserverList; - -/***************************************************************************/ - -VolumeManager::VolumeManager() - : LineWatcher('\0', kRcvBufSize), - mSocket(-1), - mCommandPending(false) -{ - DBG("VolumeManager constructor called"); -} - -VolumeManager::~VolumeManager() -{ -} - -//static -void -VolumeManager::Dump(const char* aLabel) -{ - if (!sVolumeManager) { - LOG("%s: sVolumeManager == null", aLabel); - return; - } - - VolumeArray::size_type numVolumes = NumVolumes(); - VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = GetVolume(volIndex); - vol->Dump(aLabel); - } -} - -//static -size_t -VolumeManager::NumVolumes() -{ - if (!sVolumeManager) { - return 0; - } - return sVolumeManager->mVolumeArray.Length(); -} - -//static -already_AddRefed -VolumeManager::GetVolume(size_t aIndex) -{ - MOZ_ASSERT(aIndex < NumVolumes()); - RefPtr vol = sVolumeManager->mVolumeArray[aIndex]; - return vol.forget(); -} - -//static -VolumeManager::STATE -VolumeManager::State() -{ - return mState; -} - -//static -const char * -VolumeManager::StateStr(VolumeManager::STATE aState) -{ - switch (aState) { - case UNINITIALIZED: return "Uninitialized"; - case STARTING: return "Starting"; - case VOLUMES_READY: return "Volumes Ready"; - } - return "???"; -} - - -//static -void -VolumeManager::SetState(STATE aNewState) -{ - if (mState != aNewState) { - LOG("changing state from '%s' to '%s'", - StateStr(mState), StateStr(aNewState)); - mState = aNewState; - mStateObserverList.Broadcast(StateChangedEvent()); - } -} - -//static -void -VolumeManager::RegisterStateObserver(StateObserver* aObserver) -{ - mStateObserverList.AddObserver(aObserver); -} - -//static -void VolumeManager::UnregisterStateObserver(StateObserver* aObserver) -{ - mStateObserverList.RemoveObserver(aObserver); -} - -//static -already_AddRefed -VolumeManager::FindVolumeByName(const nsCSubstring& aName) -{ - if (!sVolumeManager) { - return nullptr; - } - VolumeArray::size_type numVolumes = NumVolumes(); - VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = GetVolume(volIndex); - if (vol->Name().Equals(aName)) { - return vol.forget(); - } - } - return nullptr; -} - -//static -already_AddRefed -VolumeManager::FindAddVolumeByName(const nsCSubstring& aName) -{ - RefPtr vol = FindVolumeByName(aName); - if (vol) { - return vol.forget(); - } - // No volume found, create and add a new one. - vol = new Volume(aName); - sVolumeManager->mVolumeArray.AppendElement(vol); - return vol.forget(); -} - -//static -bool -VolumeManager::RemoveVolumeByName(const nsCSubstring& aName) -{ - if (!sVolumeManager) { - return false; - } - VolumeArray::size_type numVolumes = NumVolumes(); - VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = GetVolume(volIndex); - if (vol->Name().Equals(aName)) { - sVolumeManager->mVolumeArray.RemoveElementAt(volIndex); - return true; - } - } - // No volume found. Return false to indicate this. - return false; -} - - -//static -void VolumeManager::InitConfig() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - // This function uses /system/etc/volume.cfg to add additional volumes - // to the Volume Manager. - // - // This is useful on devices like the Nexus 4, which have no physical sd card - // or dedicated partition. - // - // The format of the volume.cfg file is as follows: - // create volume-name mount-point - // configure volume-name preference preference-value - // Blank lines and lines starting with the hash character "#" will be ignored. - - ScopedCloseFile fp; - int n = 0; - char line[255]; - const char *filename = "/system/etc/volume.cfg"; - if (!(fp = fopen(filename, "r"))) { - LOG("Unable to open volume configuration file '%s' - ignoring", filename); - return; - } - while(fgets(line, sizeof(line), fp)) { - n++; - - if (line[0] == '#') - continue; - - nsCString commandline(line); - nsCWhitespaceTokenizer tokenizer(commandline); - if (!tokenizer.hasMoreTokens()) { - // Blank line - ignore - continue; - } - - nsCString command(tokenizer.nextToken()); - if (command.EqualsLiteral("create")) { - if (!tokenizer.hasMoreTokens()) { - ERR("No vol_name in %s line %d", filename, n); - continue; - } - nsCString volName(tokenizer.nextToken()); - if (!tokenizer.hasMoreTokens()) { - ERR("No mount point for volume '%s'. %s line %d", - volName.get(), filename, n); - continue; - } - nsCString mountPoint(tokenizer.nextToken()); - RefPtr vol = FindAddVolumeByName(volName); - vol->SetFakeVolume(mountPoint); - continue; - } - if (command.EqualsLiteral("configure")) { - if (!tokenizer.hasMoreTokens()) { - ERR("No vol_name in %s line %d", filename, n); - continue; - } - nsCString volName(tokenizer.nextToken()); - if (!tokenizer.hasMoreTokens()) { - ERR("No configuration name specified for volume '%s'. %s line %d", - volName.get(), filename, n); - continue; - } - nsCString configName(tokenizer.nextToken()); - if (!tokenizer.hasMoreTokens()) { - ERR("No value for configuration name '%s'. %s line %d", - configName.get(), filename, n); - continue; - } - nsCString configValue(tokenizer.nextToken()); - RefPtr vol = FindVolumeByName(volName); - if (vol) { - vol->SetConfig(configName, configValue); - } else { - ERR("Invalid volume name '%s'.", volName.get()); - } - continue; - } - if (command.EqualsLiteral("ignore")) { - // This command is useful to remove volumes which are being tracked by - // vold, but for which we have no interest. - if (!tokenizer.hasMoreTokens()) { - ERR("No vol_name in %s line %d", filename, n); - continue; - } - nsCString volName(tokenizer.nextToken()); - RemoveVolumeByName(volName); - continue; - } - ERR("Unrecognized command: '%s'", command.get()); - } -} - -void -VolumeManager::DefaultConfig() -{ - - VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - if (numVolumes == 0) { - return; - } - if (numVolumes == 1) { - // This is to cover early shipping phones like the Buri, - // which had no internal storage, and only external sdcard. - // - // Phones line the nexus-4 which only have an internal - // storage area will need to have a volume.cfg file with - // removable set to false. - RefPtr vol = VolumeManager::GetVolume(0); - vol->SetIsRemovable(true); - vol->SetIsHotSwappable(true); - return; - } - VolumeManager::VolumeArray::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = VolumeManager::GetVolume(volIndex); - if (!vol->Name().EqualsLiteral("sdcard")) { - vol->SetIsRemovable(true); - vol->SetIsHotSwappable(true); - } - } -} - -class VolumeListCallback : public VolumeResponseCallback -{ - virtual void ResponseReceived(const VolumeCommand* aCommand) - { - switch (ResponseCode()) { - case ::ResponseCode::VolumeListResult: { - // Each line will look something like: - // - // sdcard /mnt/sdcard 1 - // - // So for each volume that we get back, we update any volumes that - // we have of the same name, or add new ones if they don't exist. - nsCWhitespaceTokenizer tokenizer(ResponseStr()); - nsDependentCSubstring volName(tokenizer.nextToken()); - RefPtr vol = VolumeManager::FindAddVolumeByName(volName); - vol->HandleVoldResponse(ResponseCode(), tokenizer); - break; - } - - case ::ResponseCode::CommandOkay: { - // We've received the list of volumes. Now read the Volume.cfg - // file to perform customizations, and then tell everybody - // that we're ready for business. - VolumeManager::DefaultConfig(); - VolumeManager::InitConfig(); - VolumeManager::Dump("READY"); - VolumeManager::SetState(VolumeManager::VOLUMES_READY); - break; - } - } - } -}; - -bool -VolumeManager::OpenSocket() -{ - SetState(STARTING); - if ((mSocket.rwget() = socket_local_client("vold", - ANDROID_SOCKET_NAMESPACE_RESERVED, - SOCK_STREAM)) < 0) { - ERR("Error connecting to vold: (%s) - will retry", strerror(errno)); - return false; - } - // add FD_CLOEXEC flag - int flags = fcntl(mSocket.get(), F_GETFD); - if (flags == -1) { - return false; - } - flags |= FD_CLOEXEC; - if (fcntl(mSocket.get(), F_SETFD, flags) == -1) { - return false; - } - // set non-blocking - if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) { - return false; - } - if (!MessageLoopForIO::current()-> - WatchFileDescriptor(mSocket.get(), - true, - MessageLoopForIO::WATCH_READ, - &mReadWatcher, - this)) { - return false; - } - - LOG("Connected to vold"); - PostCommand(new VolumeListCommand(new VolumeListCallback)); - return true; -} - -//static -void -VolumeManager::PostCommand(VolumeCommand* aCommand) -{ - if (!sVolumeManager) { - ERR("VolumeManager not initialized. Dropping command '%s'", aCommand->Data()); - return; - } - aCommand->SetPending(true); - - DBG("Sending command '%s'", aCommand->Data()); - // vold can only process one command at a time, so add our command - // to the end of the command queue. - sVolumeManager->mCommands.push(aCommand); - if (!sVolumeManager->mCommandPending) { - // There aren't any commands currently being processed, so go - // ahead and kick this one off. - sVolumeManager->mCommandPending = true; - sVolumeManager->WriteCommandData(); - } -} - -/*************************************************************************** -* The WriteCommandData initiates sending of a command to vold. Since -* we're running on the IOThread and not allowed to block, WriteCommandData -* will write as much data as it can, and if not all of the data can be -* written then it will setup a file descriptor watcher and -* OnFileCanWriteWithoutBlocking will call WriteCommandData to write out -* more of the command data. -*/ -void -VolumeManager::WriteCommandData() -{ - if (mCommands.size() == 0) { - return; - } - - VolumeCommand* cmd = mCommands.front(); - if (cmd->BytesRemaining() == 0) { - // All bytes have been written. We're waiting for a response. - return; - } - // There are more bytes left to write. Try to write them all. - ssize_t bytesWritten = write(mSocket.get(), cmd->Data(), cmd->BytesRemaining()); - if (bytesWritten < 0) { - ERR("Failed to write %d bytes to vold socket", cmd->BytesRemaining()); - Restart(); - return; - } - DBG("Wrote %d bytes (of %d)", bytesWritten, cmd->BytesRemaining()); - cmd->ConsumeBytes(bytesWritten); - if (cmd->BytesRemaining() == 0) { - return; - } - // We were unable to write all of the command bytes. Setup a watcher - // so we'll get called again when we can write without blocking. - if (!MessageLoopForIO::current()-> - WatchFileDescriptor(mSocket.get(), - false, // one-shot - MessageLoopForIO::WATCH_WRITE, - &mWriteWatcher, - this)) { - ERR("Failed to setup write watcher for vold socket"); - Restart(); - } -} - -void -VolumeManager::OnLineRead(int aFd, nsDependentCSubstring& aMessage) -{ - MOZ_ASSERT(aFd == mSocket.get()); - char* endPtr; - int responseCode = strtol(aMessage.Data(), &endPtr, 10); - if (*endPtr == ' ') { - endPtr++; - } - - // Now fish out the rest of the line after the response code - nsDependentCString responseLine(endPtr, aMessage.Length() - (endPtr - aMessage.Data())); - DBG("Rcvd: %d '%s'", responseCode, responseLine.Data()); - - if (responseCode >= ::ResponseCode::UnsolicitedInformational) { - // These are unsolicited broadcasts. We intercept these and process - // them ourselves - HandleBroadcast(responseCode, responseLine); - } else { - // Everything else is considered to be part of the command response. - if (mCommands.size() > 0) { - VolumeCommand* cmd = mCommands.front(); - cmd->HandleResponse(responseCode, responseLine); - if (responseCode >= ::ResponseCode::CommandOkay) { - // That's a terminating response. We can remove the command. - mCommands.pop(); - mCommandPending = false; - // Start the next command, if there is one. - WriteCommandData(); - } - } else { - ERR("Response with no command"); - } - } -} - -void -VolumeManager::OnFileCanWriteWithoutBlocking(int aFd) -{ - MOZ_ASSERT(aFd == mSocket.get()); - WriteCommandData(); -} - -void -VolumeManager::HandleBroadcast(int aResponseCode, nsCString& aResponseLine) -{ - // Format of the line is something like: - // - // Volume sdcard /mnt/sdcard state changed from 7 (Shared-Unmounted) to 1 (Idle-Unmounted) - // - // So we parse out the volume name and the state after the string " to " - nsCWhitespaceTokenizer tokenizer(aResponseLine); - tokenizer.nextToken(); // The word "Volume" - nsDependentCSubstring volName(tokenizer.nextToken()); - - RefPtr vol = FindVolumeByName(volName); - if (!vol) { - return; - } - vol->HandleVoldResponse(aResponseCode, tokenizer); -} - -void -VolumeManager::Restart() -{ - mReadWatcher.StopWatchingFileDescriptor(); - mWriteWatcher.StopWatchingFileDescriptor(); - - while (!mCommands.empty()) { - mCommands.pop(); - } - mCommandPending = false; - mSocket.dispose(); - Start(); -} - -//static -void -VolumeManager::Start() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (!sVolumeManager) { - return; - } - SetState(STARTING); - if (!sVolumeManager->OpenSocket()) { - // Socket open failed, try again in a second. - MessageLoopForIO::current()-> - PostDelayedTask(NewRunnableFunction(VolumeManager::Start), - 1000); - } -} - -void -VolumeManager::OnError() -{ - Restart(); -} - -/***************************************************************************/ - -static void -InitVolumeManagerIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(!sVolumeManager); - - sVolumeManager = new VolumeManager(); - VolumeManager::Start(); - - InitVolumeServiceTestIOThread(); -} - -static void -ShutdownVolumeManagerIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - sVolumeManager = nullptr; -} - -/************************************************************************** -* -* Public API -* -* Since the VolumeManager runs in IO Thread context, we need to switch -* to IOThread context before we can do anything. -* -**************************************************************************/ - -void -InitVolumeManager() -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(InitVolumeManagerIOThread)); -} - -void -ShutdownVolumeManager() -{ - ShutdownVolumeServiceTest(); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownVolumeManagerIOThread)); -} - -} // system -} // mozilla diff --git a/dom/system/gonk/VolumeManager.h b/dom/system/gonk/VolumeManager.h deleted file mode 100644 index 7c0503389..000000000 --- a/dom/system/gonk/VolumeManager.h +++ /dev/null @@ -1,192 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumemanager_h__ -#define mozilla_system_volumemanager_h__ - -#include -#include - -#include "base/message_loop.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Observer.h" -#include "nsISupportsImpl.h" -#include "nsString.h" -#include "nsTArray.h" - -#include "Volume.h" -#include "VolumeCommand.h" - -namespace mozilla { -namespace system { - -/*************************************************************************** -* -* All of the public API mentioned in this file (unless otherwise -* mentioned) must run from the IOThread. -* -***************************************************************************/ - -/*************************************************************************** -* -* The VolumeManager class is a front-end for android's vold service. -* -* Vold uses a unix socket interface and accepts null-terminated string -* commands. The following commands were determined by examining the vold -* source code: -* -* volume list -* volume mount -* volume unmount [force] -* volume debug [on|off] -* volume format -* volume share -* volume unshare -* volume shared -* -* is the name of the volume as used in /system/etc/vold.fstab -* is ums -* -* dump -* -* share status (Determines if a particular sharing method is available) -* (GB only - not available in ICS) -* -* storage users (??? always crashes vold ???) -* -* asec list -* asec ...lots more... -* -* obb list -* obb ...lots more... -* -* xwarp enable -* xwarp disable -* xwarp status -* -* There is also a command line tool called vdc, which can be used to send -* the above commands to vold. -* -* Currently, only the volume list, share/unshare, and mount/unmount -* commands are being used. -* -***************************************************************************/ - -class VolumeManager final : public MessageLoopForIO::LineWatcher -{ - virtual ~VolumeManager(); - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeManager) - - typedef nsTArray> VolumeArray; - - VolumeManager(); - - //----------------------------------------------------------------------- - // - // State related methods. - // - // The VolumeManager starts off in the STARTING state. Once a connection - // is established with vold, it asks for a list of volumes, and once the - // volume list has been received, then the VolumeManager enters the - // VOLUMES_READY state. - // - // If vold crashes, then the VolumeManager will once again enter the - // STARTING state and try to reestablish a connection with vold. - - enum STATE - { - UNINITIALIZED, - STARTING, - VOLUMES_READY - }; - - static STATE State(); - static const char* StateStr(STATE aState); - static const char* StateStr() { return StateStr(State()); } - - class StateChangedEvent - { - public: - StateChangedEvent() {} - }; - - typedef mozilla::Observer StateObserver; - typedef mozilla::ObserverList StateObserverList; - - static void RegisterStateObserver(StateObserver* aObserver); - static void UnregisterStateObserver(StateObserver* aObserver); - - //----------------------------------------------------------------------- - - static void Start(); - static void Dump(const char* aLabel); - - static VolumeArray::size_type NumVolumes(); - static already_AddRefed GetVolume(VolumeArray::index_type aIndex); - static already_AddRefed FindVolumeByName(const nsCSubstring& aName); - static already_AddRefed FindAddVolumeByName(const nsCSubstring& aName); - static bool RemoveVolumeByName(const nsCSubstring& aName); - static void InitConfig(); - - static void PostCommand(VolumeCommand* aCommand); - -protected: - - virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage); - virtual void OnFileCanWriteWithoutBlocking(int aFd); - virtual void OnError(); - - static void DefaultConfig(); - -private: - bool OpenSocket(); - - friend class VolumeListCallback; // Calls SetState - - static void SetState(STATE aNewState); - - void Restart(); - void WriteCommandData(); - void HandleBroadcast(int aResponseCode, nsCString& aResponseLine); - - typedef std::queue > CommandQueue; - - static STATE mState; - static StateObserverList mStateObserverList; - - static const int kRcvBufSize = 1024; - ScopedClose mSocket; - VolumeArray mVolumeArray; - CommandQueue mCommands; - bool mCommandPending; - MessageLoopForIO::FileDescriptorWatcher mReadWatcher; - MessageLoopForIO::FileDescriptorWatcher mWriteWatcher; - RefPtr mBroadcastCallback; -}; - -/*************************************************************************** -* -* The initialization/shutdown functions do not need to be called from -* the IOThread context. -* -***************************************************************************/ - -/** - * Initialize the Volume Manager. On initialization, the VolumeManager will - * attempt to connect with vold and collect the list of volumes that vold - * knows about. - */ -void InitVolumeManager(); - -/** - * Shuts down the Volume Manager. - */ -void ShutdownVolumeManager(); - -} // system -} // mozilla - -#endif // mozilla_system_volumemanager_h__ diff --git a/dom/system/gonk/VolumeManagerLog.h b/dom/system/gonk/VolumeManagerLog.h deleted file mode 100644 index 793f4889c..000000000 --- a/dom/system/gonk/VolumeManagerLog.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumemanagerlog_h__ -#define mozilla_system_volumemanagerlog_h__ - -#undef USE_DEBUG -#define USE_DEBUG 0 - -#if !defined(VOLUME_MANAGER_LOG_TAG) -#define VOLUME_MANAGER_LOG_TAG "VolumeManager" -#endif - -#undef LOG -#undef ERR -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, VOLUME_MANAGER_LOG_TAG, ## args) -#define ERR(args...) __android_log_print(ANDROID_LOG_ERROR, VOLUME_MANAGER_LOG_TAG, ## args) - -#undef DBG -#if USE_DEBUG -#define DBG(args...) __android_log_print(ANDROID_LOG_DEBUG, VOLUME_MANAGER_LOG_TAG, ## args) -#else -#define DBG(args...) -#endif - -#endif // mozilla_system_volumemanagerlog_h__ diff --git a/dom/system/gonk/VolumeServiceIOThread.cpp b/dom/system/gonk/VolumeServiceIOThread.cpp deleted file mode 100644 index 7eda843c0..000000000 --- a/dom/system/gonk/VolumeServiceIOThread.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "VolumeServiceIOThread.h" -#include "base/message_loop.h" -#include "nsVolumeService.h" -#include "nsXULAppAPI.h" -#include "Volume.h" -#include "VolumeManager.h" - -namespace mozilla { -namespace system { - -VolumeServiceIOThread::VolumeServiceIOThread(nsVolumeService* aVolumeService) - : mVolumeService(aVolumeService) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - VolumeManager::RegisterStateObserver(this); - Volume::RegisterVolumeObserver(this, "VolumeServiceIOThread"); - UpdateAllVolumes(); -} - -VolumeServiceIOThread::~VolumeServiceIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - Volume::UnregisterVolumeObserver(this, "VolumeServiceIOThread"); - VolumeManager::UnregisterStateObserver(this); -} - -void -VolumeServiceIOThread::Notify(Volume* const & aVolume) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - mVolumeService->UpdateVolumeIOThread(aVolume); -} - -void -VolumeServiceIOThread::Notify(const VolumeManager::StateChangedEvent& aEvent) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - UpdateAllVolumes(); -} - -void -VolumeServiceIOThread::UpdateAllVolumes() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - VolumeManager::VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); - VolumeManager::VolumeArray::index_type volIndex; - - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = VolumeManager::GetVolume(volIndex); - mVolumeService->UpdateVolumeIOThread(vol); - } -} - -static StaticRefPtr sVolumeServiceIOThread; - -void -InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - sVolumeServiceIOThread = new VolumeServiceIOThread(aVolumeService); -} - -void -ShutdownVolumeServiceIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - sVolumeServiceIOThread = nullptr; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/VolumeServiceIOThread.h b/dom/system/gonk/VolumeServiceIOThread.h deleted file mode 100644 index 0c2a6a62f..000000000 --- a/dom/system/gonk/VolumeServiceIOThread.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumeserviceiothread_h__ -#define mozilla_system_volumeserviceiothread_h__ - -#include "Volume.h" -#include "VolumeManager.h" -#include "mozilla/RefPtr.h" - -namespace mozilla { -namespace system { - -class nsVolumeService; - -/*************************************************************************** -* The nsVolumeServiceIOThread is a companion class to the nsVolumeService -* class, but whose methods are called from IOThread. -*/ -class VolumeServiceIOThread : public VolumeManager::StateObserver, - public Volume::EventObserver -{ - ~VolumeServiceIOThread(); - -public: - NS_INLINE_DECL_REFCOUNTING(VolumeServiceIOThread) - - VolumeServiceIOThread(nsVolumeService* aVolumeService); - -private: - void UpdateAllVolumes(); - - virtual void Notify(const VolumeManager::StateChangedEvent& aEvent); - virtual void Notify(Volume* const & aVolume); - - RefPtr mVolumeService; -}; - -void InitVolumeServiceIOThread(nsVolumeService* const & aVolumeService); -void ShutdownVolumeServiceIOThread(); -void FormatVolume(const nsCString& aVolume); -void MountVolume(const nsCString& aVolume); -void UnmountVolume(const nsCString& aVolume); - -} // system -} // mozilla - -#endif // mozilla_system_volumeserviceiothread_h__ diff --git a/dom/system/gonk/VolumeServiceTest.cpp b/dom/system/gonk/VolumeServiceTest.cpp deleted file mode 100644 index 4082e3889..000000000 --- a/dom/system/gonk/VolumeServiceTest.cpp +++ /dev/null @@ -1,202 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "VolumeServiceTest.h" - -#include "base/message_loop.h" -#include "nsCOMPtr.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsIVolumeStat.h" -#include "nsXULAppAPI.h" - -#include "mozilla/Services.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "VolumeServiceTest" -#include "VolumeManagerLog.h" - -using namespace mozilla::services; - -namespace mozilla { -namespace system { - -#define TEST_NSVOLUME_OBSERVER 0 - -#if TEST_NSVOLUME_OBSERVER - -/*************************************************************************** -* A test class to verify that the Observer stuff is working properly. -*/ -class VolumeTestObserver : public nsIObserver -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - - VolumeTestObserver() - { - nsCOMPtr obs = GetObserverService(); - if (!obs) { - return; - } - obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, false); - } - ~VolumeTestObserver() - { - nsCOMPtr obs = GetObserverService(); - if (!obs) { - return; - } - obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED); - } - - void LogVolume(nsIVolume* vol) - { - nsString volName; - nsString mountPoint; - int32_t volState; - - vol->GetName(volName); - vol->GetMountPoint(mountPoint); - vol->GetState(&volState); - - LOG(" Volume: %s MountPoint: %s State: %s", - NS_LossyConvertUTF16toASCII(volName).get(), - NS_LossyConvertUTF16toASCII(mountPoint).get(), - NS_VolumeStateStr(volState)); - - nsCOMPtr stat; - nsresult rv = vol->GetStats(getter_AddRefs(stat)); - if (NS_SUCCEEDED(rv)) { - int64_t totalBytes; - int64_t freeBytes; - - stat->GetTotalBytes(&totalBytes); - stat->GetFreeBytes(&freeBytes); - - LOG(" Total Space: %llu Mb Free Bytes: %llu Mb", - totalBytes / (1024LL * 1024LL), freeBytes / (1024LL * 1024LL)); - } - else { - LOG(" Unable to retrieve stats"); - } - } -}; -static nsCOMPtr sTestObserver; - -NS_IMPL_ISUPPORTS(VolumeTestObserver, nsIObserver) - -NS_IMETHODIMP -VolumeTestObserver::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - LOG("TestObserver: topic: %s", aTopic); - - if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) { - return NS_OK; - } - nsCOMPtr vol = do_QueryInterface(aSubject); - if (vol) { - LogVolume(vol); - } - - // Since this observe method was called then we know that the service - // has been initialized so we can do the VolumeService tests. - - nsCOMPtr vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - if (!vs) { - ERR("do_GetService('%s') failed", NS_VOLUMESERVICE_CONTRACTID); - return NS_ERROR_FAILURE; - } - - nsresult rv = vs->GetVolumeByName(NS_LITERAL_STRING("sdcard"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - LOG("GetVolumeByName( 'sdcard' ) succeeded (expected)"); - LogVolume(vol); - } else { - ERR("GetVolumeByName( 'sdcard' ) failed (unexpected)"); - } - - rv = vs->GetVolumeByName(NS_LITERAL_STRING("foo"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - ERR("GetVolumeByName( 'foo' ) succeeded (unexpected)"); - } else { - LOG("GetVolumeByName( 'foo' ) failed (expected)"); - } - - rv = vs->GetVolumeByPath(NS_LITERAL_STRING("/mnt/sdcard"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - LOG("GetVolumeByPath( '/mnt/sdcard' ) succeeded (expected)"); - LogVolume(vol); - } else { - ERR("GetVolumeByPath( '/mnt/sdcard' ) failed (unexpected"); - } - - rv = vs->GetVolumeByPath(NS_LITERAL_STRING("/mnt/sdcard/foo"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - LOG("GetVolumeByPath( '/mnt/sdcard/foo' ) succeeded (expected)"); - LogVolume(vol); - } else { - LOG("GetVolumeByPath( '/mnt/sdcard/foo' ) failed (unexpected)"); - } - - rv = vs->GetVolumeByPath(NS_LITERAL_STRING("/mnt/sdcardfoo"), getter_AddRefs(vol)); - if (NS_SUCCEEDED(rv)) { - ERR("GetVolumeByPath( '/mnt/sdcardfoo' ) succeeded (unexpected)"); - } else { - LOG("GetVolumeByPath( '/mnt/sdcardfoo' ) failed (expected)"); - } - - return NS_OK; -} - -class InitVolumeServiceTestIO : public Runnable -{ -public: - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - - DBG("InitVolumeServiceTest called"); - nsCOMPtr vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - if (!vs) { - ERR("do_GetService('%s') failed", NS_VOLUMESERVICE_CONTRACTID); - return NS_ERROR_FAILURE; - } - sTestObserver = new VolumeTestObserver(); - - return NS_OK; - } -}; -#endif // TEST_NSVOLUME_OBSERVER - -void -InitVolumeServiceTestIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - -#if TEST_NSVOLUME_OBSERVER - // Now that the volume manager is initialized we can go - // ahead and do our test (on main thread). - NS_DispatchToMainThread(new InitVolumeServiceTestIO()); -#endif -} - -void -ShutdownVolumeServiceTest() -{ -#if TEST_NSVOLUME_OBSERVER - DBG("ShutdownVolumeServiceTestIOThread called"); - sTestObserver = nullptr; -#endif -} - -} // system -} // mozilla diff --git a/dom/system/gonk/VolumeServiceTest.h b/dom/system/gonk/VolumeServiceTest.h deleted file mode 100644 index 71a92bf6c..000000000 --- a/dom/system/gonk/VolumeServiceTest.h +++ /dev/null @@ -1,19 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_volumeservicetest_h__ -#define mozilla_system_volumeservicetest_h__ - - -namespace mozilla { -namespace system { - -void InitVolumeServiceTestIOThread(); -void ShutdownVolumeServiceTest(); - -} // system -} // mozilla - -#endif // mozilla_system_volumeservicetest_h__ - diff --git a/dom/system/gonk/android_audio/AudioSystem.h b/dom/system/gonk/android_audio/AudioSystem.h deleted file mode 100644 index d5841eaaa..000000000 --- a/dom/system/gonk/android_audio/AudioSystem.h +++ /dev/null @@ -1,1134 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef ANDROID_AUDIOSYSTEM_H_ -#define ANDROID_AUDIOSYSTEM_H_ - -#pragma GCC visibility push(default) - -#include -#include -#include "IAudioFlinger.h" - -#ifndef VANILLA_ANDROID -/* request to open a direct output with get_output() (by opposition to - * sharing an output with other AudioTracks) - */ -typedef enum { - AUDIO_POLICY_OUTPUT_FLAG_INDIRECT = 0x0, - AUDIO_POLICY_OUTPUT_FLAG_DIRECT = 0x1 -} audio_policy_output_flags_t; - -/* device categories used for audio_policy->set_force_use() */ -typedef enum { - AUDIO_POLICY_FORCE_NONE, - AUDIO_POLICY_FORCE_SPEAKER, - AUDIO_POLICY_FORCE_HEADPHONES, - AUDIO_POLICY_FORCE_BT_SCO, - AUDIO_POLICY_FORCE_BT_A2DP, - AUDIO_POLICY_FORCE_WIRED_ACCESSORY, - AUDIO_POLICY_FORCE_BT_CAR_DOCK, - AUDIO_POLICY_FORCE_BT_DESK_DOCK, - AUDIO_POLICY_FORCE_ANALOG_DOCK, - AUDIO_POLICY_FORCE_DIGITAL_DOCK, - AUDIO_POLICY_FORCE_NO_BT_A2DP, - AUDIO_POLICY_FORCE_CFG_CNT, - AUDIO_POLICY_FORCE_CFG_MAX = AUDIO_POLICY_FORCE_CFG_CNT - 1, - - AUDIO_POLICY_FORCE_DEFAULT = AUDIO_POLICY_FORCE_NONE, -} audio_policy_forced_cfg_t; - -/* usages used for audio_policy->set_force_use() */ -typedef enum { - AUDIO_POLICY_FORCE_FOR_COMMUNICATION, - AUDIO_POLICY_FORCE_FOR_MEDIA, - AUDIO_POLICY_FORCE_FOR_RECORD, - AUDIO_POLICY_FORCE_FOR_DOCK, - - AUDIO_POLICY_FORCE_USE_CNT, - AUDIO_POLICY_FORCE_USE_MAX = AUDIO_POLICY_FORCE_USE_CNT - 1, -} audio_policy_force_use_t; - -typedef enum { - AUDIO_STREAM_DEFAULT = -1, - AUDIO_STREAM_VOICE_CALL = 0, - AUDIO_STREAM_SYSTEM = 1, - AUDIO_STREAM_RING = 2, - AUDIO_STREAM_MUSIC = 3, - AUDIO_STREAM_ALARM = 4, - AUDIO_STREAM_NOTIFICATION = 5, - AUDIO_STREAM_BLUETOOTH_SCO = 6, - AUDIO_STREAM_ENFORCED_AUDIBLE = 7, /* Sounds that cannot be muted by user and must be routed to speaker */ - AUDIO_STREAM_DTMF = 8, - AUDIO_STREAM_TTS = 9, -#if ANDROID_VERSION < 19 - AUDIO_STREAM_FM = 10, -#endif - - AUDIO_STREAM_CNT, - AUDIO_STREAM_MAX = AUDIO_STREAM_CNT - 1, -} audio_stream_type_t; - -/* PCM sub formats */ -typedef enum { - AUDIO_FORMAT_PCM_SUB_16_BIT = 0x1, /* DO NOT CHANGE - PCM signed 16 bits */ - AUDIO_FORMAT_PCM_SUB_8_BIT = 0x2, /* DO NOT CHANGE - PCM unsigned 8 bits */ - AUDIO_FORMAT_PCM_SUB_32_BIT = 0x3, /* PCM signed .31 fixed point */ - AUDIO_FORMAT_PCM_SUB_8_24_BIT = 0x4, /* PCM signed 7.24 fixed point */ -} audio_format_pcm_sub_fmt_t; - -/* Audio format consists in a main format field (upper 8 bits) and a sub format - * field (lower 24 bits). - * - * The main format indicates the main codec type. The sub format field - * indicates options and parameters for each format. The sub format is mainly - * used for record to indicate for instance the requested bitrate or profile. - * It can also be used for certain formats to give informations not present in - * the encoded audio stream (e.g. octet alignement for AMR). - */ -typedef enum { - AUDIO_FORMAT_INVALID = 0xFFFFFFFFUL, - AUDIO_FORMAT_DEFAULT = 0, - AUDIO_FORMAT_PCM = 0x00000000UL, /* DO NOT CHANGE */ - AUDIO_FORMAT_MP3 = 0x01000000UL, - AUDIO_FORMAT_AMR_NB = 0x02000000UL, - AUDIO_FORMAT_AMR_WB = 0x03000000UL, - AUDIO_FORMAT_AAC = 0x04000000UL, - AUDIO_FORMAT_HE_AAC_V1 = 0x05000000UL, - AUDIO_FORMAT_HE_AAC_V2 = 0x06000000UL, - AUDIO_FORMAT_VORBIS = 0x07000000UL, - AUDIO_FORMAT_MAIN_MASK = 0xFF000000UL, - AUDIO_FORMAT_SUB_MASK = 0x00FFFFFFUL, - - /* Aliases */ - AUDIO_FORMAT_PCM_16_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_16_BIT), - AUDIO_FORMAT_PCM_8_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_8_BIT), - AUDIO_FORMAT_PCM_32_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_32_BIT), - AUDIO_FORMAT_PCM_8_24_BIT = (AUDIO_FORMAT_PCM | - AUDIO_FORMAT_PCM_SUB_8_24_BIT), -} audio_format_t; - -typedef enum { - /* output channels */ - AUDIO_CHANNEL_OUT_FRONT_LEFT = 0x1, - AUDIO_CHANNEL_OUT_FRONT_RIGHT = 0x2, - AUDIO_CHANNEL_OUT_FRONT_CENTER = 0x4, - AUDIO_CHANNEL_OUT_LOW_FREQUENCY = 0x8, - AUDIO_CHANNEL_OUT_BACK_LEFT = 0x10, - AUDIO_CHANNEL_OUT_BACK_RIGHT = 0x20, - AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x40, - AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80, - AUDIO_CHANNEL_OUT_BACK_CENTER = 0x100, - AUDIO_CHANNEL_OUT_SIDE_LEFT = 0x200, - AUDIO_CHANNEL_OUT_SIDE_RIGHT = 0x400, - AUDIO_CHANNEL_OUT_TOP_CENTER = 0x800, - AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT = 0x1000, - AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER = 0x2000, - AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT = 0x4000, - AUDIO_CHANNEL_OUT_TOP_BACK_LEFT = 0x8000, - AUDIO_CHANNEL_OUT_TOP_BACK_CENTER = 0x10000, - AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT = 0x20000, - - AUDIO_CHANNEL_OUT_MONO = AUDIO_CHANNEL_OUT_FRONT_LEFT, - AUDIO_CHANNEL_OUT_STEREO = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT), - AUDIO_CHANNEL_OUT_QUAD = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT), - AUDIO_CHANNEL_OUT_SURROUND = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_BACK_CENTER), - AUDIO_CHANNEL_OUT_5POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT), - // matches the correct AudioFormat.CHANNEL_OUT_7POINT1_SURROUND definition for 7.1 - AUDIO_CHANNEL_OUT_7POINT1 = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT | - AUDIO_CHANNEL_OUT_SIDE_LEFT | - AUDIO_CHANNEL_OUT_SIDE_RIGHT), - AUDIO_CHANNEL_OUT_ALL = (AUDIO_CHANNEL_OUT_FRONT_LEFT | - AUDIO_CHANNEL_OUT_FRONT_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_CENTER | - AUDIO_CHANNEL_OUT_LOW_FREQUENCY | - AUDIO_CHANNEL_OUT_BACK_LEFT | - AUDIO_CHANNEL_OUT_BACK_RIGHT | - AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER | - AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | - AUDIO_CHANNEL_OUT_BACK_CENTER| - AUDIO_CHANNEL_OUT_SIDE_LEFT| - AUDIO_CHANNEL_OUT_SIDE_RIGHT| - AUDIO_CHANNEL_OUT_TOP_CENTER| - AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT| - AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER| - AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT| - AUDIO_CHANNEL_OUT_TOP_BACK_LEFT| - AUDIO_CHANNEL_OUT_TOP_BACK_CENTER| - AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT), - - /* input channels */ - AUDIO_CHANNEL_IN_LEFT = 0x4, - AUDIO_CHANNEL_IN_RIGHT = 0x8, - AUDIO_CHANNEL_IN_FRONT = 0x10, - AUDIO_CHANNEL_IN_BACK = 0x20, - AUDIO_CHANNEL_IN_LEFT_PROCESSED = 0x40, - AUDIO_CHANNEL_IN_RIGHT_PROCESSED = 0x80, - AUDIO_CHANNEL_IN_FRONT_PROCESSED = 0x100, - AUDIO_CHANNEL_IN_BACK_PROCESSED = 0x200, - AUDIO_CHANNEL_IN_PRESSURE = 0x400, - AUDIO_CHANNEL_IN_X_AXIS = 0x800, - AUDIO_CHANNEL_IN_Y_AXIS = 0x1000, - AUDIO_CHANNEL_IN_Z_AXIS = 0x2000, - AUDIO_CHANNEL_IN_VOICE_UPLINK = 0x4000, - AUDIO_CHANNEL_IN_VOICE_DNLINK = 0x8000, - - AUDIO_CHANNEL_IN_MONO = AUDIO_CHANNEL_IN_FRONT, - AUDIO_CHANNEL_IN_STEREO = (AUDIO_CHANNEL_IN_LEFT | AUDIO_CHANNEL_IN_RIGHT), - AUDIO_CHANNEL_IN_ALL = (AUDIO_CHANNEL_IN_LEFT | - AUDIO_CHANNEL_IN_RIGHT | - AUDIO_CHANNEL_IN_FRONT | - AUDIO_CHANNEL_IN_BACK| - AUDIO_CHANNEL_IN_LEFT_PROCESSED | - AUDIO_CHANNEL_IN_RIGHT_PROCESSED | - AUDIO_CHANNEL_IN_FRONT_PROCESSED | - AUDIO_CHANNEL_IN_BACK_PROCESSED| - AUDIO_CHANNEL_IN_PRESSURE | - AUDIO_CHANNEL_IN_X_AXIS | - AUDIO_CHANNEL_IN_Y_AXIS | - AUDIO_CHANNEL_IN_Z_AXIS | - AUDIO_CHANNEL_IN_VOICE_UPLINK | - AUDIO_CHANNEL_IN_VOICE_DNLINK), -} audio_channels_t; - -#if ANDROID_VERSION >= 17 -typedef enum { - AUDIO_MODE_INVALID = -2, - AUDIO_MODE_CURRENT = -1, - AUDIO_MODE_NORMAL = 0, - AUDIO_MODE_RINGTONE = 1, - AUDIO_MODE_IN_CALL = 2, - AUDIO_MODE_IN_COMMUNICATION = 3, - - AUDIO_MODE_CNT, - AUDIO_MODE_MAX = AUDIO_MODE_CNT - 1, -} audio_mode_t; -#endif -#endif - -#if ANDROID_VERSION < 17 -typedef enum { - AUDIO_DEVICE_NONE = 0x0, - /* output devices */ - AUDIO_DEVICE_OUT_EARPIECE = 0x1, - AUDIO_DEVICE_OUT_SPEAKER = 0x2, - AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, - AUDIO_DEVICE_OUT_FM = 0x2000, - AUDIO_DEVICE_OUT_ANC_HEADSET = 0x4000, - AUDIO_DEVICE_OUT_ANC_HEADPHONE = 0x8000, - AUDIO_DEVICE_OUT_FM_TX = 0x10000, - AUDIO_DEVICE_OUT_DIRECTOUTPUT = 0x20000, - AUDIO_DEVICE_OUT_PROXY = 0x40000, - AUDIO_DEVICE_OUT_DEFAULT = 0x80000, - AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_FM | - AUDIO_DEVICE_OUT_ANC_HEADSET | - AUDIO_DEVICE_OUT_ANC_HEADPHONE | - AUDIO_DEVICE_OUT_FM_TX | - AUDIO_DEVICE_OUT_DIRECTOUTPUT | - AUDIO_DEVICE_OUT_PROXY | - AUDIO_DEVICE_OUT_DEFAULT), - AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), - /* input devices */ - AUDIO_DEVICE_IN_COMMUNICATION = 0x100000, - AUDIO_DEVICE_IN_AMBIENT = 0x200000, - AUDIO_DEVICE_IN_BUILTIN_MIC = 0x400000, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x800000, - AUDIO_DEVICE_IN_WIRED_HEADSET = 0x1000000, - AUDIO_DEVICE_IN_AUX_DIGITAL = 0x2000000, - AUDIO_DEVICE_IN_VOICE_CALL = 0x4000000, - AUDIO_DEVICE_IN_BACK_MIC = 0x8000000, - AUDIO_DEVICE_IN_ANC_HEADSET = 0x10000000, - AUDIO_DEVICE_IN_FM_RX = 0x20000000, - AUDIO_DEVICE_IN_FM_RX_A2DP = 0x40000000, - AUDIO_DEVICE_IN_DEFAULT = 0x80000000, - - AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_VOICE_CALL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_ANC_HEADSET | - AUDIO_DEVICE_IN_FM_RX | - AUDIO_DEVICE_IN_FM_RX_A2DP | - AUDIO_DEVICE_IN_DEFAULT), - AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, -} audio_devices_t; -#elif ANDROID_VERSION < 21 -enum { - AUDIO_DEVICE_NONE = 0x0, - /* reserved bits */ - AUDIO_DEVICE_BIT_IN = 0x80000000, - AUDIO_DEVICE_BIT_DEFAULT = 0x40000000, - /* output devices */ - AUDIO_DEVICE_OUT_EARPIECE = 0x1, - AUDIO_DEVICE_OUT_SPEAKER = 0x2, - AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, - AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000, - AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000, - AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000, - AUDIO_DEVICE_OUT_ANC_HEADSET = 0x10000, - AUDIO_DEVICE_OUT_ANC_HEADPHONE = 0x20000, - AUDIO_DEVICE_OUT_PROXY = 0x40000, - AUDIO_DEVICE_OUT_FM = 0x80000, - AUDIO_DEVICE_OUT_FM_TX = 0x100000, - AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, - AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE | - AUDIO_DEVICE_OUT_REMOTE_SUBMIX | - AUDIO_DEVICE_OUT_ANC_HEADSET | - AUDIO_DEVICE_OUT_ANC_HEADPHONE | - AUDIO_DEVICE_OUT_PROXY | - AUDIO_DEVICE_OUT_FM | - AUDIO_DEVICE_OUT_FM_TX | - AUDIO_DEVICE_OUT_DEFAULT), - AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), - AUDIO_DEVICE_OUT_ALL_USB = (AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE), - - /* input devices */ - AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1, - AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2, - AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8, - AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10, - AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20, - AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40, - AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80, - AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100, - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200, - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400, - AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800, - AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000, - AUDIO_DEVICE_IN_ANC_HEADSET = AUDIO_DEVICE_BIT_IN | 0x2000, - AUDIO_DEVICE_IN_PROXY = AUDIO_DEVICE_BIT_IN | 0x4000, - AUDIO_DEVICE_IN_FM_RX = AUDIO_DEVICE_BIT_IN | 0x8000, - AUDIO_DEVICE_IN_FM_RX_A2DP = AUDIO_DEVICE_BIT_IN | 0x10000, - AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT, - - AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_VOICE_CALL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_REMOTE_SUBMIX | - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_IN_USB_ACCESSORY | - AUDIO_DEVICE_IN_USB_DEVICE | - AUDIO_DEVICE_IN_ANC_HEADSET | - AUDIO_DEVICE_IN_FM_RX | - AUDIO_DEVICE_IN_FM_RX_A2DP | - AUDIO_DEVICE_IN_PROXY | - AUDIO_DEVICE_IN_DEFAULT), - AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, -}; - -typedef uint32_t audio_devices_t; -#else -enum { - AUDIO_DEVICE_NONE = 0x0, - /* reserved bits */ - AUDIO_DEVICE_BIT_IN = 0x80000000, - AUDIO_DEVICE_BIT_DEFAULT = 0x40000000, - /* output devices */ - AUDIO_DEVICE_OUT_EARPIECE = 0x1, - AUDIO_DEVICE_OUT_SPEAKER = 0x2, - AUDIO_DEVICE_OUT_WIRED_HEADSET = 0x4, - AUDIO_DEVICE_OUT_WIRED_HEADPHONE = 0x8, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO = 0x10, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - AUDIO_DEVICE_OUT_AUX_DIGITAL = 0x400, - AUDIO_DEVICE_OUT_HDMI = AUDIO_DEVICE_OUT_AUX_DIGITAL, - /* uses an analog connection (multiplexed over the USB connector pins for instance) */ - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET = 0x800, - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET = 0x1000, - /* USB accessory mode: your Android device is a USB device and the dock is a USB host */ - AUDIO_DEVICE_OUT_USB_ACCESSORY = 0x2000, - /* USB host mode: your Android device is a USB host and the dock is a USB device */ - AUDIO_DEVICE_OUT_USB_DEVICE = 0x4000, - AUDIO_DEVICE_OUT_REMOTE_SUBMIX = 0x8000, - /* Telephony voice TX path */ - AUDIO_DEVICE_OUT_TELEPHONY_TX = 0x10000, - /* Analog jack with line impedance detected */ - AUDIO_DEVICE_OUT_LINE = 0x20000, - /* HDMI Audio Return Channel */ - AUDIO_DEVICE_OUT_HDMI_ARC = 0x40000, - /* S/PDIF out */ - AUDIO_DEVICE_OUT_SPDIF = 0x80000, - /* FM transmitter out */ - AUDIO_DEVICE_OUT_FM = 0x100000, - /* Line out for av devices */ - AUDIO_DEVICE_OUT_AUX_LINE = 0x200000, - /* limited-output speaker device for acoustic safety */ - AUDIO_DEVICE_OUT_SPEAKER_SAFE = 0x400000, - AUDIO_DEVICE_OUT_DEFAULT = AUDIO_DEVICE_BIT_DEFAULT, - AUDIO_DEVICE_OUT_ALL = (AUDIO_DEVICE_OUT_EARPIECE | - AUDIO_DEVICE_OUT_SPEAKER | - AUDIO_DEVICE_OUT_WIRED_HEADSET | - AUDIO_DEVICE_OUT_WIRED_HEADPHONE | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | - AUDIO_DEVICE_OUT_AUX_DIGITAL | - AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE | - AUDIO_DEVICE_OUT_REMOTE_SUBMIX | - AUDIO_DEVICE_OUT_TELEPHONY_TX | - AUDIO_DEVICE_OUT_LINE | - AUDIO_DEVICE_OUT_HDMI_ARC | - AUDIO_DEVICE_OUT_SPDIF | - AUDIO_DEVICE_OUT_FM | - AUDIO_DEVICE_OUT_AUX_LINE | - AUDIO_DEVICE_OUT_SPEAKER_SAFE | - AUDIO_DEVICE_OUT_DEFAULT), - AUDIO_DEVICE_OUT_ALL_A2DP = (AUDIO_DEVICE_OUT_BLUETOOTH_A2DP | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - AUDIO_DEVICE_OUT_ALL_SCO = (AUDIO_DEVICE_OUT_BLUETOOTH_SCO | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT), - AUDIO_DEVICE_OUT_ALL_USB = (AUDIO_DEVICE_OUT_USB_ACCESSORY | - AUDIO_DEVICE_OUT_USB_DEVICE), - /* input devices */ - AUDIO_DEVICE_IN_COMMUNICATION = AUDIO_DEVICE_BIT_IN | 0x1, - AUDIO_DEVICE_IN_AMBIENT = AUDIO_DEVICE_BIT_IN | 0x2, - AUDIO_DEVICE_IN_BUILTIN_MIC = AUDIO_DEVICE_BIT_IN | 0x4, - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET = AUDIO_DEVICE_BIT_IN | 0x8, - AUDIO_DEVICE_IN_WIRED_HEADSET = AUDIO_DEVICE_BIT_IN | 0x10, - AUDIO_DEVICE_IN_AUX_DIGITAL = AUDIO_DEVICE_BIT_IN | 0x20, - AUDIO_DEVICE_IN_HDMI = AUDIO_DEVICE_IN_AUX_DIGITAL, - /* Telephony voice RX path */ - AUDIO_DEVICE_IN_VOICE_CALL = AUDIO_DEVICE_BIT_IN | 0x40, - AUDIO_DEVICE_IN_BACK_MIC = AUDIO_DEVICE_BIT_IN | 0x80, - AUDIO_DEVICE_IN_REMOTE_SUBMIX = AUDIO_DEVICE_BIT_IN | 0x100, - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x200, - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET = AUDIO_DEVICE_BIT_IN | 0x400, - AUDIO_DEVICE_IN_USB_ACCESSORY = AUDIO_DEVICE_BIT_IN | 0x800, - AUDIO_DEVICE_IN_USB_DEVICE = AUDIO_DEVICE_BIT_IN | 0x1000, - /* FM tuner input */ - AUDIO_DEVICE_IN_FM_TUNER = AUDIO_DEVICE_BIT_IN | 0x2000, - /* TV tuner input */ - AUDIO_DEVICE_IN_TV_TUNER = AUDIO_DEVICE_BIT_IN | 0x4000, - /* Analog jack with line impedance detected */ - AUDIO_DEVICE_IN_LINE = AUDIO_DEVICE_BIT_IN | 0x8000, - /* S/PDIF in */ - AUDIO_DEVICE_IN_SPDIF = AUDIO_DEVICE_BIT_IN | 0x10000, - AUDIO_DEVICE_IN_BLUETOOTH_A2DP = AUDIO_DEVICE_BIT_IN | 0x20000, - AUDIO_DEVICE_IN_LOOPBACK = AUDIO_DEVICE_BIT_IN | 0x40000, - AUDIO_DEVICE_IN_DEFAULT = AUDIO_DEVICE_BIT_IN | AUDIO_DEVICE_BIT_DEFAULT, - AUDIO_DEVICE_IN_ALL = (AUDIO_DEVICE_IN_COMMUNICATION | - AUDIO_DEVICE_IN_AMBIENT | - AUDIO_DEVICE_IN_BUILTIN_MIC | - AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET | - AUDIO_DEVICE_IN_WIRED_HEADSET | - AUDIO_DEVICE_IN_AUX_DIGITAL | - AUDIO_DEVICE_IN_VOICE_CALL | - AUDIO_DEVICE_IN_BACK_MIC | - AUDIO_DEVICE_IN_REMOTE_SUBMIX | - AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET | - AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET | - AUDIO_DEVICE_IN_USB_ACCESSORY | - AUDIO_DEVICE_IN_USB_DEVICE | - AUDIO_DEVICE_IN_FM_TUNER | - AUDIO_DEVICE_IN_TV_TUNER | - AUDIO_DEVICE_IN_LINE | - AUDIO_DEVICE_IN_SPDIF | - AUDIO_DEVICE_IN_BLUETOOTH_A2DP | - AUDIO_DEVICE_IN_LOOPBACK | - AUDIO_DEVICE_IN_DEFAULT), - AUDIO_DEVICE_IN_ALL_SCO = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, - AUDIO_DEVICE_IN_ALL_USB = (AUDIO_DEVICE_IN_USB_ACCESSORY | - AUDIO_DEVICE_IN_USB_DEVICE), -}; - -typedef uint32_t audio_devices_t; -#endif - -static inline bool audio_is_output_device(uint32_t device) -{ -#if ANDROID_VERSION < 17 - if ((__builtin_popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0)) - return true; - else - return false; -#else - if (((device & AUDIO_DEVICE_BIT_IN) == 0) && - (__builtin_popcount(device) == 1) && ((device & ~AUDIO_DEVICE_OUT_ALL) == 0)) - return true; - else - return false; -#endif -} - -/* device connection states used for audio_policy->set_device_connection_state() - * */ -typedef enum { - AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, - AUDIO_POLICY_DEVICE_STATE_AVAILABLE, - - AUDIO_POLICY_DEVICE_STATE_CNT, - AUDIO_POLICY_DEVICE_STATE_MAX = AUDIO_POLICY_DEVICE_STATE_CNT - 1, -} audio_policy_dev_state_t; - -namespace android { - -typedef void (*audio_error_callback)(status_t err); -typedef int audio_io_handle_t; - -class IAudioPolicyService; -class String8; - -class AudioSystem -{ -public: - - enum stream_type { - DEFAULT =-1, - VOICE_CALL = 0, - SYSTEM = 1, - RING = 2, - MUSIC = 3, - ALARM = 4, - NOTIFICATION = 5, - BLUETOOTH_SCO = 6, - ENFORCED_AUDIBLE = 7, // Sounds that cannot be muted by user and must be routed to speaker - DTMF = 8, - TTS = 9, - FM = 10, - NUM_STREAM_TYPES - }; - - // Audio sub formats (see AudioSystem::audio_format). - enum pcm_sub_format { - PCM_SUB_16_BIT = 0x1, // must be 1 for backward compatibility - PCM_SUB_8_BIT = 0x2, // must be 2 for backward compatibility - }; - - // MP3 sub format field definition : can use 11 LSBs in the same way as MP3 frame header to specify - // bit rate, stereo mode, version... - enum mp3_sub_format { - //TODO - }; - - // AMR NB/WB sub format field definition: specify frame block interleaving, bandwidth efficient or octet aligned, - // encoding mode for recording... - enum amr_sub_format { - //TODO - }; - - // AAC sub format field definition: specify profile or bitrate for recording... - enum aac_sub_format { - //TODO - }; - - // VORBIS sub format field definition: specify quality for recording... - enum vorbis_sub_format { - //TODO - }; - - // Audio format consists in a main format field (upper 8 bits) and a sub format field (lower 24 bits). - // The main format indicates the main codec type. The sub format field indicates options and parameters - // for each format. The sub format is mainly used for record to indicate for instance the requested bitrate - // or profile. It can also be used for certain formats to give informations not present in the encoded - // audio stream (e.g. octet alignement for AMR). - enum audio_format { - INVALID_FORMAT = -1, - FORMAT_DEFAULT = 0, - PCM = 0x00000000, // must be 0 for backward compatibility - MP3 = 0x01000000, - AMR_NB = 0x02000000, - AMR_WB = 0x03000000, - AAC = 0x04000000, - HE_AAC_V1 = 0x05000000, - HE_AAC_V2 = 0x06000000, - VORBIS = 0x07000000, - EVRC = 0x08000000, - QCELP = 0x09000000, - VOIP_PCM_INPUT = 0x0A000000, - MAIN_FORMAT_MASK = 0xFF000000, - SUB_FORMAT_MASK = 0x00FFFFFF, - // Aliases - PCM_16_BIT = (PCM|PCM_SUB_16_BIT), - PCM_8_BIT = (PCM|PCM_SUB_8_BIT) - }; - - - // Channel mask definitions must be kept in sync with JAVA values in /media/java/android/media/AudioFormat.java - enum audio_channels { - // output channels - CHANNEL_OUT_FRONT_LEFT = 0x4, - CHANNEL_OUT_FRONT_RIGHT = 0x8, - CHANNEL_OUT_FRONT_CENTER = 0x10, - CHANNEL_OUT_LOW_FREQUENCY = 0x20, - CHANNEL_OUT_BACK_LEFT = 0x40, - CHANNEL_OUT_BACK_RIGHT = 0x80, - CHANNEL_OUT_FRONT_LEFT_OF_CENTER = 0x100, - CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x200, - CHANNEL_OUT_BACK_CENTER = 0x400, - CHANNEL_OUT_MONO = CHANNEL_OUT_FRONT_LEFT, - CHANNEL_OUT_STEREO = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT), - CHANNEL_OUT_QUAD = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT), - CHANNEL_OUT_SURROUND = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_BACK_CENTER), - CHANNEL_OUT_5POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT), - CHANNEL_OUT_7POINT1 = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | - CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER), - CHANNEL_OUT_ALL = (CHANNEL_OUT_FRONT_LEFT | CHANNEL_OUT_FRONT_RIGHT | - CHANNEL_OUT_FRONT_CENTER | CHANNEL_OUT_LOW_FREQUENCY | CHANNEL_OUT_BACK_LEFT | CHANNEL_OUT_BACK_RIGHT | - CHANNEL_OUT_FRONT_LEFT_OF_CENTER | CHANNEL_OUT_FRONT_RIGHT_OF_CENTER | CHANNEL_OUT_BACK_CENTER), - - // input channels - CHANNEL_IN_LEFT = 0x4, - CHANNEL_IN_RIGHT = 0x8, - CHANNEL_IN_FRONT = 0x10, - CHANNEL_IN_BACK = 0x20, - CHANNEL_IN_LEFT_PROCESSED = 0x40, - CHANNEL_IN_RIGHT_PROCESSED = 0x80, - CHANNEL_IN_FRONT_PROCESSED = 0x100, - CHANNEL_IN_BACK_PROCESSED = 0x200, - CHANNEL_IN_PRESSURE = 0x400, - CHANNEL_IN_X_AXIS = 0x800, - CHANNEL_IN_Y_AXIS = 0x1000, - CHANNEL_IN_Z_AXIS = 0x2000, - CHANNEL_IN_VOICE_UPLINK = 0x4000, - CHANNEL_IN_VOICE_DNLINK = 0x8000, - CHANNEL_IN_MONO = CHANNEL_IN_FRONT, - CHANNEL_IN_STEREO = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT), - CHANNEL_IN_ALL = (CHANNEL_IN_LEFT | CHANNEL_IN_RIGHT | CHANNEL_IN_FRONT | CHANNEL_IN_BACK| - CHANNEL_IN_LEFT_PROCESSED | CHANNEL_IN_RIGHT_PROCESSED | CHANNEL_IN_FRONT_PROCESSED | CHANNEL_IN_BACK_PROCESSED| - CHANNEL_IN_PRESSURE | CHANNEL_IN_X_AXIS | CHANNEL_IN_Y_AXIS | CHANNEL_IN_Z_AXIS | - CHANNEL_IN_VOICE_UPLINK | CHANNEL_IN_VOICE_DNLINK) - }; - - enum audio_mode { - MODE_INVALID = -2, - MODE_CURRENT = -1, - MODE_NORMAL = 0, - MODE_RINGTONE, - MODE_IN_CALL, - MODE_IN_COMMUNICATION, - NUM_MODES // not a valid entry, denotes end-of-list - }; - - enum audio_in_acoustics { - AGC_ENABLE = 0x0001, - AGC_DISABLE = 0, - NS_ENABLE = 0x0002, - NS_DISABLE = 0, - TX_IIR_ENABLE = 0x0004, - TX_DISABLE = 0 - }; - - // special audio session values - enum audio_sessions { - SESSION_OUTPUT_STAGE = -1, // session for effects attached to a particular output stream - // (value must be less than 0) - SESSION_OUTPUT_MIX = 0, // session for effects applied to output mix. These effects can - // be moved by audio policy manager to another output stream - // (value must be 0) - }; - - /* These are static methods to control the system-wide AudioFlinger - * only privileged processes can have access to them - */ - - // mute/unmute microphone - static status_t muteMicrophone(bool state); - static status_t isMicrophoneMuted(bool *state); - - // set/get master volume - static status_t setMasterVolume(float value); - static status_t getMasterVolume(float* volume); - // mute/unmute audio outputs - static status_t setMasterMute(bool mute); - static status_t getMasterMute(bool* mute); - - // set/get stream volume on specified output - static status_t setStreamVolume(int stream, float value, int output); - static status_t getStreamVolume(int stream, float* volume, int output); - - // mute/unmute stream - static status_t setStreamMute(int stream, bool mute); - static status_t getStreamMute(int stream, bool* mute); - - // set audio mode in audio hardware (see AudioSystem::audio_mode) - static status_t setMode(int mode); - - // returns true in *state if tracks are active on the specified stream - static status_t isStreamActive(int stream, bool *state); - - // set/get audio hardware parameters. The function accepts a list of parameters - // key value pairs in the form: key1=value1;key2=value2;... - // Some keys are reserved for standard parameters (See AudioParameter class). - static status_t setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs); - static String8 getParameters(audio_io_handle_t ioHandle, const String8& keys); - - static void setErrorCallback(audio_error_callback cb); - - // helper function to obtain AudioFlinger service handle - static const sp& get_audio_flinger(); - - static float linearToLog(int volume); - static int logToLinear(float volume); - - static status_t getOutputSamplingRate(int* samplingRate, int stream = DEFAULT); - static status_t getOutputFrameCount(int* frameCount, int stream = DEFAULT); - static status_t getOutputLatency(uint32_t* latency, int stream = DEFAULT); - - static bool routedToA2dpOutput(int streamType); - - static status_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount, - size_t* buffSize); - - static status_t setVoiceVolume(float volume); - - // return the number of audio frames written by AudioFlinger to audio HAL and - // audio dsp to DAC since the output on which the specificed stream is playing - // has exited standby. - // returned status (from utils/Errors.h) can be: - // - NO_ERROR: successful operation, halFrames and dspFrames point to valid data - // - INVALID_OPERATION: Not supported on current hardware platform - // - BAD_VALUE: invalid parameter - // NOTE: this feature is not supported on all hardware platforms and it is - // necessary to check returned status before using the returned values. - static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream = DEFAULT); - - static unsigned int getInputFramesLost(audio_io_handle_t ioHandle); - - static int newAudioSessionId(); - // - // AudioPolicyService interface - // - - enum audio_devices { - // output devices - DEVICE_OUT_EARPIECE = 0x1, - DEVICE_OUT_SPEAKER = 0x2, - DEVICE_OUT_WIRED_HEADSET = 0x4, - DEVICE_OUT_WIRED_HEADPHONE = 0x8, - DEVICE_OUT_BLUETOOTH_SCO = 0x10, - DEVICE_OUT_BLUETOOTH_SCO_HEADSET = 0x20, - DEVICE_OUT_BLUETOOTH_SCO_CARKIT = 0x40, - DEVICE_OUT_BLUETOOTH_A2DP = 0x80, - DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES = 0x100, - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER = 0x200, - DEVICE_OUT_AUX_DIGITAL = 0x400, - DEVICE_OUT_DEFAULT = 0x8000, - DEVICE_OUT_ALL = (DEVICE_OUT_EARPIECE | DEVICE_OUT_SPEAKER | DEVICE_OUT_WIRED_HEADSET | - DEVICE_OUT_WIRED_HEADPHONE | DEVICE_OUT_BLUETOOTH_SCO | DEVICE_OUT_BLUETOOTH_SCO_HEADSET | - DEVICE_OUT_BLUETOOTH_SCO_CARKIT | DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER | DEVICE_OUT_AUX_DIGITAL | DEVICE_OUT_DEFAULT), - DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | - DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER), - - // input devices - DEVICE_IN_COMMUNICATION = 0x10000, - DEVICE_IN_AMBIENT = 0x20000, - DEVICE_IN_BUILTIN_MIC = 0x40000, - DEVICE_IN_BLUETOOTH_SCO_HEADSET = 0x80000, - DEVICE_IN_WIRED_HEADSET = 0x100000, - DEVICE_IN_AUX_DIGITAL = 0x200000, - DEVICE_IN_VOICE_CALL = 0x400000, - DEVICE_IN_BACK_MIC = 0x800000, - DEVICE_IN_DEFAULT = 0x80000000, - - DEVICE_IN_ALL = (DEVICE_IN_COMMUNICATION | DEVICE_IN_AMBIENT | DEVICE_IN_BUILTIN_MIC | - DEVICE_IN_BLUETOOTH_SCO_HEADSET | DEVICE_IN_WIRED_HEADSET | DEVICE_IN_AUX_DIGITAL | - DEVICE_IN_VOICE_CALL | DEVICE_IN_BACK_MIC | DEVICE_IN_DEFAULT) - }; - - // device connection states used for setDeviceConnectionState() - enum device_connection_state { - DEVICE_STATE_UNAVAILABLE, - DEVICE_STATE_AVAILABLE, - NUM_DEVICE_STATES - }; - - // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks) - enum output_flags { - OUTPUT_FLAG_INDIRECT = 0x0, - OUTPUT_FLAG_DIRECT = 0x1 - }; - - // device categories used for setForceUse() - enum forced_config { - FORCE_NONE, - FORCE_SPEAKER, - FORCE_HEADPHONES, - FORCE_BT_SCO, - FORCE_BT_A2DP, - FORCE_WIRED_ACCESSORY, - FORCE_BT_CAR_DOCK, - FORCE_BT_DESK_DOCK, - FORCE_ANALOG_DOCK, - FORCE_DIGITAL_DOCK, - FORCE_NO_BT_A2DP, - NUM_FORCE_CONFIG, - FORCE_DEFAULT = FORCE_NONE - }; - - // usages used for setForceUse() - enum force_use { - FOR_COMMUNICATION, - FOR_MEDIA, - FOR_RECORD, - FOR_DOCK, - NUM_FORCE_USE - }; - - // types of io configuration change events received with ioConfigChanged() - enum io_config_event { - OUTPUT_OPENED, - OUTPUT_CLOSED, - OUTPUT_CONFIG_CHANGED, - INPUT_OPENED, - INPUT_CLOSED, - INPUT_CONFIG_CHANGED, - STREAM_CONFIG_CHANGED, - NUM_CONFIG_EVENTS - }; - - // audio output descritor used to cache output configurations in client process to avoid frequent calls - // through IAudioFlinger - class OutputDescriptor { - public: - OutputDescriptor() - : samplingRate(0), format(0), channels(0), frameCount(0), latency(0) {} - - uint32_t samplingRate; - int32_t format; - int32_t channels; - size_t frameCount; - uint32_t latency; - }; - - // - // IAudioPolicyService interface (see AudioPolicyInterface for method descriptions) - // - static status_t setDeviceConnectionState(audio_devices device, device_connection_state state, const char *device_address); - static device_connection_state getDeviceConnectionState(audio_devices device, const char *device_address); - static status_t setPhoneState(int state); -#if ANDROID_VERSION >= 17 - static status_t setPhoneState(audio_mode_t state); -#endif - static status_t setRingerMode(uint32_t mode, uint32_t mask); -#ifdef VANILLA_ANDROID - static status_t setForceUse(force_use usage, forced_config config); - static forced_config getForceUse(force_use usage); - static audio_io_handle_t getOutput(stream_type stream, - uint32_t samplingRate = 0, - uint32_t format = FORMAT_DEFAULT, - uint32_t channels = CHANNEL_OUT_STEREO, - output_flags flags = OUTPUT_FLAG_INDIRECT); - static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address); - static status_t setFmVolume(float volume); - static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device, const char *device_address); -#else - static status_t setForceUse(force_use usage, forced_config config) __attribute__((weak)); - static forced_config getForceUse(force_use usage) __attribute__((weak)); - static audio_io_handle_t getOutput(stream_type stream, - uint32_t samplingRate = 0, - uint32_t format = FORMAT_DEFAULT, - uint32_t channels = CHANNEL_OUT_STEREO, - output_flags flags = OUTPUT_FLAG_INDIRECT) __attribute__((weak)); - - static status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config) __attribute__((weak)); - static audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) __attribute__((weak)); - static audio_io_handle_t getOutput(audio_stream_type_t stream, - uint32_t samplingRate = 0, - uint32_t format = AUDIO_FORMAT_DEFAULT, - uint32_t channels = AUDIO_CHANNEL_OUT_STEREO, - audio_policy_output_flags_t flags = AUDIO_POLICY_OUTPUT_FLAG_INDIRECT) __attribute__((weak)); - static status_t setDeviceConnectionState(audio_devices_t device, audio_policy_dev_state_t state, const char *device_address) __attribute__((weak)); - static status_t setFmVolume(float volume) __attribute__((weak)); - static audio_policy_dev_state_t getDeviceConnectionState(audio_devices_t device, const char *device_address) __attribute__((weak)); - -#endif - static status_t startOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session = 0); - static status_t stopOutput(audio_io_handle_t output, - AudioSystem::stream_type stream, - int session = 0); - static void releaseOutput(audio_io_handle_t output); - static audio_io_handle_t getInput(int inputSource, - uint32_t samplingRate = 0, - uint32_t format = FORMAT_DEFAULT, - uint32_t channels = CHANNEL_IN_MONO, - audio_in_acoustics acoustics = (audio_in_acoustics)0); - static status_t startInput(audio_io_handle_t input); - static status_t stopInput(audio_io_handle_t input); - static void releaseInput(audio_io_handle_t input); - static status_t initStreamVolume(stream_type stream, - int indexMin, - int indexMax); - static status_t initStreamVolume(audio_stream_type_t stream, - int indexMin, - int indexMax); - static status_t setStreamVolumeIndex(stream_type stream, int index); - static status_t setStreamVolumeIndex(audio_stream_type_t stream, int index); -#if ANDROID_VERSION >= 17 - static status_t setStreamVolumeIndex(audio_stream_type_t stream, - int index, - audio_devices_t device); - static status_t getStreamVolumeIndex(audio_stream_type_t stream, - int *index, - audio_devices_t device); -#endif - static status_t getStreamVolumeIndex(stream_type stream, int *index); - static status_t getStreamVolumeIndex(audio_stream_type_t stream, int *index); - - static uint32_t getStrategyForStream(stream_type stream); -#if ANDROID_VERSION >= 17 - static audio_devices_t getDevicesForStream(audio_stream_type_t stream); -#endif - - static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); - static status_t registerEffect(effect_descriptor_t *desc, - audio_io_handle_t output, - uint32_t strategy, - int session, - int id); - static status_t unregisterEffect(int id); - - static const sp& get_audio_policy_service(); - - // ---------------------------------------------------------------------------- - - static uint32_t popCount(uint32_t u); - static bool isOutputDevice(audio_devices device); - static bool isInputDevice(audio_devices device); - static bool isA2dpDevice(audio_devices device); - static bool isBluetoothScoDevice(audio_devices device); - static bool isSeperatedStream(stream_type stream); - static bool isLowVisibility(stream_type stream); - static bool isOutputChannel(uint32_t channel); - static bool isInputChannel(uint32_t channel); - static bool isValidFormat(uint32_t format); - static bool isLinearPCM(uint32_t format); - static bool isModeInCall(); - -#if ANDROID_VERSION >= 21 - class AudioPortCallback : public RefBase - { - public: - - AudioPortCallback() {} - virtual ~AudioPortCallback() {} - - virtual void onAudioPortListUpdate() = 0; - virtual void onAudioPatchListUpdate() = 0; - virtual void onServiceDied() = 0; - - }; - - static void setAudioPortCallback(sp callBack); -#endif - -private: - - class AudioFlingerClient: public IBinder::DeathRecipient, public BnAudioFlingerClient - { - public: - AudioFlingerClient() { - } - - // DeathRecipient - virtual void binderDied(const wp& who); - - // IAudioFlingerClient - - // indicate a change in the configuration of an output or input: keeps the cached - // values for output/input parameters upto date in client process - virtual void ioConfigChanged(int event, int ioHandle, void *param2); - }; - - class AudioPolicyServiceClient: public IBinder::DeathRecipient - { - public: - AudioPolicyServiceClient() { - } - - // DeathRecipient - virtual void binderDied(const wp& who); - }; - - static sp gAudioFlingerClient; - static sp gAudioPolicyServiceClient; - friend class AudioFlingerClient; - friend class AudioPolicyServiceClient; - - static Mutex gLock; - static sp gAudioFlinger; - static audio_error_callback gAudioErrorCallback; - - static size_t gInBuffSize; - // previous parameters for recording buffer size queries - static uint32_t gPrevInSamplingRate; - static int gPrevInFormat; - static int gPrevInChannelCount; - - static sp gAudioPolicyService; - - // mapping between stream types and outputs - static DefaultKeyedVector gStreamOutputMap; - // list of output descritor containing cached parameters (sampling rate, framecount, channel count...) - static DefaultKeyedVector gOutputs; -}; - -class AudioParameter { - -public: - AudioParameter() {} - AudioParameter(const String8& keyValuePairs); - virtual ~AudioParameter(); - - // reserved parameter keys for changing standard parameters with setParameters() function. - // Using these keys is mandatory for AudioFlinger to properly monitor audio output/input - // configuration changes and act accordingly. - // keyRouting: to change audio routing, value is an int in AudioSystem::audio_devices - // keySamplingRate: to change sampling rate routing, value is an int - // keyFormat: to change audio format, value is an int in AudioSystem::audio_format - // keyChannels: to change audio channel configuration, value is an int in AudioSystem::audio_channels - // keyFrameCount: to change audio output frame count, value is an int - // keyInputSource: to change audio input source, value is an int in audio_source - // (defined in media/mediarecorder.h) - static const char *keyRouting; - static const char *keySamplingRate; - static const char *keyFormat; - static const char *keyChannels; - static const char *keyFrameCount; - static const char *keyInputSource; - - String8 toString(); - - status_t add(const String8& key, const String8& value); - status_t addInt(const String8& key, const int value); - status_t addFloat(const String8& key, const float value); - - status_t remove(const String8& key); - - status_t get(const String8& key, String8& value); - status_t getInt(const String8& key, int& value); - status_t getFloat(const String8& key, float& value); - status_t getAt(size_t index, String8& key, String8& value); - - size_t size() { return mParameters.size(); } - -private: - String8 mKeyValuePairs; - KeyedVector mParameters; -}; - -}; // namespace android - -#pragma GCC visibility pop - -#endif /*ANDROID_AUDIOSYSTEM_H_*/ diff --git a/dom/system/gonk/android_audio/AudioTrack.h b/dom/system/gonk/android_audio/AudioTrack.h deleted file mode 100644 index 6f8c6bb28..000000000 --- a/dom/system/gonk/android_audio/AudioTrack.h +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_AUDIOTRACK_H -#define ANDROID_AUDIOTRACK_H - -#include -#include - -#include "IAudioFlinger.h" -#include "IAudioTrack.h" -#include "AudioSystem.h" - -#include -#include -#include -#include -#include - - -namespace android { - -// ---------------------------------------------------------------------------- - -class audio_track_cblk_t; - -// ---------------------------------------------------------------------------- - -class AudioTrack -{ -public: - enum channel_index { - MONO = 0, - LEFT = 0, - RIGHT = 1 - }; - - /* Events used by AudioTrack callback function (audio_track_cblk_t). - */ - enum event_type { - EVENT_MORE_DATA = 0, // Request to write more data to PCM buffer. - EVENT_UNDERRUN = 1, // PCM buffer underrun occured. - EVENT_LOOP_END = 2, // Sample loop end was reached; playback restarted from loop start if loop count was not 0. - EVENT_MARKER = 3, // Playback head is at the specified marker position (See setMarkerPosition()). - EVENT_NEW_POS = 4, // Playback head is at a new position (See setPositionUpdatePeriod()). - EVENT_BUFFER_END = 5 // Playback head is at the end of the buffer. - }; - - /* Create Buffer on the stack and pass it to obtainBuffer() - * and releaseBuffer(). - */ - - class Buffer - { - public: - enum { - MUTE = 0x00000001 - }; - uint32_t flags; - int channelCount; - int format; - size_t frameCount; - size_t size; - union { - void* raw; - short* i16; - int8_t* i8; - }; - }; - - - /* As a convenience, if a callback is supplied, a handler thread - * is automatically created with the appropriate priority. This thread - * invokes the callback when a new buffer becomes availlable or an underrun condition occurs. - * Parameters: - * - * event: type of event notified (see enum AudioTrack::event_type). - * user: Pointer to context for use by the callback receiver. - * info: Pointer to optional parameter according to event type: - * - EVENT_MORE_DATA: pointer to AudioTrack::Buffer struct. The callback must not write - * more bytes than indicated by 'size' field and update 'size' if less bytes are - * written. - * - EVENT_UNDERRUN: unused. - * - EVENT_LOOP_END: pointer to an int indicating the number of loops remaining. - * - EVENT_MARKER: pointer to an uin32_t containing the marker position in frames. - * - EVENT_NEW_POS: pointer to an uin32_t containing the new position in frames. - * - EVENT_BUFFER_END: unused. - */ - - typedef void (*callback_t)(int event, void* user, void *info); - - /* Returns the minimum frame count required for the successful creation of - * an AudioTrack object. - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - NO_INIT: audio server or audio hardware not initialized - */ - - static status_t getMinFrameCount(int* frameCount, - int streamType =-1, - uint32_t sampleRate = 0); - - /* Constructs an uninitialized AudioTrack. No connection with - * AudioFlinger takes place. - */ - AudioTrack(); - - /* Creates an audio track and registers it with AudioFlinger. - * Once created, the track needs to be started before it can be used. - * Unspecified values are set to the audio hardware's current - * values. - * - * Parameters: - * - * streamType: Select the type of audio stream this track is attached to - * (e.g. AudioSystem::MUSIC). - * sampleRate: Track sampling rate in Hz. - * format: Audio format (e.g AudioSystem::PCM_16_BIT for signed - * 16 bits per sample). - * channels: Channel mask: see AudioSystem::audio_channels. - * frameCount: Total size of track PCM buffer in frames. This defines the - * latency of the track. - * flags: Reserved for future use. - * cbf: Callback function. If not null, this function is called periodically - * to request new PCM data. - * notificationFrames: The callback function is called each time notificationFrames PCM - * frames have been comsumed from track input buffer. - * user Context for use by the callback receiver. - */ - - AudioTrack( int streamType, - uint32_t sampleRate = 0, - int format = 0, - int channels = 0, - int frameCount = 0, - uint32_t flags = 0, - callback_t cbf = 0, - void* user = 0, - int notificationFrames = 0, - int sessionId = 0); - - /* Creates an audio track and registers it with AudioFlinger. With this constructor, - * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer - * identified by the argument sharedBuffer. This prototype is for static buffer playback. - * PCM data must be present into memory before the AudioTrack is started. - * The Write() and Flush() methods are not supported in this case. - * It is recommented to pass a callback function to be notified of playback end by an - * EVENT_UNDERRUN event. - */ - - AudioTrack( int streamType, - uint32_t sampleRate = 0, - int format = 0, - int channels = 0, - const sp& sharedBuffer = 0, - uint32_t flags = 0, - callback_t cbf = 0, - void* user = 0, - int notificationFrames = 0, - int sessionId = 0); - - /* Terminates the AudioTrack and unregisters it from AudioFlinger. - * Also destroys all resources assotiated with the AudioTrack. - */ - ~AudioTrack(); - - - /* Initialize an uninitialized AudioTrack. - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful intialization - * - INVALID_OPERATION: AudioTrack is already intitialized - * - BAD_VALUE: invalid parameter (channels, format, sampleRate...) - * - NO_INIT: audio server or audio hardware not initialized - * */ - status_t set(int streamType =-1, - uint32_t sampleRate = 0, - int format = 0, - int channels = 0, - int frameCount = 0, - uint32_t flags = 0, - callback_t cbf = 0, - void* user = 0, - int notificationFrames = 0, - const sp& sharedBuffer = 0, - bool threadCanCallJava = false, - int sessionId = 0); - - - /* Result of constructing the AudioTrack. This must be checked - * before using any AudioTrack API (except for set()), using - * an uninitialized AudioTrack produces undefined results. - * See set() method above for possible return codes. - */ - status_t initCheck() const; - - /* Returns this track's latency in milliseconds. - * This includes the latency due to AudioTrack buffer size, AudioMixer (if any) - * and audio hardware driver. - */ - uint32_t latency() const; - - /* getters, see constructor */ - - int streamType() const; - int format() const; - int channelCount() const; - uint32_t frameCount() const; - int frameSize() const; - sp& sharedBuffer(); - - - /* After it's created the track is not active. Call start() to - * make it active. If set, the callback will start being called. - */ - void start(); - - /* Stop a track. If set, the callback will cease being called and - * obtainBuffer returns STOPPED. Note that obtainBuffer() still works - * and will fill up buffers until the pool is exhausted. - */ - void stop(); - bool stopped() const; - - /* flush a stopped track. All pending buffers are discarded. - * This function has no effect if the track is not stoped. - */ - void flush(); - - /* Pause a track. If set, the callback will cease being called and - * obtainBuffer returns STOPPED. Note that obtainBuffer() still works - * and will fill up buffers until the pool is exhausted. - */ - void pause(); - - /* mute or unmutes this track. - * While mutted, the callback, if set, is still called. - */ - void mute(bool); - bool muted() const; - - - /* set volume for this track, mostly used for games' sound effects - * left and right volumes. Levels must be <= 1.0. - */ - status_t setVolume(float left, float right); - void getVolume(float* left, float* right); - - /* set the send level for this track. An auxiliary effect should be attached - * to the track with attachEffect(). Level must be <= 1.0. - */ - status_t setAuxEffectSendLevel(float level); - void getAuxEffectSendLevel(float* level); - - /* set sample rate for this track, mostly used for games' sound effects - */ - status_t setSampleRate(int sampleRate); - uint32_t getSampleRate(); - - /* Enables looping and sets the start and end points of looping. - * - * Parameters: - * - * loopStart: loop start expressed as the number of PCM frames played since AudioTrack start. - * loopEnd: loop end expressed as the number of PCM frames played since AudioTrack start. - * loopCount: number of loops to execute. Calling setLoop() with loopCount == 0 cancels any pending or - * active loop. loopCount = -1 means infinite looping. - * - * For proper operation the following condition must be respected: - * (loopEnd-loopStart) <= framecount() - */ - status_t setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount); - status_t getLoop(uint32_t *loopStart, uint32_t *loopEnd, int *loopCount); - - - /* Sets marker position. When playback reaches the number of frames specified, a callback with event - * type EVENT_MARKER is called. Calling setMarkerPosition with marker == 0 cancels marker notification - * callback. - * If the AudioTrack has been opened with no callback function associated, the operation will fail. - * - * Parameters: - * - * marker: marker position expressed in frames. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack has no callback installed. - */ - status_t setMarkerPosition(uint32_t marker); - status_t getMarkerPosition(uint32_t *marker); - - - /* Sets position update period. Every time the number of frames specified has been played, - * a callback with event type EVENT_NEW_POS is called. - * Calling setPositionUpdatePeriod with updatePeriod == 0 cancels new position notification - * callback. - * If the AudioTrack has been opened with no callback function associated, the operation will fail. - * - * Parameters: - * - * updatePeriod: position update notification period expressed in frames. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack has no callback installed. - */ - status_t setPositionUpdatePeriod(uint32_t updatePeriod); - status_t getPositionUpdatePeriod(uint32_t *updatePeriod); - - - /* Sets playback head position within AudioTrack buffer. The new position is specified - * in number of frames. - * This method must be called with the AudioTrack in paused or stopped state. - * Note that the actual position set is modulo the AudioTrack buffer size in frames. - * Therefore using this method makes sense only when playing a "static" audio buffer - * as opposed to streaming. - * The getPosition() method on the other hand returns the total number of frames played since - * playback start. - * - * Parameters: - * - * position: New playback head position within AudioTrack buffer. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack is not stopped. - * - BAD_VALUE: The specified position is beyond the number of frames present in AudioTrack buffer - */ - status_t setPosition(uint32_t position); - status_t getPosition(uint32_t *position); - - /* Forces AudioTrack buffer full condition. When playing a static buffer, this method avoids - * rewriting the buffer before restarting playback after a stop. - * This method must be called with the AudioTrack in paused or stopped state. - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the AudioTrack is not stopped. - */ - status_t reload(); - - /* returns a handle on the audio output used by this AudioTrack. - * - * Parameters: - * none. - * - * Returned value: - * handle on audio hardware output - */ - audio_io_handle_t getOutput(); - - /* returns the unique ID associated to this track. - * - * Parameters: - * none. - * - * Returned value: - * AudioTrack ID. - */ - int getSessionId(); - - - /* Attach track auxiliary output to specified effect. Used effectId = 0 - * to detach track from effect. - * - * Parameters: - * - * effectId: effectId obtained from AudioEffect::id(). - * - * Returned status (from utils/Errors.h) can be: - * - NO_ERROR: successful operation - * - INVALID_OPERATION: the effect is not an auxiliary effect. - * - BAD_VALUE: The specified effect ID is invalid - */ - status_t attachAuxEffect(int effectId); - - /* obtains a buffer of "frameCount" frames. The buffer must be - * filled entirely. If the track is stopped, obtainBuffer() returns - * STOPPED instead of NO_ERROR as long as there are buffers availlable, - * at which point NO_MORE_BUFFERS is returned. - * Buffers will be returned until the pool (buffercount()) - * is exhausted, at which point obtainBuffer() will either block - * or return WOULD_BLOCK depending on the value of the "blocking" - * parameter. - */ - - enum { - NO_MORE_BUFFERS = 0x80000001, - STOPPED = 1 - }; - - status_t obtainBuffer(Buffer* audioBuffer, int32_t waitCount); - void releaseBuffer(Buffer* audioBuffer); - - - /* As a convenience we provide a write() interface to the audio buffer. - * This is implemented on top of lockBuffer/unlockBuffer. For best - * performance - * - */ - ssize_t write(const void* buffer, size_t size); - - /* - * Dumps the state of an audio track. - */ - status_t dump(int fd, const Vector& args) const; - -private: - /* copying audio tracks is not allowed */ - AudioTrack(const AudioTrack& other); - AudioTrack& operator = (const AudioTrack& other); - - /* a small internal class to handle the callback */ - class AudioTrackThread : public Thread - { - public: - AudioTrackThread(AudioTrack& receiver, bool bCanCallJava = false); - private: - friend class AudioTrack; - virtual bool threadLoop(); - virtual status_t readyToRun(); - virtual void onFirstRef(); - AudioTrack& mReceiver; - Mutex mLock; - }; - - bool processAudioBuffer(const sp& thread); - status_t createTrack(int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp& sharedBuffer, - audio_io_handle_t output, - bool enforceFrameCount); - - sp mAudioTrack; - sp mCblkMemory; - sp mAudioTrackThread; - - float mVolume[2]; - float mSendLevel; - uint32_t mFrameCount; - - audio_track_cblk_t* mCblk; - uint8_t mStreamType; - uint8_t mFormat; - uint8_t mChannelCount; - uint8_t mMuted; - uint32_t mChannels; - status_t mStatus; - uint32_t mLatency; - - volatile int32_t mActive; - - callback_t mCbf; - void* mUserData; - uint32_t mNotificationFramesReq; // requested number of frames between each notification callback - uint32_t mNotificationFramesAct; // actual number of frames between each notification callback - sp mSharedBuffer; - int mLoopCount; - uint32_t mRemainingFrames; - uint32_t mMarkerPosition; - bool mMarkerReached; - uint32_t mNewPosition; - uint32_t mUpdatePeriod; - uint32_t mFlags; - int mSessionId; - int mAuxEffectId; - uint32_t mPadding[8]; -}; - - -}; // namespace android - -#endif // ANDROID_AUDIOTRACK_H diff --git a/dom/system/gonk/android_audio/EffectApi.h b/dom/system/gonk/android_audio/EffectApi.h deleted file mode 100644 index 729545d0c..000000000 --- a/dom/system/gonk/android_audio/EffectApi.h +++ /dev/null @@ -1,798 +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. - */ - -#ifndef ANDROID_EFFECTAPI_H_ -#define ANDROID_EFFECTAPI_H_ - -#include -#include -#include - -#if __cplusplus -extern "C" { -#endif - -///////////////////////////////////////////////// -// Effect control interface -///////////////////////////////////////////////// - -// The effect control interface is exposed by each effect engine implementation. It consists of -// a set of functions controlling the configuration, activation and process of the engine. -// The functions are grouped in a structure of type effect_interface_s: -// struct effect_interface_s { -// effect_process_t process; -// effect_command_t command; -// }; - - -// effect_interface_t: Effect control interface handle. -// The effect_interface_t serves two purposes regarding the implementation of the effect engine: -// - 1 it is the address of a pointer to an effect_interface_s structure where the functions -// of the effect control API for a particular effect are located. -// - 2 it is the address of the context of a particular effect instance. -// A typical implementation in the effect library would define a structure as follows: -// struct effect_module_s { -// const struct effect_interface_s *itfe; -// effect_config_t config; -// effect_context_t context; -// } -// The implementation of EffectCreate() function would then allocate a structure of this -// type and return its address as effect_interface_t -typedef struct effect_interface_s **effect_interface_t; - - -// Effect API version 1.0 -#define EFFECT_API_VERSION 0x0100 // Format 0xMMmm MM: Major version, mm: minor version - -// Maximum length of character strings in structures defines by this API. -#define EFFECT_STRING_LEN_MAX 64 - -// -//--- Effect descriptor structure effect_descriptor_t -// - -// Unique effect ID (can be generated from the following site: -// http://www.itu.int/ITU-T/asn1/uuid.html) -// This format is used for both "type" and "uuid" fields of the effect descriptor structure. -// - When used for effect type and the engine is implementing and effect corresponding to a standard -// OpenSL ES interface, this ID must be the one defined in OpenSLES_IID.h for that interface. -// - When used as uuid, it should be a unique UUID for this particular implementation. -typedef struct effect_uuid_s { - uint32_t timeLow; - uint16_t timeMid; - uint16_t timeHiAndVersion; - uint16_t clockSeq; - uint8_t node[6]; -} effect_uuid_t; - -// NULL UUID definition (matches SL_IID_NULL_) -#define EFFECT_UUID_INITIALIZER { 0xec7178ec, 0xe5e1, 0x4432, 0xa3f4, \ - { 0x46, 0x57, 0xe6, 0x79, 0x52, 0x10 } } -static const effect_uuid_t EFFECT_UUID_NULL_ = EFFECT_UUID_INITIALIZER; -const effect_uuid_t * const EFFECT_UUID_NULL = &EFFECT_UUID_NULL_; -const char * const EFFECT_UUID_NULL_STR = "ec7178ec-e5e1-4432-a3f4-4657e6795210"; - -// The effect descriptor contains necessary information to facilitate the enumeration of the effect -// engines present in a library. -typedef struct effect_descriptor_s { - effect_uuid_t type; // UUID of to the OpenSL ES interface implemented by this effect - effect_uuid_t uuid; // UUID for this particular implementation - uint16_t apiVersion; // Version of the effect API implemented: matches EFFECT_API_VERSION - uint32_t flags; // effect engine capabilities/requirements flags (see below) - uint16_t cpuLoad; // CPU load indication (see below) - uint16_t memoryUsage; // Data Memory usage (see below) - char name[EFFECT_STRING_LEN_MAX]; // human readable effect name - char implementor[EFFECT_STRING_LEN_MAX]; // human readable effect implementor name -} effect_descriptor_t; - -// CPU load and memory usage indication: each effect implementation must provide an indication of -// its CPU and memory usage for the audio effect framework to limit the number of effects -// instantiated at a given time on a given platform. -// The CPU load is expressed in 0.1 MIPS units as estimated on an ARM9E core (ARMv5TE) with 0 WS. -// The memory usage is expressed in KB and includes only dynamically allocated memory - -// Definitions for flags field of effect descriptor. -// +---------------------------+-----------+----------------------------------- -// | description | bits | values -// +---------------------------+-----------+----------------------------------- -// | connection mode | 0..1 | 0 insert: after track process -// | | | 1 auxiliary: connect to track auxiliary -// | | | output and use send level -// | | | 2 replace: replaces track process function; -// | | | must implement SRC, volume and mono to stereo. -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | insertion preference | 2..4 | 0 none -// | | | 1 first of the chain -// | | | 2 last of the chain -// | | | 3 exclusive (only effect in the insert chain) -// | | | 4..7 reserved -// +---------------------------+-----------+----------------------------------- -// | Volume management | 5..6 | 0 none -// | | | 1 implements volume control -// | | | 2 requires volume indication -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | Device indication | 7..8 | 0 none -// | | | 1 requires device updates -// | | | 2..3 reserved -// +---------------------------+-----------+----------------------------------- -// | Sample input mode | 9..10 | 0 direct: process() function or EFFECT_CMD_CONFIGURE -// | | | command must specify a buffer descriptor -// | | | 1 provider: process() function uses the -// | | | bufferProvider indicated by the -// | | | EFFECT_CMD_CONFIGURE command to request input. -// | | | buffers. -// | | | 2 both: both input modes are supported -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | Sample output mode | 11..12 | 0 direct: process() function or EFFECT_CMD_CONFIGURE -// | | | command must specify a buffer descriptor -// | | | 1 provider: process() function uses the -// | | | bufferProvider indicated by the -// | | | EFFECT_CMD_CONFIGURE command to request output -// | | | buffers. -// | | | 2 both: both output modes are supported -// | | | 3 reserved -// +---------------------------+-----------+----------------------------------- -// | Hardware acceleration | 13..15 | 0 No hardware acceleration -// | | | 1 non tunneled hw acceleration: the process() function -// | | | reads the samples, send them to HW accelerated -// | | | effect processor, reads back the processed samples -// | | | and returns them to the output buffer. -// | | | 2 tunneled hw acceleration: the process() function is -// | | | transparent. The effect interface is only used to -// | | | control the effect engine. This mode is relevant for -// | | | global effects actually applied by the audio -// | | | hardware on the output stream. -// +---------------------------+-----------+----------------------------------- -// | Audio Mode indication | 16..17 | 0 none -// | | | 1 requires audio mode updates -// | | | 2..3 reserved -// +---------------------------+-----------+----------------------------------- - -// Insert mode -#define EFFECT_FLAG_TYPE_MASK 0x00000003 -#define EFFECT_FLAG_TYPE_INSERT 0x00000000 -#define EFFECT_FLAG_TYPE_AUXILIARY 0x00000001 -#define EFFECT_FLAG_TYPE_REPLACE 0x00000002 - -// Insert preference -#define EFFECT_FLAG_INSERT_MASK 0x0000001C -#define EFFECT_FLAG_INSERT_ANY 0x00000000 -#define EFFECT_FLAG_INSERT_FIRST 0x00000004 -#define EFFECT_FLAG_INSERT_LAST 0x00000008 -#define EFFECT_FLAG_INSERT_EXCLUSIVE 0x0000000C - - -// Volume control -#define EFFECT_FLAG_VOLUME_MASK 0x00000060 -#define EFFECT_FLAG_VOLUME_CTRL 0x00000020 -#define EFFECT_FLAG_VOLUME_IND 0x00000040 -#define EFFECT_FLAG_VOLUME_NONE 0x00000000 - -// Device indication -#define EFFECT_FLAG_DEVICE_MASK 0x00000180 -#define EFFECT_FLAG_DEVICE_IND 0x00000080 -#define EFFECT_FLAG_DEVICE_NONE 0x00000000 - -// Sample input modes -#define EFFECT_FLAG_INPUT_MASK 0x00000600 -#define EFFECT_FLAG_INPUT_DIRECT 0x00000000 -#define EFFECT_FLAG_INPUT_PROVIDER 0x00000200 -#define EFFECT_FLAG_INPUT_BOTH 0x00000400 - -// Sample output modes -#define EFFECT_FLAG_OUTPUT_MASK 0x00001800 -#define EFFECT_FLAG_OUTPUT_DIRECT 0x00000000 -#define EFFECT_FLAG_OUTPUT_PROVIDER 0x00000800 -#define EFFECT_FLAG_OUTPUT_BOTH 0x00001000 - -// Hardware acceleration mode -#define EFFECT_FLAG_HW_ACC_MASK 0x00006000 -#define EFFECT_FLAG_HW_ACC_SIMPLE 0x00002000 -#define EFFECT_FLAG_HW_ACC_TUNNEL 0x00004000 - -// Audio mode indication -#define EFFECT_FLAG_AUDIO_MODE_MASK 0x00018000 -#define EFFECT_FLAG_AUDIO_MODE_IND 0x00008000 -#define EFFECT_FLAG_AUDIO_MODE_NONE 0x00000000 - -// Forward definition of type audio_buffer_t -typedef struct audio_buffer_s audio_buffer_t; - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: process -// -// Description: Effect process function. Takes input samples as specified -// (count and location) in input buffer descriptor and output processed -// samples as specified in output buffer descriptor. If the buffer descriptor -// is not specified the function must use either the buffer or the -// buffer provider function installed by the EFFECT_CMD_CONFIGURE command. -// The effect framework will call the process() function after the EFFECT_CMD_ENABLE -// command is received and until the EFFECT_CMD_DISABLE is received. When the engine -// receives the EFFECT_CMD_DISABLE command it should turn off the effect gracefully -// and when done indicate that it is OK to stop calling the process() function by -// returning the -ENODATA status. -// -// NOTE: the process() function implementation should be "real-time safe" that is -// it should not perform blocking calls: malloc/free, sleep, read/write/open/close, -// pthread_cond_wait/pthread_mutex_lock... -// -// Input: -// effect_interface_t: handle to the effect interface this function -// is called on. -// inBuffer: buffer descriptor indicating where to read samples to process. -// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command. -// -// inBuffer: buffer descriptor indicating where to write processed samples. -// If NULL, use the configuration passed by EFFECT_CMD_CONFIGURE command. -// -// Output: -// returned value: 0 successful operation -// -ENODATA the engine has finished the disable phase and the framework -// can stop calling process() -// -EINVAL invalid interface handle or -// invalid input/output buffer description -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_process_t)(effect_interface_t self, - audio_buffer_t *inBuffer, - audio_buffer_t *outBuffer); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: command -// -// Description: Send a command and receive a response to/from effect engine. -// -// Input: -// effect_interface_t: handle to the effect interface this function -// is called on. -// cmdCode: command code: the command can be a standardized command defined in -// effect_command_e (see below) or a proprietary command. -// cmdSize: size of command in bytes -// pCmdData: pointer to command data -// pReplyData: pointer to reply data -// -// Input/Output: -// replySize: maximum size of reply data as input -// actual size of reply data as output -// -// Output: -// returned value: 0 successful operation -// -EINVAL invalid interface handle or -// invalid command/reply size or format according to command code -// The return code should be restricted to indicate problems related to the this -// API specification. Status related to the execution of a particular command should be -// indicated as part of the reply field. -// -// *pReplyData updated with command response -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_command_t)(effect_interface_t self, - uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *replySize, - void *pReplyData); - - -// Effect control interface definition -struct effect_interface_s { - effect_process_t process; - effect_command_t command; -}; - - -// -//--- Standardized command codes for command() function -// -enum effect_command_e { - EFFECT_CMD_INIT, // initialize effect engine - EFFECT_CMD_CONFIGURE, // configure effect engine (see effect_config_t) - EFFECT_CMD_RESET, // reset effect engine - EFFECT_CMD_ENABLE, // enable effect process - EFFECT_CMD_DISABLE, // disable effect process - EFFECT_CMD_SET_PARAM, // set parameter immediately (see effect_param_t) - EFFECT_CMD_SET_PARAM_DEFERRED, // set parameter deferred - EFFECT_CMD_SET_PARAM_COMMIT, // commit previous set parameter deferred - EFFECT_CMD_GET_PARAM, // get parameter - EFFECT_CMD_SET_DEVICE, // set audio device (see audio_device_e) - EFFECT_CMD_SET_VOLUME, // set volume - EFFECT_CMD_SET_AUDIO_MODE, // set the audio mode (normal, ring, ...) - EFFECT_CMD_FIRST_PROPRIETARY = 0x10000 // first proprietary command code -}; - -//================================================================================================== -// command: EFFECT_CMD_INIT -//-------------------------------------------------------------------------------------------------- -// description: -// Initialize effect engine: All configurations return to default -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_CONFIGURE -//-------------------------------------------------------------------------------------------------- -// description: -// Apply new audio parameters configurations for input and output buffers -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_config_t) -// data: effect_config_t -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_RESET -//-------------------------------------------------------------------------------------------------- -// description: -// Reset the effect engine. Keep configuration but resets state and buffer content -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_ENABLE -//-------------------------------------------------------------------------------------------------- -// description: -// Enable the process. Called by the framework before the first call to process() -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_DISABLE -//-------------------------------------------------------------------------------------------------- -// description: -// Disable the process. Called by the framework after the last call to process() -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_SET_PARAM -//-------------------------------------------------------------------------------------------------- -// description: -// Set a parameter and apply it immediately -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_param_t) + size of param and value -// data: effect_param_t + param + value. See effect_param_t definition below for value offset -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_SET_PARAM_DEFERRED -//-------------------------------------------------------------------------------------------------- -// description: -// Set a parameter but apply it only when receiving EFFECT_CMD_SET_PARAM_COMMIT command -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_param_t) + size of param and value -// data: effect_param_t + param + value. See effect_param_t definition below for value offset -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_SET_PARAM_COMMIT -//-------------------------------------------------------------------------------------------------- -// description: -// Apply all previously received EFFECT_CMD_SET_PARAM_DEFERRED commands -//-------------------------------------------------------------------------------------------------- -// command format: -// size: 0 -// data: N/A -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(int) -// data: status -//================================================================================================== -// command: EFFECT_CMD_GET_PARAM -//-------------------------------------------------------------------------------------------------- -// description: -// Get a parameter value -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(effect_param_t) + size of param -// data: effect_param_t + param -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: sizeof(effect_param_t) + size of param and value -// data: effect_param_t + param + value. See effect_param_t definition below for value offset -//================================================================================================== -// command: EFFECT_CMD_SET_DEVICE -//-------------------------------------------------------------------------------------------------- -// description: -// Set the rendering device the audio output path is connected to. See audio_device_e for device -// values. -// The effect implementation must set EFFECT_FLAG_DEVICE_IND flag in its descriptor to receive this -// command when the device changes -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(uint32_t) -// data: audio_device_e -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_SET_VOLUME -//-------------------------------------------------------------------------------------------------- -// description: -// Set and get volume. Used by audio framework to delegate volume control to effect engine. -// The effect implementation must set EFFECT_FLAG_VOLUME_IND or EFFECT_FLAG_VOLUME_CTRL flag in -// its descriptor to receive this command before every call to process() function -// If EFFECT_FLAG_VOLUME_CTRL flag is set in the effect descriptor, the effect engine must return -// the volume that should be applied before the effect is processed. The overall volume (the volume -// actually applied by the effect engine multiplied by the returned value) should match the value -// indicated in the command. -//-------------------------------------------------------------------------------------------------- -// command format: -// size: n * sizeof(uint32_t) -// data: volume for each channel defined in effect_config_t for output buffer expressed in -// 8.24 fixed point format -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: n * sizeof(uint32_t) / 0 -// data: - if EFFECT_FLAG_VOLUME_CTRL is set in effect descriptor: -// volume for each channel defined in effect_config_t for output buffer expressed in -// 8.24 fixed point format -// - if EFFECT_FLAG_VOLUME_CTRL is not set in effect descriptor: -// N/A -// It is legal to receive a null pointer as pReplyData in which case the effect framework has -// delegated volume control to another effect -//================================================================================================== -// command: EFFECT_CMD_SET_AUDIO_MODE -//-------------------------------------------------------------------------------------------------- -// description: -// Set the audio mode. The effect implementation must set EFFECT_FLAG_AUDIO_MODE_IND flag in its -// descriptor to receive this command when the audio mode changes. -//-------------------------------------------------------------------------------------------------- -// command format: -// size: sizeof(uint32_t) -// data: audio_mode_e -//-------------------------------------------------------------------------------------------------- -// reply format: -// size: 0 -// data: N/A -//================================================================================================== -// command: EFFECT_CMD_FIRST_PROPRIETARY -//-------------------------------------------------------------------------------------------------- -// description: -// All proprietary effect commands must use command codes above this value. The size and format of -// command and response fields is free in this case -//================================================================================================== - - -// Audio buffer descriptor used by process(), bufferProvider() functions and buffer_config_t -// structure. Multi-channel audio is always interleaved. The channel order is from LSB to MSB with -// regard to the channel mask definition in audio_channels_e e.g : -// Stereo: left, right -// 5 point 1: front left, front right, front center, low frequency, back left, back right -// The buffer size is expressed in frame count, a frame being composed of samples for all -// channels at a given time. Frame size for unspecified format (AUDIO_FORMAT_OTHER) is 8 bit by -// definition -struct audio_buffer_s { - size_t frameCount; // number of frames in buffer - union { - void* raw; // raw pointer to start of buffer - int32_t* s32; // pointer to signed 32 bit data at start of buffer - int16_t* s16; // pointer to signed 16 bit data at start of buffer - uint8_t* u8; // pointer to unsigned 8 bit data at start of buffer - }; -}; - -// The buffer_provider_s structure contains functions that can be used -// by the effect engine process() function to query and release input -// or output audio buffer. -// The getBuffer() function is called to retrieve a buffer where data -// should read from or written to by process() function. -// The releaseBuffer() function MUST be called when the buffer retrieved -// with getBuffer() is not needed anymore. -// The process function should use the buffer provider mechanism to retrieve -// input or output buffer if the inBuffer or outBuffer passed as argument is NULL -// and the buffer configuration (buffer_config_t) given by the EFFECT_CMD_CONFIGURE -// command did not specify an audio buffer. - -typedef int32_t (* buffer_function_t)(void *cookie, audio_buffer_t *buffer); - -typedef struct buffer_provider_s { - buffer_function_t getBuffer; // retrieve next buffer - buffer_function_t releaseBuffer; // release used buffer - void *cookie; // for use by client of buffer provider functions -} buffer_provider_t; - - -// The buffer_config_s structure specifies the input or output audio format -// to be used by the effect engine. It is part of the effect_config_t -// structure that defines both input and output buffer configurations and is -// passed by the EFFECT_CMD_CONFIGURE command. -typedef struct buffer_config_s { - audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly - uint32_t samplingRate; // sampling rate - uint32_t channels; // channel mask (see audio_channels_e) - buffer_provider_t bufferProvider; // buffer provider - uint8_t format; // Audio format (see audio_format_e) - uint8_t accessMode; // read/write or accumulate in buffer (effect_buffer_access_e) - uint16_t mask; // indicates which of the above fields is valid -} buffer_config_t; - -// Sample format -enum audio_format_e { - SAMPLE_FORMAT_PCM_S15, // PCM signed 16 bits - SAMPLE_FORMAT_PCM_U8, // PCM unsigned 8 bits - SAMPLE_FORMAT_PCM_S7_24, // PCM signed 7.24 fixed point representation - SAMPLE_FORMAT_OTHER // other format (e.g. compressed) -}; - -// Channel mask -enum audio_channels_e { - CHANNEL_FRONT_LEFT = 0x1, // front left channel - CHANNEL_FRONT_RIGHT = 0x2, // front right channel - CHANNEL_FRONT_CENTER = 0x4, // front center channel - CHANNEL_LOW_FREQUENCY = 0x8, // low frequency channel - CHANNEL_BACK_LEFT = 0x10, // back left channel - CHANNEL_BACK_RIGHT = 0x20, // back right channel - CHANNEL_FRONT_LEFT_OF_CENTER = 0x40, // front left of center channel - CHANNEL_FRONT_RIGHT_OF_CENTER = 0x80, // front right of center channel - CHANNEL_BACK_CENTER = 0x100, // back center channel - CHANNEL_MONO = CHANNEL_FRONT_LEFT, - CHANNEL_STEREO = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT), - CHANNEL_QUAD = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT), - CHANNEL_SURROUND = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_FRONT_CENTER | CHANNEL_BACK_CENTER), - CHANNEL_5POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT), - CHANNEL_7POINT1 = (CHANNEL_FRONT_LEFT | CHANNEL_FRONT_RIGHT | - CHANNEL_FRONT_CENTER | CHANNEL_LOW_FREQUENCY | CHANNEL_BACK_LEFT | CHANNEL_BACK_RIGHT | - CHANNEL_FRONT_LEFT_OF_CENTER | CHANNEL_FRONT_RIGHT_OF_CENTER), -}; - -// Render device -enum audio_device_e { - DEVICE_EARPIECE = 0x1, // earpiece - DEVICE_SPEAKER = 0x2, // speaker - DEVICE_WIRED_HEADSET = 0x4, // wired headset, with microphone - DEVICE_WIRED_HEADPHONE = 0x8, // wired headphone, without microphone - DEVICE_BLUETOOTH_SCO = 0x10, // generic bluetooth SCO - DEVICE_BLUETOOTH_SCO_HEADSET = 0x20, // bluetooth SCO headset - DEVICE_BLUETOOTH_SCO_CARKIT = 0x40, // bluetooth SCO car kit - DEVICE_BLUETOOTH_A2DP = 0x80, // generic bluetooth A2DP - DEVICE_BLUETOOTH_A2DP_HEADPHONES = 0x100, // bluetooth A2DP headphones - DEVICE_BLUETOOTH_A2DP_SPEAKER = 0x200, // bluetooth A2DP speakers - DEVICE_AUX_DIGITAL = 0x400, // digital output - DEVICE_EXTERNAL_SPEAKER = 0x800 // external speaker (stereo and High quality) -}; - -#if ANDROID_VERSION < 17 -// Audio mode -enum audio_mode_e { - AUDIO_MODE_NORMAL, // device idle - AUDIO_MODE_RINGTONE, // device ringing - AUDIO_MODE_IN_CALL // audio call connected (VoIP or telephony) -}; -#endif - -// Values for "accessMode" field of buffer_config_t: -// overwrite, read only, accumulate (read/modify/write) -enum effect_buffer_access_e { - EFFECT_BUFFER_ACCESS_WRITE, - EFFECT_BUFFER_ACCESS_READ, - EFFECT_BUFFER_ACCESS_ACCUMULATE - -}; - -// Values for bit field "mask" in buffer_config_t. If a bit is set, the corresponding field -// in buffer_config_t must be taken into account when executing the EFFECT_CMD_CONFIGURE command -#define EFFECT_CONFIG_BUFFER 0x0001 // buffer field must be taken into account -#define EFFECT_CONFIG_SMP_RATE 0x0002 // samplingRate field must be taken into account -#define EFFECT_CONFIG_CHANNELS 0x0004 // channels field must be taken into account -#define EFFECT_CONFIG_FORMAT 0x0008 // format field must be taken into account -#define EFFECT_CONFIG_ACC_MODE 0x0010 // accessMode field must be taken into account -#define EFFECT_CONFIG_PROVIDER 0x0020 // bufferProvider field must be taken into account -#define EFFECT_CONFIG_ALL (EFFECT_CONFIG_BUFFER | EFFECT_CONFIG_SMP_RATE | \ - EFFECT_CONFIG_CHANNELS | EFFECT_CONFIG_FORMAT | \ - EFFECT_CONFIG_ACC_MODE | EFFECT_CONFIG_PROVIDER) - - -// effect_config_s structure describes the format of the pCmdData argument of EFFECT_CMD_CONFIGURE -// command to configure audio parameters and buffers for effect engine input and output. -typedef struct effect_config_s { - buffer_config_t inputCfg; - buffer_config_t outputCfg;; -} effect_config_t; - - -// effect_param_s structure describes the format of the pCmdData argument of EFFECT_CMD_SET_PARAM -// command and pCmdData and pReplyData of EFFECT_CMD_GET_PARAM command. -// psize and vsize represent the actual size of parameter and value. -// -// NOTE: the start of value field inside the data field is always on a 32 bit boundary: -// -// +-----------+ -// | status | sizeof(int) -// +-----------+ -// | psize | sizeof(int) -// +-----------+ -// | vsize | sizeof(int) -// +-----------+ -// | | | | -// ~ parameter ~ > psize | -// | | | > ((psize - 1)/sizeof(int) + 1) * sizeof(int) -// +-----------+ | -// | padding | | -// +-----------+ -// | | | -// ~ value ~ > vsize -// | | | -// +-----------+ - -typedef struct effect_param_s { - int32_t status; // Transaction status (unused for command, used for reply) - uint32_t psize; // Parameter size - uint32_t vsize; // Value size - char data[]; // Start of Parameter + Value data -} effect_param_t; - - -///////////////////////////////////////////////// -// Effect library interface -///////////////////////////////////////////////// - -// An effect library is required to implement and expose the following functions -// to enable effect enumeration and instantiation. The name of these functions must be as -// specified here as the effect framework will get the function address with dlsym(): -// -// - effect_QueryNumberEffects_t EffectQueryNumberEffects; -// - effect_QueryEffect_t EffectQueryEffect; -// - effect_CreateEffect_t EffectCreate; -// - effect_ReleaseEffect_t EffectRelease; - - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectQueryNumberEffects -// -// Description: Returns the number of different effects exposed by the -// library. Each effect must have a unique effect uuid (see -// effect_descriptor_t). This function together with EffectQueryEffect() -// is used to enumerate all effects present in the library. -// -// Input/Output: -// pNumEffects: address where the number of effects should be returned. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid pNumEffects -// *pNumEffects: updated with number of effects in library -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_QueryNumberEffects_t)(uint32_t *pNumEffects); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectQueryEffect -// -// Description: Returns the descriptor of the effect engine which index is -// given as first argument. -// See effect_descriptor_t for details on effect descriptors. -// This function together with EffectQueryNumberEffects() is used to enumerate all -// effects present in the library. The enumeration sequence is: -// EffectQueryNumberEffects(&num_effects); -// for (i = 0; i < num_effects; i++) -// EffectQueryEffect(i,...); -// -// Input/Output: -// index: index of the effect -// pDescriptor: address where to return the effect descriptor. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid pDescriptor or index -// -ENOSYS effect list has changed since last execution of -// EffectQueryNumberEffects() -// -ENOENT no more effect available -// *pDescriptor: updated with the effect descriptor. -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_QueryEffect_t)(uint32_t index, - effect_descriptor_t *pDescriptor); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectCreate -// -// Description: Creates an effect engine of the specified type and returns an -// effect control interface on this engine. The function will allocate the -// resources for an instance of the requested effect engine and return -// a handle on the effect control interface. -// -// Input: -// uuid: pointer to the effect uuid. -// sessionId: audio session to which this effect instance will be attached. All effects -// created with the same session ID are connected in series and process the same signal -// stream. Knowing that two effects are part of the same effect chain can help the -// library implement some kind of optimizations. -// ioId: identifies the output or input stream this effect is directed to at audio HAL. -// For future use especially with tunneled HW accelerated effects -// -// Input/Output: -// pInterface: address where to return the effect interface. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid pEffectUuid or pInterface -// -ENOENT no effect with this uuid found -// *pInterface: updated with the effect interface handle. -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_CreateEffect_t)(effect_uuid_t *uuid, - int32_t sessionId, - int32_t ioId, - effect_interface_t *pInterface); - -//////////////////////////////////////////////////////////////////////////////// -// -// Function: EffectRelease -// -// Description: Releases the effect engine whose handle is given as argument. -// All resources allocated to this particular instance of the effect are -// released. -// -// Input: -// interface: handle on the effect interface to be released. -// -// Output: -// returned value: 0 successful operation. -// -ENODEV library failed to initialize -// -EINVAL invalid interface handle -// -//////////////////////////////////////////////////////////////////////////////// -typedef int32_t (*effect_ReleaseEffect_t)(effect_interface_t interface); - - -#if __cplusplus -} // extern "C" -#endif - - -#endif /*ANDROID_EFFECTAPI_H_*/ diff --git a/dom/system/gonk/android_audio/IAudioFlinger.h b/dom/system/gonk/android_audio/IAudioFlinger.h deleted file mode 100644 index b10d3ab93..000000000 --- a/dom/system/gonk/android_audio/IAudioFlinger.h +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_IAUDIOFLINGER_H -#define ANDROID_IAUDIOFLINGER_H - -#include -#include -#include - -#include -#include -#include -#include "IAudioTrack.h" -#include "IAudioRecord.h" -#include "IAudioFlingerClient.h" -#include "EffectApi.h" -#include "IEffect.h" -#include "IEffectClient.h" -#include - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioFlinger : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioFlinger); - - /* create an audio track and registers it with AudioFlinger. - * return null if the track cannot be created. - */ - virtual sp createTrack( - pid_t pid, - int streamType, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - const sp& sharedBuffer, - int output, - int *sessionId, - status_t *status) = 0; - - virtual sp openRecord( - pid_t pid, - int input, - uint32_t sampleRate, - int format, - int channelCount, - int frameCount, - uint32_t flags, - int *sessionId, - status_t *status) = 0; - - /* query the audio hardware state. This state never changes, - * and therefore can be cached. - */ - virtual uint32_t sampleRate(int output) const = 0; - virtual int channelCount(int output) const = 0; - virtual int format(int output) const = 0; - virtual size_t frameCount(int output) const = 0; - virtual uint32_t latency(int output) const = 0; - - /* set/get the audio hardware state. This will probably be used by - * the preference panel, mostly. - */ - virtual status_t setMasterVolume(float value) = 0; - virtual status_t setMasterMute(bool muted) = 0; - - virtual float masterVolume() const = 0; - virtual bool masterMute() const = 0; - - /* set/get stream type state. This will probably be used by - * the preference panel, mostly. - */ - virtual status_t setStreamVolume(int stream, float value, int output) = 0; - virtual status_t setStreamMute(int stream, bool muted) = 0; - - virtual float streamVolume(int stream, int output) const = 0; - virtual bool streamMute(int stream) const = 0; - - // set audio mode - virtual status_t setMode(int mode) = 0; - - // mic mute/state - virtual status_t setMicMute(bool state) = 0; - virtual bool getMicMute() const = 0; - - // is any track active on this stream? - virtual bool isStreamActive(int stream) const = 0; - - virtual status_t setParameters(int ioHandle, const String8& keyValuePairs) = 0; - virtual String8 getParameters(int ioHandle, const String8& keys) = 0; - - // register a current process for audio output change notifications - virtual void registerClient(const sp& client) = 0; - - // retrieve the audio recording buffer size - virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount) = 0; - - virtual int openOutput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t *pLatencyMs, - uint32_t flags) = 0; - virtual int openDuplicateOutput(int output1, int output2) = 0; - virtual status_t closeOutput(int output) = 0; - virtual status_t suspendOutput(int output) = 0; - virtual status_t restoreOutput(int output) = 0; - - virtual int openInput(uint32_t *pDevices, - uint32_t *pSamplingRate, - uint32_t *pFormat, - uint32_t *pChannels, - uint32_t acoustics) = 0; - virtual status_t closeInput(int input) = 0; - - virtual status_t setStreamOutput(uint32_t stream, int output) = 0; - - virtual status_t setVoiceVolume(float volume) = 0; - - virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0; - - virtual unsigned int getInputFramesLost(int ioHandle) = 0; - - virtual int newAudioSessionId() = 0; - - virtual status_t loadEffectLibrary(const char *libPath, int *handle) = 0; - - virtual status_t unloadEffectLibrary(int handle) = 0; - - virtual status_t queryNumberEffects(uint32_t *numEffects) = 0; - - virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) = 0; - - virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0; - - virtual sp createEffect(pid_t pid, - effect_descriptor_t *pDesc, - const sp& client, - int32_t priority, - int output, - int sessionId, - status_t *status, - int *id, - int *enabled) = 0; - - virtual status_t moveEffects(int session, int srcOutput, int dstOutput) = 0; -}; - - -// ---------------------------------------------------------------------------- - -class BnAudioFlinger : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IAUDIOFLINGER_H diff --git a/dom/system/gonk/android_audio/IAudioFlingerClient.h b/dom/system/gonk/android_audio/IAudioFlingerClient.h deleted file mode 100644 index aa0cdcff1..000000000 --- a/dom/system/gonk/android_audio/IAudioFlingerClient.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2009 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. - */ - -#ifndef ANDROID_IAUDIOFLINGERCLIENT_H -#define ANDROID_IAUDIOFLINGERCLIENT_H - - -#include -#include -#include - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioFlingerClient : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioFlingerClient); - - // Notifies a change of audio input/output configuration. - virtual void ioConfigChanged(int event, int ioHandle, void *param2) = 0; - -}; - - -// ---------------------------------------------------------------------------- - -class BnAudioFlingerClient : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IAUDIOFLINGERCLIENT_H diff --git a/dom/system/gonk/android_audio/IAudioRecord.h b/dom/system/gonk/android_audio/IAudioRecord.h deleted file mode 100644 index 46735def2..000000000 --- a/dom/system/gonk/android_audio/IAudioRecord.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef IAUDIORECORD_H_ -#define IAUDIORECORD_H_ - -#include -#include - -#include -#include -#include -#include - - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioRecord : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioRecord); - - /* After it's created the track is not active. Call start() to - * make it active. If set, the callback will start being called. - */ - virtual status_t start() = 0; - - /* Stop a track. If set, the callback will cease being called and - * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. - */ - virtual void stop() = 0; - - /* get this tracks control block */ - virtual sp getCblk() const = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnAudioRecord : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif /*IAUDIORECORD_H_*/ diff --git a/dom/system/gonk/android_audio/IAudioTrack.h b/dom/system/gonk/android_audio/IAudioTrack.h deleted file mode 100644 index 47d530be5..000000000 --- a/dom/system/gonk/android_audio/IAudioTrack.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_IAUDIOTRACK_H -#define ANDROID_IAUDIOTRACK_H - -#include -#include - -#include -#include -#include -#include - - -namespace android { - -// ---------------------------------------------------------------------------- - -class IAudioTrack : public IInterface -{ -public: - DECLARE_META_INTERFACE(AudioTrack); - - /* After it's created the track is not active. Call start() to - * make it active. If set, the callback will start being called. - */ - virtual status_t start() = 0; - - /* Stop a track. If set, the callback will cease being called and - * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. - */ - virtual void stop() = 0; - - /* flush a stopped track. All pending buffers are discarded. - * This function has no effect if the track is not stoped. - */ - virtual void flush() = 0; - - /* mute or unmutes this track. - * While mutted, the callback, if set, is still called. - */ - virtual void mute(bool) = 0; - - /* Pause a track. If set, the callback will cease being called and - * obtainBuffer will return an error. Buffers that are already released - * will be processed, unless flush() is called. - */ - virtual void pause() = 0; - - /* Attach track auxiliary output to specified effect. Use effectId = 0 - * to detach track from effect. - */ - virtual status_t attachAuxEffect(int effectId) = 0; - - /* get this tracks control block */ - virtual sp getCblk() const = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnAudioTrack : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- - -}; // namespace android - -#endif // ANDROID_IAUDIOTRACK_H diff --git a/dom/system/gonk/android_audio/IEffect.h b/dom/system/gonk/android_audio/IEffect.h deleted file mode 100644 index ff04869e0..000000000 --- a/dom/system/gonk/android_audio/IEffect.h +++ /dev/null @@ -1,60 +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. - */ - -#ifndef ANDROID_IEFFECT_H -#define ANDROID_IEFFECT_H - -#include -#include -#include -#include - -namespace android { - -class IEffect: public IInterface -{ -public: - DECLARE_META_INTERFACE(Effect); - - virtual status_t enable() = 0; - - virtual status_t disable() = 0; - - virtual status_t command(uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t *pReplySize, - void *pReplyData) = 0; - - virtual void disconnect() = 0; - - virtual sp getCblk() const = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnEffect: public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -}; // namespace android - -#endif // ANDROID_IEFFECT_H diff --git a/dom/system/gonk/android_audio/IEffectClient.h b/dom/system/gonk/android_audio/IEffectClient.h deleted file mode 100644 index 2f78c98f1..000000000 --- a/dom/system/gonk/android_audio/IEffectClient.h +++ /dev/null @@ -1,54 +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. - */ - -#ifndef ANDROID_IEFFECTCLIENT_H -#define ANDROID_IEFFECTCLIENT_H - -#include -#include -#include -#include - -namespace android { - -class IEffectClient: public IInterface -{ -public: - DECLARE_META_INTERFACE(EffectClient); - - virtual void controlStatusChanged(bool controlGranted) = 0; - virtual void enableStatusChanged(bool enabled) = 0; - virtual void commandExecuted(uint32_t cmdCode, - uint32_t cmdSize, - void *pCmdData, - uint32_t replySize, - void *pReplyData) = 0; -}; - -// ---------------------------------------------------------------------------- - -class BnEffectClient: public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -}; // namespace android - -#endif // ANDROID_IEFFECTCLIENT_H diff --git a/dom/system/gonk/moz.build b/dom/system/gonk/moz.build deleted file mode 100644 index 229baaab4..000000000 --- a/dom/system/gonk/moz.build +++ /dev/null @@ -1,107 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -XPIDL_SOURCES += [ - 'nsIAudioManager.idl', - 'nsINetworkInterface.idl', - 'nsINetworkInterfaceListService.idl', - 'nsINetworkManager.idl', - 'nsINetworkService.idl', - 'nsINetworkWorker.idl', - 'nsISystemWorkerManager.idl', - 'nsITetheringService.idl', - 'nsIVolume.idl', - 'nsIVolumeMountLock.idl', - 'nsIVolumeService.idl', - 'nsIVolumeStat.idl', - 'nsIWorkerHolder.idl', -] - -XPIDL_MODULE = 'dom_system_gonk' - -EXPORTS += [ - 'GeolocationUtil.h', - 'GonkGPSGeolocationProvider.h', - 'nsVolume.h', - 'nsVolumeService.h', - 'SystemProperty.h', -] -UNIFIED_SOURCES += [ - 'AudioChannelManager.cpp', - 'AudioManager.cpp', - 'AutoMounter.cpp', - 'AutoMounterSetting.cpp', - 'GeolocationUtil.cpp', - 'GonkGPSGeolocationProvider.cpp', - 'MozMtpDatabase.cpp', - 'MozMtpServer.cpp', - 'MozMtpStorage.cpp', - 'NetIdManager.cpp', - 'NetworkUtils.cpp', - 'NetworkWorker.cpp', - 'nsVolume.cpp', - 'nsVolumeMountLock.cpp', - 'nsVolumeService.cpp', - 'nsVolumeStat.cpp', - 'OpenFileFinder.cpp', - 'SystemProperty.cpp', - 'SystemWorkerManager.cpp', - 'TimeZoneSettingObserver.cpp', - 'Volume.cpp', - 'VolumeCommand.cpp', - 'VolumeManager.cpp', - 'VolumeServiceIOThread.cpp', - 'VolumeServiceTest.cpp', -] - -if CONFIG['ANDROID_VERSION'] >= '17': - LOCAL_INCLUDES += ['%' + '%s/frameworks/av/media/mtp' % CONFIG['ANDROID_SOURCE']] -else: - LOCAL_INCLUDES += ['%' + '%s/frameworks/base/media/mtp' % CONFIG['ANDROID_SOURCE']] - -if CONFIG['ENABLE_TESTS']: - XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini'] - -EXTRA_COMPONENTS += [ - 'NetworkInterfaceListService.js', - 'NetworkInterfaceListService.manifest', - 'NetworkManager.js', - 'NetworkManager.manifest', - 'NetworkService.js', - 'NetworkService.manifest', - 'TetheringService.js', - 'TetheringService.manifest', -] -EXTRA_JS_MODULES += [ - 'systemlibs.js', -] - -include('/ipc/chromium/chromium-config.mozbuild') - -DEFINES['HAVE_ANDROID_OS'] = True - -LOCAL_INCLUDES += [ - '/dom/base', - '/dom/bluetooth/common', - '/dom/geolocation', - '/dom/wifi', -] - -FINAL_LIBRARY = 'xul' - -FINAL_TARGET_FILES.modules.workers += [ - 'worker_buf.js', -] diff --git a/dom/system/gonk/mozstumbler/MozStumbler.cpp b/dom/system/gonk/mozstumbler/MozStumbler.cpp deleted file mode 100644 index 61e09e705..000000000 --- a/dom/system/gonk/mozstumbler/MozStumbler.cpp +++ /dev/null @@ -1,426 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "MozStumbler.h" -#include "nsDataHashtable.h" -#include "nsGeoPosition.h" -#include "nsNetCID.h" -#include "nsPrintfCString.h" -#include "StumblerLogging.h" -#include "WriteStumbleOnThread.h" -#include "../GeolocationUtil.h" - -#include "nsIInterfaceRequestor.h" -#include "nsIInterfaceRequestorUtils.h" -#include "nsIMobileConnectionInfo.h" -#include "nsIMobileConnectionService.h" -#include "nsIMobileCellInfo.h" -#include "nsIMobileNetworkInfo.h" -#include "nsINetworkInterface.h" -#include "nsIRadioInterfaceLayer.h" - -using namespace mozilla; -using namespace mozilla::dom; - - -NS_IMPL_ISUPPORTS(StumblerInfo, nsICellInfoListCallback, nsIWifiScanResultsReady) - -class RequestCellInfoEvent : public Runnable { -public: - RequestCellInfoEvent(StumblerInfo *callback) - : mRequestCallback(callback) - {} - - NS_IMETHOD Run() override { - MOZ_ASSERT(NS_IsMainThread()); - // Get Cell Info - nsCOMPtr service = - do_GetService(NS_MOBILE_CONNECTION_SERVICE_CONTRACTID); - - if (!service) { - STUMBLER_ERR("Stumbler-can not get nsIMobileConnectionService \n"); - return NS_OK; - } - nsCOMPtr connection; - uint32_t numberOfRilServices = 1, cellInfoNum = 0; - - service->GetNumItems(&numberOfRilServices); - for (uint32_t rilNum = 0; rilNum < numberOfRilServices; rilNum++) { - service->GetItemByServiceId(rilNum /* Client Id */, getter_AddRefs(connection)); - if (!connection) { - STUMBLER_ERR("Stumbler-can not get nsIMobileConnection by ServiceId %d \n", rilNum); - } else { - cellInfoNum++; - connection->GetCellInfoList(mRequestCallback); - } - } - mRequestCallback->SetCellInfoResponsesExpected(cellInfoNum); - - // Get Wifi AP Info - nsCOMPtr ir = do_GetService("@mozilla.org/telephony/system-worker-manager;1"); - nsCOMPtr wifi = do_GetInterface(ir); - if (!wifi) { - mRequestCallback->SetWifiInfoResponseReceived(); - STUMBLER_ERR("Stumbler-can not get nsIWifi interface\n"); - return NS_OK; - } - wifi->GetWifiScanResults(mRequestCallback); - return NS_OK; - } -private: - RefPtr mRequestCallback; -}; - -void -MozStumble(nsGeoPosition* position) -{ - if (WriteStumbleOnThread::IsFileWaitingForUpload()) { - nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(target); - // Knowing that file is waiting to upload, and no collection will take place, - // just trigger the thread with an empty string. - nsCOMPtr event = new WriteStumbleOnThread(EmptyCString()); - target->Dispatch(event, NS_DISPATCH_NORMAL); - return; - } - - nsCOMPtr coords; - position->GetCoords(getter_AddRefs(coords)); - if (!coords) { - return; - } - - double latitude, longitude; - coords->GetLatitude(&latitude); - coords->GetLongitude(&longitude); - - const double kMinChangeInMeters = 30; - static int64_t lastTime_ms = 0; - static double sLastLat = 0; - static double sLastLon = 0; - double delta = -1.0; - int64_t timediff = (PR_Now() / PR_USEC_PER_MSEC) - lastTime_ms; - - if (0 != sLastLon || 0 != sLastLat) { - delta = CalculateDeltaInMeter(latitude, longitude, sLastLat, sLastLon); - } - STUMBLER_DBG("Stumbler-Location. [%f , %f] time_diff:%lld, delta : %f\n", - longitude, latitude, timediff, delta); - - // Consecutive GPS locations must be 30 meters and 3 seconds apart - if (lastTime_ms == 0 || ((timediff >= STUMBLE_INTERVAL_MS) && (delta > kMinChangeInMeters))){ - lastTime_ms = (PR_Now() / PR_USEC_PER_MSEC); - sLastLat = latitude; - sLastLon = longitude; - RefPtr requestCallback = new StumblerInfo(position); - RefPtr runnable = new RequestCellInfoEvent(requestCallback); - NS_DispatchToMainThread(runnable); - } else { - STUMBLER_DBG("Stumbler-GPS locations less than 30 meters and 3 seconds. Ignore!\n"); - } -} - -void -StumblerInfo::SetWifiInfoResponseReceived() -{ - mIsWifiInfoResponseReceived = true; - - if (mIsWifiInfoResponseReceived && mCellInfoResponsesReceived == mCellInfoResponsesExpected) { - STUMBLER_DBG("Call DumpStumblerInfo from SetWifiInfoResponseReceived\n"); - DumpStumblerInfo(); - } -} - -void -StumblerInfo::SetCellInfoResponsesExpected(uint8_t count) -{ - mCellInfoResponsesExpected = count; - STUMBLER_DBG("SetCellInfoNum (%d)\n", count); - - if (mIsWifiInfoResponseReceived && mCellInfoResponsesReceived == mCellInfoResponsesExpected) { - STUMBLER_DBG("Call DumpStumblerInfo from SetCellInfoResponsesExpected\n"); - DumpStumblerInfo(); - } -} - - -#define TEXT_LAT NS_LITERAL_CSTRING("latitude") -#define TEXT_LON NS_LITERAL_CSTRING("longitude") -#define TEXT_ACC NS_LITERAL_CSTRING("accuracy") -#define TEXT_ALT NS_LITERAL_CSTRING("altitude") -#define TEXT_ALTACC NS_LITERAL_CSTRING("altitudeAccuracy") -#define TEXT_HEAD NS_LITERAL_CSTRING("heading") -#define TEXT_SPD NS_LITERAL_CSTRING("speed") - -nsresult -StumblerInfo::LocationInfoToString(nsACString& aLocDesc) -{ - nsCOMPtr coords; - mPosition->GetCoords(getter_AddRefs(coords)); - if (!coords) { - return NS_ERROR_FAILURE; - } - - nsDataHashtable info; - - double val; - coords->GetLatitude(&val); - info.Put(TEXT_LAT, val); - coords->GetLongitude(&val); - info.Put(TEXT_LON, val); - coords->GetAccuracy(&val); - info.Put(TEXT_ACC, val); - coords->GetAltitude(&val); - info.Put(TEXT_ALT, val); - coords->GetAltitudeAccuracy(&val); - info.Put(TEXT_ALTACC, val); - coords->GetHeading(&val); - info.Put(TEXT_HEAD, val); - coords->GetSpeed(&val); - info.Put(TEXT_SPD, val); - - for (auto it = info.Iter(); !it.Done(); it.Next()) { - const nsACString& key = it.Key(); - val = it.UserData(); - if (!IsNaN(val)) { - aLocDesc += nsPrintfCString("\"%s\":%f,", key.BeginReading(), val); - } - } - - aLocDesc += nsPrintfCString("\"timestamp\":%lld,", PR_Now() / PR_USEC_PER_MSEC).get(); - return NS_OK; -} - -#define TEXT_RADIOTYPE NS_LITERAL_CSTRING("radioType") -#define TEXT_MCC NS_LITERAL_CSTRING("mobileCountryCode") -#define TEXT_MNC NS_LITERAL_CSTRING("mobileNetworkCode") -#define TEXT_LAC NS_LITERAL_CSTRING("locationAreaCode") -#define TEXT_CID NS_LITERAL_CSTRING("cellId") -#define TEXT_PSC NS_LITERAL_CSTRING("psc") -#define TEXT_STRENGTH_ASU NS_LITERAL_CSTRING("asu") -#define TEXT_STRENGTH_DBM NS_LITERAL_CSTRING("signalStrength") -#define TEXT_REGISTERED NS_LITERAL_CSTRING("serving") -#define TEXT_TIMEING_ADVANCE NS_LITERAL_CSTRING("timingAdvance") - -template void -ExtractCommonNonCDMACellInfoItems(nsCOMPtr& cell, nsDataHashtable& info) -{ - int32_t mcc, mnc, cid, sig; - - cell->GetMcc(&mcc); - cell->GetMnc(&mnc); - cell->GetCid(&cid); - cell->GetSignalStrength(&sig); - - info.Put(TEXT_MCC, mcc); - info.Put(TEXT_MNC, mnc); - info.Put(TEXT_CID, cid); - info.Put(TEXT_STRENGTH_ASU, sig); -} - -void -StumblerInfo::CellNetworkInfoToString(nsACString& aCellDesc) -{ - aCellDesc += "\"cellTowers\": ["; - - for (uint32_t idx = 0; idx < mCellInfo.Length() ; idx++) { - const char* radioType = 0; - int32_t type; - mCellInfo[idx]->GetType(&type); - bool registered; - mCellInfo[idx]->GetRegistered(®istered); - if (idx) { - aCellDesc += ",{"; - } else { - aCellDesc += "{"; - } - - STUMBLER_DBG("type=%d\n", type); - - nsDataHashtable info; - info.Put(TEXT_REGISTERED, registered); - - if(type == nsICellInfo::CELL_INFO_TYPE_GSM) { - radioType = "gsm"; - nsCOMPtr gsmCellInfo = do_QueryInterface(mCellInfo[idx]); - ExtractCommonNonCDMACellInfoItems(gsmCellInfo, info); - int32_t lac; - gsmCellInfo->GetLac(&lac); - info.Put(TEXT_LAC, lac); - } else if (type == nsICellInfo::CELL_INFO_TYPE_WCDMA) { - radioType = "wcdma"; - nsCOMPtr wcdmaCellInfo = do_QueryInterface(mCellInfo[idx]); - ExtractCommonNonCDMACellInfoItems(wcdmaCellInfo, info); - int32_t lac, psc; - wcdmaCellInfo->GetLac(&lac); - wcdmaCellInfo->GetPsc(&psc); - info.Put(TEXT_LAC, lac); - info.Put(TEXT_PSC, psc); - } else if (type == nsICellInfo::CELL_INFO_TYPE_CDMA) { - radioType = "cdma"; - nsCOMPtr cdmaCellInfo = do_QueryInterface(mCellInfo[idx]); - int32_t mnc, lac, cid, sig; - cdmaCellInfo->GetSystemId(&mnc); - cdmaCellInfo->GetNetworkId(&lac); - cdmaCellInfo->GetBaseStationId(&cid); - info.Put(TEXT_MNC, mnc); - info.Put(TEXT_LAC, lac); - info.Put(TEXT_CID, cid); - - cdmaCellInfo->GetEvdoDbm(&sig); - if (sig < 0 || sig == nsICellInfo::UNKNOWN_VALUE) { - cdmaCellInfo->GetCdmaDbm(&sig); - } - if (sig > -1 && sig != nsICellInfo::UNKNOWN_VALUE) { - sig *= -1; - info.Put(TEXT_STRENGTH_DBM, sig); - } - } else if (type == nsICellInfo::CELL_INFO_TYPE_LTE) { - radioType = "lte"; - nsCOMPtr lteCellInfo = do_QueryInterface(mCellInfo[idx]); - ExtractCommonNonCDMACellInfoItems(lteCellInfo, info); - int32_t lac, timingAdvance, pcid, rsrp; - lteCellInfo->GetTac(&lac); - lteCellInfo->GetTimingAdvance(&timingAdvance); - lteCellInfo->GetPcid(&pcid); - lteCellInfo->GetRsrp(&rsrp); - info.Put(TEXT_LAC, lac); - info.Put(TEXT_TIMEING_ADVANCE, timingAdvance); - info.Put(TEXT_PSC, pcid); - if (rsrp != nsICellInfo::UNKNOWN_VALUE) { - info.Put(TEXT_STRENGTH_DBM, rsrp * -1); - } - } - - aCellDesc += nsPrintfCString("\"%s\":\"%s\"", TEXT_RADIOTYPE.get(), radioType); - for (auto it = info.Iter(); !it.Done(); it.Next()) { - const nsACString& key = it.Key(); - int32_t value = it.UserData(); - if (value != nsICellInfo::UNKNOWN_VALUE) { - aCellDesc += nsPrintfCString(",\"%s\":%d", key.BeginReading(), value); - } - } - - aCellDesc += "}"; - } - aCellDesc += "]"; -} - -void -StumblerInfo::DumpStumblerInfo() -{ - if (!mIsWifiInfoResponseReceived || mCellInfoResponsesReceived != mCellInfoResponsesExpected) { - STUMBLER_DBG("CellInfoReceived=%d (Expected=%d), WifiInfoResponseReceived=%d\n", - mCellInfoResponsesReceived, mCellInfoResponsesExpected, mIsWifiInfoResponseReceived); - return; - } - mIsWifiInfoResponseReceived = false; - mCellInfoResponsesReceived = 0; - - nsAutoCString desc; - nsresult rv = LocationInfoToString(desc); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("LocationInfoToString failed, skip this dump"); - return; - } - - CellNetworkInfoToString(desc); - desc += mWifiDesc; - - STUMBLER_DBG("dispatch write event to thread\n"); - nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(target); - - nsCOMPtr event = new WriteStumbleOnThread(desc); - target->Dispatch(event, NS_DISPATCH_NORMAL); -} - -NS_IMETHODIMP -StumblerInfo::NotifyGetCellInfoList(uint32_t count, nsICellInfo** aCellInfos) -{ - MOZ_ASSERT(NS_IsMainThread()); - STUMBLER_DBG("There are %d cellinfo in the result\n", count); - - for (uint32_t i = 0; i < count; i++) { - mCellInfo.AppendElement(aCellInfos[i]); - } - mCellInfoResponsesReceived++; - DumpStumblerInfo(); - return NS_OK; -} - -NS_IMETHODIMP StumblerInfo::NotifyGetCellInfoListFailed(const nsAString& error) -{ - MOZ_ASSERT(NS_IsMainThread()); - mCellInfoResponsesReceived++; - STUMBLER_ERR("NotifyGetCellInfoListFailedm CellInfoReadyNum=%d, mCellInfoResponsesExpected=%d, mIsWifiInfoResponseReceived=%d", - mCellInfoResponsesReceived, mCellInfoResponsesExpected, mIsWifiInfoResponseReceived); - DumpStumblerInfo(); - return NS_OK; -} - -NS_IMETHODIMP -StumblerInfo::Onready(uint32_t count, nsIWifiScanResult** results) -{ - MOZ_ASSERT(NS_IsMainThread()); - STUMBLER_DBG("There are %d wifiAPinfo in the result\n",count); - - mWifiDesc += ",\"wifiAccessPoints\": ["; - bool firstItem = true; - for (uint32_t i = 0 ; i < count ; i++) { - nsString ssid; - results[i]->GetSsid(ssid); - if (ssid.IsEmpty()) { - STUMBLER_DBG("no ssid, skip this AP\n"); - continue; - } - - if (ssid.Length() >= 6) { - if (StringEndsWith(ssid, NS_LITERAL_STRING("_nomap"))) { - STUMBLER_DBG("end with _nomap. skip this AP(ssid :%s)\n", ssid.get()); - continue; - } - } - - if (firstItem) { - mWifiDesc += "{"; - firstItem = false; - } else { - mWifiDesc += ",{"; - } - - // mac address - nsString bssid; - results[i]->GetBssid(bssid); - // 00:00:00:00:00:00 --> 000000000000 - bssid.StripChars(":"); - mWifiDesc += "\"macAddress\":\""; - mWifiDesc += NS_ConvertUTF16toUTF8(bssid); - - uint32_t signal; - results[i]->GetSignalStrength(&signal); - mWifiDesc += "\",\"signalStrength\":"; - mWifiDesc.AppendInt(signal); - - mWifiDesc += "}"; - } - mWifiDesc += "]"; - - mIsWifiInfoResponseReceived = true; - DumpStumblerInfo(); - return NS_OK; -} - -NS_IMETHODIMP -StumblerInfo::Onfailure() -{ - MOZ_ASSERT(NS_IsMainThread()); - STUMBLER_ERR("GetWifiScanResults Onfailure\n"); - mIsWifiInfoResponseReceived = true; - DumpStumblerInfo(); - return NS_OK; -} - diff --git a/dom/system/gonk/mozstumbler/MozStumbler.h b/dom/system/gonk/mozstumbler/MozStumbler.h deleted file mode 100644 index 41ee4e5e1..000000000 --- a/dom/system/gonk/mozstumbler/MozStumbler.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_mozstumbler_h__ -#define mozilla_system_mozstumbler_h__ - -#include "nsIDOMEventTarget.h" -#include "nsICellInfo.h" -#include "nsIWifi.h" - -#define STUMBLE_INTERVAL_MS 3000 - -class nsGeoPosition; - -void MozStumble(nsGeoPosition* position); - -class StumblerInfo final : public nsICellInfoListCallback, - public nsIWifiScanResultsReady -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSICELLINFOLISTCALLBACK - NS_DECL_NSIWIFISCANRESULTSREADY - - explicit StumblerInfo(nsGeoPosition* position) - : mPosition(position), mCellInfoResponsesExpected(0), mCellInfoResponsesReceived(0), mIsWifiInfoResponseReceived(0) - {} - void SetWifiInfoResponseReceived(); - void SetCellInfoResponsesExpected(uint8_t count); - -private: - ~StumblerInfo() {} - void DumpStumblerInfo(); - nsresult LocationInfoToString(nsACString& aLocDesc); - void CellNetworkInfoToString(nsACString& aCellDesc); - nsTArray> mCellInfo; - nsCString mWifiDesc; - RefPtr mPosition; - int mCellInfoResponsesExpected; - int mCellInfoResponsesReceived; - bool mIsWifiInfoResponseReceived; -}; -#endif // mozilla_system_mozstumbler_h__ - diff --git a/dom/system/gonk/mozstumbler/StumblerLogging.cpp b/dom/system/gonk/mozstumbler/StumblerLogging.cpp deleted file mode 100644 index acf23b3b1..000000000 --- a/dom/system/gonk/mozstumbler/StumblerLogging.cpp +++ /dev/null @@ -1,13 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "StumblerLogging.h" - -mozilla::LogModule* GetLog() -{ - static mozilla::LazyLogModule log("mozstumbler"); - return log; -} diff --git a/dom/system/gonk/mozstumbler/StumblerLogging.h b/dom/system/gonk/mozstumbler/StumblerLogging.h deleted file mode 100644 index 038f44f8f..000000000 --- a/dom/system/gonk/mozstumbler/StumblerLogging.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef STUMBLERLOGGING_H -#define STUMBLERLOGGING_H - -#include "mozilla/Logging.h" - -mozilla::LogModule* GetLog(); - -#define STUMBLER_DBG(arg, ...) MOZ_LOG(GetLog(), mozilla::LogLevel::Debug, ("STUMBLER - %s: " arg, __func__, ##__VA_ARGS__)) -#define STUMBLER_LOG(arg, ...) MOZ_LOG(GetLog(), mozilla::LogLevel::Info, ("STUMBLER - %s: " arg, __func__, ##__VA_ARGS__)) -#define STUMBLER_ERR(arg, ...) MOZ_LOG(GetLog(), mozilla::LogLevel::Error, ("STUMBLER -%s: " arg, __func__, ##__VA_ARGS__)) - -#endif diff --git a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp b/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp deleted file mode 100644 index d97aa9712..000000000 --- a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.cpp +++ /dev/null @@ -1,151 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "UploadStumbleRunnable.h" -#include "StumblerLogging.h" -#include "mozilla/dom/Event.h" -#include "nsIInputStream.h" -#include "nsIScriptSecurityManager.h" -#include "nsIURLFormatter.h" -#include "nsIXMLHttpRequest.h" -#include "nsNetUtil.h" -#include "nsVariant.h" - -UploadStumbleRunnable::UploadStumbleRunnable(nsIInputStream* aUploadData) -: mUploadInputStream(aUploadData) -{ -} - -NS_IMETHODIMP -UploadStumbleRunnable::Run() -{ - MOZ_ASSERT(NS_IsMainThread()); - nsresult rv = Upload(); - if (NS_FAILED(rv)) { - WriteStumbleOnThread::UploadEnded(false); - } - return NS_OK; -} - -nsresult -UploadStumbleRunnable::Upload() -{ - nsresult rv; - RefPtr variant = new nsVariant(); - - rv = variant->SetAsISupports(mUploadInputStream); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr xhr = do_CreateInstance(NS_XMLHTTPREQUEST_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr secman = - do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr systemPrincipal; - rv = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - - rv = xhr->Init(systemPrincipal, nullptr, nullptr, nullptr); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr formatter = - do_CreateInstance("@mozilla.org/toolkit/URLFormatterService;1", &rv); - NS_ENSURE_SUCCESS(rv, rv); - nsString url; - rv = formatter->FormatURLPref(NS_LITERAL_STRING("geo.stumbler.url"), url); - NS_ENSURE_SUCCESS(rv, rv); - - rv = xhr->Open(NS_LITERAL_CSTRING("POST"), NS_ConvertUTF16toUTF8(url), false, EmptyString(), EmptyString()); - NS_ENSURE_SUCCESS(rv, rv); - - xhr->SetRequestHeader(NS_LITERAL_CSTRING("Content-Type"), NS_LITERAL_CSTRING("gzip")); - xhr->SetMozBackgroundRequest(true); - // 60s timeout - xhr->SetTimeout(60 * 1000); - - nsCOMPtr target(do_QueryInterface(xhr)); - RefPtr listener = new UploadEventListener(xhr); - - const char* const sEventStrings[] = { - // nsIXMLHttpRequestEventTarget event types - "abort", - "error", - "load", - "timeout" - }; - - for (uint32_t index = 0; index < MOZ_ARRAY_LENGTH(sEventStrings); index++) { - nsAutoString eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]); - rv = target->AddEventListener(eventType, listener, false); - NS_ENSURE_SUCCESS(rv, rv); - } - - rv = xhr->Send(variant); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -NS_IMPL_ISUPPORTS(UploadEventListener, nsIDOMEventListener) - -UploadEventListener::UploadEventListener(nsIXMLHttpRequest* aXHR) -: mXHR(aXHR) -{ -} - -NS_IMETHODIMP -UploadEventListener::HandleEvent(nsIDOMEvent* aEvent) -{ - nsString type; - if (NS_FAILED(aEvent->GetType(type))) { - STUMBLER_ERR("Failed to get event type"); - WriteStumbleOnThread::UploadEnded(false); - return NS_ERROR_FAILURE; - } - - if (type.EqualsLiteral("load")) { - STUMBLER_DBG("Got load Event\n"); - } else if (type.EqualsLiteral("error") && mXHR) { - STUMBLER_ERR("Upload Error"); - } else { - STUMBLER_DBG("Receive %s Event", NS_ConvertUTF16toUTF8(type).get()); - } - - uint32_t statusCode = 0; - bool doDelete = false; - if (!mXHR) { - return NS_OK; - } - nsresult rv = mXHR->GetStatus(&statusCode); - if (NS_SUCCEEDED(rv)) { - STUMBLER_DBG("statuscode %d \n", statusCode); - } - - if (200 == statusCode || 400 == statusCode) { - doDelete = true; - } - - WriteStumbleOnThread::UploadEnded(doDelete); - nsCOMPtr target(do_QueryInterface(mXHR)); - - const char* const sEventStrings[] = { - // nsIXMLHttpRequestEventTarget event types - "abort", - "error", - "load", - "timeout" - }; - - for (uint32_t index = 0; index < MOZ_ARRAY_LENGTH(sEventStrings); index++) { - nsAutoString eventType = NS_ConvertASCIItoUTF16(sEventStrings[index]); - rv = target->RemoveEventListener(eventType, this, false); - } - - mXHR = nullptr; - return NS_OK; -} diff --git a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.h b/dom/system/gonk/mozstumbler/UploadStumbleRunnable.h deleted file mode 100644 index 462665a86..000000000 --- a/dom/system/gonk/mozstumbler/UploadStumbleRunnable.h +++ /dev/null @@ -1,46 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -#ifndef UPLOADSTUMBLERUNNABLE_H -#define UPLOADSTUMBLERUNNABLE_H - -#include "nsIDOMEventListener.h" - -class nsIXMLHttpRequest; -class nsIInputStream; - -/* - This runnable is managed by WriteStumbleOnThread only, see that class - for how this is scheduled. - */ -class UploadStumbleRunnable final : public Runnable -{ -public: - explicit UploadStumbleRunnable(nsIInputStream* aUploadInputStream); - - NS_IMETHOD Run() override; -private: - virtual ~UploadStumbleRunnable() {} - nsCOMPtr mUploadInputStream; - nsresult Upload(); -}; - - -class UploadEventListener : public nsIDOMEventListener -{ -public: - UploadEventListener(nsIXMLHttpRequest* aXHR); - - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENTLISTENER - -protected: - virtual ~UploadEventListener() {} - nsCOMPtr mXHR; -}; - -#endif diff --git a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp b/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp deleted file mode 100644 index e58e771c4..000000000 --- a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.cpp +++ /dev/null @@ -1,321 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "WriteStumbleOnThread.h" -#include "StumblerLogging.h" -#include "UploadStumbleRunnable.h" -#include "nsDumpUtils.h" -#include "nsGZFileWriter.h" -#include "nsIFileStreams.h" -#include "nsIInputStream.h" -#include "nsPrintfCString.h" - -#define MAXFILESIZE_KB (15 * 1024) -#define ONEDAY_IN_MSEC (24 * 60 * 60 * 1000) -#define MAX_UPLOAD_ATTEMPTS 20 - -mozilla::Atomic WriteStumbleOnThread::sIsFileWaitingForUpload(false); -mozilla::Atomic WriteStumbleOnThread::sIsAlreadyRunning(false); -WriteStumbleOnThread::UploadFreqGuard WriteStumbleOnThread::sUploadFreqGuard = {0}; - -#define FILENAME_INPROGRESS NS_LITERAL_CSTRING("stumbles.json.gz") -#define FILENAME_COMPLETED NS_LITERAL_CSTRING("stumbles.done.json.gz") -#define OUTPUT_DIR NS_LITERAL_CSTRING("mozstumbler") - -class DeleteRunnable : public Runnable -{ - public: - DeleteRunnable() {} - - NS_IMETHOD - Run() override - { - nsCOMPtr tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, - getter_AddRefs(tmpFile), - OUTPUT_DIR, - nsDumpUtils::CREATE); - if (NS_SUCCEEDED(rv)) { - tmpFile->Remove(true); - } - // critically, this sets this flag to false so writing can happen again - WriteStumbleOnThread::sIsAlreadyRunning = false; - WriteStumbleOnThread::sIsFileWaitingForUpload = false; - return NS_OK; - } - - private: - ~DeleteRunnable() {} -}; - -bool -WriteStumbleOnThread::IsFileWaitingForUpload() -{ - return sIsFileWaitingForUpload; -} - -void -WriteStumbleOnThread::UploadEnded(bool deleteUploadFile) -{ - if (!deleteUploadFile) { - sIsAlreadyRunning = false; - return; - } - - nsCOMPtr target = do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); - MOZ_ASSERT(target); - nsCOMPtr event = new DeleteRunnable(); - target->Dispatch(event, NS_DISPATCH_NORMAL); -} - -void -WriteStumbleOnThread::WriteJSON(Partition aPart) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr tmpFile; - nsresult rv; - rv = nsDumpUtils::OpenTempFile(FILENAME_INPROGRESS, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Open a file for stumble failed"); - return; - } - - RefPtr gzWriter = new nsGZFileWriter(nsGZFileWriter::Append); - rv = gzWriter->Init(tmpFile); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("gzWriter init failed"); - return; - } - - /* - The json format is like below. - {items:[ - {item}, - {item}, - {item} - ]} - */ - - // Need to add "]}" after the last item - if (aPart == Partition::End) { - rv = gzWriter->Write("]}"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("gzWriter Write failed"); - } - - rv = gzWriter->Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream finish failed"); - } - - nsCOMPtr targetFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(targetFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - nsAutoString targetFilename; - rv = targetFile->GetLeafName(targetFilename); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Get Filename failed"); - return; - } - rv = targetFile->Remove(true); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Remove File failed"); - return; - } - // Rename tmpfile - rv = tmpFile->MoveTo(/* directory */ nullptr, targetFilename); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Rename File failed"); - return; - } - return; - } - - // Need to add "{items:[" before the first item - if (aPart == Partition::Begining) { - rv = gzWriter->Write("{\"items\":[{"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write begining failed"); - } - } else if (aPart == Partition::Middle) { - rv = gzWriter->Write(",{"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write middle failed"); - } - } - rv = gzWriter->Write(mDesc.get()); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write mDesc failed"); - } - // one item is ended with '}' (e.g. {item}) - rv = gzWriter->Write("}"); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream write end failed"); - } - - rv = gzWriter->Finish(); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("ostream finish failed"); - } - - // check if it is the end of this file - int64_t fileSize = 0; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - return; - } - if (fileSize >= MAXFILESIZE_KB) { - WriteJSON(Partition::End); - return; - } -} - -WriteStumbleOnThread::Partition -WriteStumbleOnThread::GetWritePosition() -{ - MOZ_ASSERT(!NS_IsMainThread()); - - nsCOMPtr tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_INPROGRESS, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("Open a file for stumble failed"); - return Partition::Unknown; - } - - int64_t fileSize = 0; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - return Partition::Unknown; - } - - if (fileSize == 0) { - return Partition::Begining; - } else if (fileSize >= MAXFILESIZE_KB) { - return Partition::End; - } else { - return Partition::Middle; - } -} - -NS_IMETHODIMP -WriteStumbleOnThread::Run() -{ - MOZ_ASSERT(!NS_IsMainThread()); - - bool b = sIsAlreadyRunning.exchange(true); - if (b) { - return NS_OK; - } - - UploadFileStatus status = GetUploadFileStatus(); - - if (UploadFileStatus::NoFile != status) { - if (UploadFileStatus::ExistsAndReadyToUpload == status) { - sIsFileWaitingForUpload = true; - Upload(); - return NS_OK; - } - } else { - Partition partition = GetWritePosition(); - if (partition == Partition::Unknown) { - STUMBLER_ERR("GetWritePosition failed, skip once"); - } else { - WriteJSON(partition); - } - } - - sIsFileWaitingForUpload = false; - sIsAlreadyRunning = false; - return NS_OK; -} - - -/* - If the upload file exists, then check if it is one day old. - • if it is a day old -> ExistsAndReadyToUpload - • if it is less than the current day old -> Exists - • otherwise -> NoFile - - The Exists case means that the upload and the stumbling is rate limited - per-day to the size of the one file. - */ -WriteStumbleOnThread::UploadFileStatus -WriteStumbleOnThread::GetUploadFileStatus() -{ - nsCOMPtr tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - int64_t fileSize; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - return UploadFileStatus::NoFile; - } - if (fileSize <= 0) { - tmpFile->Remove(true); - return UploadFileStatus::NoFile; - } - - PRTime lastModifiedTime; - tmpFile->GetLastModifiedTime(&lastModifiedTime); - if ((PR_Now() / PR_USEC_PER_MSEC) - lastModifiedTime >= ONEDAY_IN_MSEC) { - return UploadFileStatus::ExistsAndReadyToUpload; - } - return UploadFileStatus::Exists; -} - -void -WriteStumbleOnThread::Upload() -{ - MOZ_ASSERT(!NS_IsMainThread()); - - time_t seconds = time(0); - int day = seconds / (60 * 60 * 24); - - if (sUploadFreqGuard.daySinceEpoch < day) { - sUploadFreqGuard.daySinceEpoch = day; - sUploadFreqGuard.attempts = 0; - } - - sUploadFreqGuard.attempts++; - if (sUploadFreqGuard.attempts > MAX_UPLOAD_ATTEMPTS) { - STUMBLER_ERR("Too many upload attempts today"); - sIsAlreadyRunning = false; - return; - } - - nsCOMPtr tmpFile; - nsresult rv = nsDumpUtils::OpenTempFile(FILENAME_COMPLETED, getter_AddRefs(tmpFile), - OUTPUT_DIR, nsDumpUtils::CREATE); - int64_t fileSize; - rv = tmpFile->GetFileSize(&fileSize); - if (NS_WARN_IF(NS_FAILED(rv))) { - STUMBLER_ERR("GetFileSize failed"); - sIsAlreadyRunning = false; - return; - } - - if (fileSize <= 0) { - sIsAlreadyRunning = false; - return; - } - - // prepare json into nsIInputStream - nsCOMPtr inStream; - rv = NS_NewLocalFileInputStream(getter_AddRefs(inStream), tmpFile); - if (NS_FAILED(rv)) { - sIsAlreadyRunning = false; - return; - } - - RefPtr uploader = new UploadStumbleRunnable(inStream); - NS_DispatchToMainThread(uploader); -} diff --git a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.h b/dom/system/gonk/mozstumbler/WriteStumbleOnThread.h deleted file mode 100644 index 104cf9bdd..000000000 --- a/dom/system/gonk/mozstumbler/WriteStumbleOnThread.h +++ /dev/null @@ -1,91 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef WriteStumbleOnThread_H -#define WriteStumbleOnThread_H - -#include "mozilla/Atomics.h" - -class DeleteRunnable; - -/* - This class is the entry point to stumbling, in that it - receives the location+cell+wifi string and writes it - to disk, or instead, it calls UploadStumbleRunnable - to upload the data. - - Writes will happen until the file is a max size, then stop. - Uploads will happen only when the file is one day old. - The purpose of these decisions is to have very simple rate-limiting - on the writes, as well as the uploads. - - There is only one file active; it is either being used for writing, - or for uploading. If the file is ready for uploading, no further - writes will take place until this file has been uploaded. - This can mean writing might not take place for days until the uploaded - file is processed. This is correct by-design. - - A notable limitation is that the upload is triggered by a location event, - this is used as an arbitrary and simple trigger. In future, there are - better events that can be used, such as detecting network activity. - - This thread is guarded so that only one instance is active (see the - mozilla::Atomics used for this). - */ -class WriteStumbleOnThread : public mozilla::Runnable -{ -public: - explicit WriteStumbleOnThread(const nsCString& aDesc) - : mDesc(aDesc) - {} - - NS_IMETHOD Run() override; - - static void UploadEnded(bool deleteUploadFile); - - // Used externally to determine if cell+wifi scans should happen - // (returns false for that case). - static bool IsFileWaitingForUpload(); - -private: - friend class DeleteRunnable; - - enum class Partition { - Begining, - Middle, - End, - Unknown - }; - - enum class UploadFileStatus { - NoFile, Exists, ExistsAndReadyToUpload - }; - - ~WriteStumbleOnThread() {} - - Partition GetWritePosition(); - UploadFileStatus GetUploadFileStatus(); - void WriteJSON(Partition aPart); - void Upload(); - - nsCString mDesc; - - // Only run one instance of this - static mozilla::Atomic sIsAlreadyRunning; - - static mozilla::Atomic sIsFileWaitingForUpload; - - // Limit the upload attempts per day. If the device is rebooted - // this resets the allowed attempts, which is acceptable. - struct UploadFreqGuard { - int attempts; - int daySinceEpoch; - }; - static UploadFreqGuard sUploadFreqGuard; - -}; - -#endif diff --git a/dom/system/gonk/nsIAudioManager.idl b/dom/system/gonk/nsIAudioManager.idl deleted file mode 100644 index c2eb62b21..000000000 --- a/dom/system/gonk/nsIAudioManager.idl +++ /dev/null @@ -1,58 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, builtinclass, uuid(df31c280-1ef1-11e5-867f-0800200c9a66)] -interface nsIAudioManager : nsISupports -{ - /** - * Microphone muted? - */ - attribute boolean microphoneMuted; - - /** - * Set the phone's audio mode. - */ - const long PHONE_STATE_INVALID = -2; - const long PHONE_STATE_CURRENT = -1; - const long PHONE_STATE_NORMAL = 0; - const long PHONE_STATE_RINGTONE = 1; - const long PHONE_STATE_IN_CALL = 2; - const long PHONE_STATE_IN_COMMUNICATION = 3; - - attribute long phoneState; - - /** - * Configure a particular device ("force") to be used for one of the uses - * (communication, media playback, etc.) - */ - const long FORCE_NONE = 0; // the default - const long FORCE_SPEAKER = 1; - const long FORCE_HEADPHONES = 2; - const long FORCE_BT_SCO = 3; - const long FORCE_BT_A2DP = 4; - const long FORCE_WIRED_ACCESSORY = 5; - const long FORCE_BT_CAR_DOCK = 6; - const long FORCE_BT_DESK_DOCK = 7; - const long FORCE_ANALOG_DOCK = 8; - const long FORCE_DIGITAL_DOCK = 9; - const long FORCE_NO_BT_A2DP = 10; - const long USE_COMMUNICATION = 0; - const long USE_MEDIA = 1; - const long USE_RECORD = 2; - const long USE_DOCK = 3; - - void setForceForUse(in long usage, in long force); - long getForceForUse(in long usage); - - /** - * These functions would be used when we enable the new volume control API - * (mozAudioChannelManager). The range of volume index is from 0 to N. - * More details on : https://gist.github.com/evanxd/41d8e2d91c5201a42bfa - */ - void setAudioChannelVolume(in unsigned long channel, in unsigned long index); - unsigned long getAudioChannelVolume(in unsigned long channel); - unsigned long getMaxAudioChannelVolume(in unsigned long channel); -}; diff --git a/dom/system/gonk/nsIDataCallInterfaceService.idl b/dom/system/gonk/nsIDataCallInterfaceService.idl deleted file mode 100644 index c387879fa..000000000 --- a/dom/system/gonk/nsIDataCallInterfaceService.idl +++ /dev/null @@ -1,268 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(6b66446a-7000-438f-8e1b-b56b4cbf4fa9)] -interface nsIDataCall : nsISupports -{ - /** - * Data call fail cause. One of the nsIDataCallInterface.DATACALL_FAIL_* - * values. - */ - readonly attribute long failCause; - - /** - * If failCause != nsIDataCallInterface.DATACALL_FAIL_NONE, this field - * indicates the suggested retry back-off timer. The unit is milliseconds. - */ - readonly attribute long suggestedRetryTime; - - /** - * Context ID, uniquely identifies this call. - */ - readonly attribute long cid; - - /** - * Data call network state. One of the nsIDataCallInterface.DATACALL_STATE_* - * values. - */ - readonly attribute long active; - - /** - * Data call connection type. One of the - * nsIDataCallInterface.DATACALL_PDP_TYPE_* values. - */ - readonly attribute long pdpType; - - /** - * The network interface name. - */ - readonly attribute DOMString ifname; - - /** - * A space-delimited list of addresses with optional "/" prefix length. - */ - readonly attribute DOMString addresses; - - /** - * A space-delimited list of DNS server addresses. - */ - readonly attribute DOMString dnses; - - /** - * A space-delimited list of default gateway addresses. - */ - readonly attribute DOMString gateways; - - /** - * A space-delimited list of Proxy Call State Control Function addresses for - * IMS client. - */ - readonly attribute DOMString pcscf; - - /** - * MTU received from network, -1 if not set or invalid. - */ - readonly attribute long mtu; -}; - -[scriptable, uuid(e119c54b-9354-4ad6-a1ee-18608bde9320)] -interface nsIDataCallInterfaceListener : nsISupports -{ - /** - * Notify data call interface listeners about unsolicited data call state - * changes. - */ - void notifyDataCallListChanged(in uint32_t count, - [array, size_is(count)] in nsIDataCall - dataCalls); -}; - -[scriptable, uuid(db0b640a-3b3a-4f48-84dc-256e176876c2)] -interface nsIDataCallCallback : nsISupports -{ - /** - * Called when setupDataCall() returns succesfully. - */ - void notifySetupDataCallSuccess(in nsIDataCall dataCall); - - /** - * Called when getDataCallList() returns succesfully. - */ - void notifyGetDataCallListSuccess(in uint32_t count, - [array, size_is(count)] in nsIDataCall - dataCalls); - /** - * Called when request returns succesfully. - */ - void notifySuccess(); - - /** - * Called when request returns error. - */ - void notifyError(in AString errorMsg); -}; - -[scriptable, uuid(ec219021-8623-4b9f-aba5-4db58c60684f)] -interface nsIDataCallInterface : nsISupports -{ - /** - * Data fail causes, defined in TS 24.008. - */ - const long DATACALL_FAIL_NONE = 0; - const long DATACALL_FAIL_OPERATOR_BARRED = 0x08; - const long DATACALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A; - const long DATACALL_FAIL_MISSING_UKNOWN_APN = 0x1B; - const long DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C; - const long DATACALL_FAIL_USER_AUTHENTICATION = 0x1D; - const long DATACALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E; - const long DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F; - const long DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20; - const long DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21; - const long DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22; - const long DATACALL_FAIL_NSAPI_IN_USE = 0x23; - const long DATACALL_FAIL_ONLY_IPV4_ALLOWED = 0x32; - const long DATACALL_FAIL_ONLY_IPV6_ALLOWED = 0x33; - const long DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34; - const long DATACALL_FAIL_PROTOCOL_ERRORS = 0x6F; - /* Not mentioned in the specification */ - const long DATACALL_FAIL_VOICE_REGISTRATION_FAIL = -1; - const long DATACALL_FAIL_DATA_REGISTRATION_FAIL = -2; - const long DATACALL_FAIL_SIGNAL_LOST = -3; - const long DATACALL_FAIL_PREF_RADIO_TECH_CHANGED = -4; - const long DATACALL_FAIL_RADIO_POWER_OFF = -5; - const long DATACALL_FAIL_TETHERED_CALL_ACTIVE = -6; - const long DATACALL_FAIL_ERROR_UNSPECIFIED = 0xFFFF; - - /** - * Data call network state. - */ - const long DATACALL_STATE_INACTIVE = 0; - const long DATACALL_STATE_ACTIVE_DOWN = 1; - const long DATACALL_STATE_ACTIVE_UP = 2; - - /** - * Data call authentication type. Must match the values in ril_consts - * RIL_DATACALL_AUTH_TO_GECKO array. - */ - const long DATACALL_AUTH_NONE = 0; - const long DATACALL_AUTH_PAP = 1; - const long DATACALL_AUTH_CHAP = 2; - const long DATACALL_AUTH_PAP_OR_CHAP = 3; - - /** - * Data call protocol type. Must match the values in ril_consts - * RIL_DATACALL_PDP_TYPES array. - */ - const long DATACALL_PDP_TYPE_IPV4 = 0; - const long DATACALL_PDP_TYPE_IPV4V6 = 1; - const long DATACALL_PDP_TYPE_IPV6 = 2; - - /** - * Reason for deactivating data call. - */ - const long DATACALL_DEACTIVATE_NO_REASON = 0; - const long DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1; - - /** - * Setup data call. - * - * @param apn - * Apn to connect to. - * @param username - * Username for apn. - * @param password - * Password for apn. - * @param authType - * Authentication type. One of the DATACALL_AUTH_* values. - * @param pdpType - * Connection type. One of the DATACALL_PDP_TYPE_* values. - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifySetupDataCallSuccess() will be called with the - * new nsIDataCall. - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable', 'OpNotAllowedBeforeRegToNw', - * 'OpNotAllowedDuringVoiceCall', 'RequestNotSupported' or 'GenericFailure'. - */ - void setupDataCall(in AString apn, in AString username, - in AString password, in long authType, - in long pdpType, - in nsIDataCallCallback callback); - - /** - * Deactivate data call. - * - * @param cid - * Context id. - * @param reason - * Disconnect Reason. One of the DATACALL_DEACTIVATE_* values. - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifySuccess() will be called. - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable' or 'GenericFailure'. - */ - void deactivateDataCall(in long cid, - in long reason, - in nsIDataCallCallback callback); - - /** - * Get current data call list. - * - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifyGetDataCallListSuccess() will be called with the - * list of nsIDataCall(s). - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable' or 'GenericFailure'. - */ - void getDataCallList(in nsIDataCallCallback callback); - - /** - * Set data registration state. - * - * @param attach - * whether to attach data registration or not. - * @param nsIDataCallCallback - * Called when request is finished. - * - * If successful, the notifySuccess() will be called. - * - * Otherwise, the notifyError() will be called, and the error will be either - * 'RadioNotAvailable', 'SubscriptionNotAvailable' or 'GenericFailure'. - */ - void setDataRegistration(in boolean attach, - in nsIDataCallCallback callback); - - /** - * Register to receive unsolicited events from this nsIDataCallInterface. - */ - void registerListener(in nsIDataCallInterfaceListener listener); - - /** - * Unregister to stop receiving unsolicited events from this - * nsIDataCallInterface. - */ - void unregisterListener(in nsIDataCallInterfaceListener listener); -}; - -[scriptable, uuid(64700406-7429-4743-a6ae-f82e9877fd0d)] -interface nsIDataCallInterfaceService : nsISupports -{ - /** - * Get the corresponding data call interface. - * - * @param clientId - * clientId of the data call interface to get. - */ - nsIDataCallInterface getDataCallInterface(in long clientId); -}; \ No newline at end of file diff --git a/dom/system/gonk/nsIDataCallManager.idl b/dom/system/gonk/nsIDataCallManager.idl deleted file mode 100644 index de8477801..000000000 --- a/dom/system/gonk/nsIDataCallManager.idl +++ /dev/null @@ -1,81 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" -#include "nsINetworkInterface.idl" - -[scriptable, uuid(b8bcd6aa-5b06-4362-a68c-317878429e51)] -interface nsIRilNetworkInfo : nsINetworkInfo -{ - readonly attribute unsigned long serviceId; - readonly attribute DOMString iccId; - - /* The following attributes are for MMS proxy settings. */ - readonly attribute DOMString mmsc; // Empty string if not set. - readonly attribute DOMString mmsProxy; // Empty string if not set. - readonly attribute long mmsPort; // -1 if not set. - - /** - * Get the list of pcscf addresses, could be IPv4 or IPv6. - * - * @param count - * The length of the list of pcscf addresses. - * - * @returns the list of pcscf addresses. - */ - void getPcscf([optional] out unsigned long count, - [array, size_is(count), retval] out wstring pcscf); -}; - -[scriptable, function, uuid(cb2f0f5b-67f4-4c14-93e8-01e66b630464)] -interface nsIDeactivateDataCallsCallback : nsISupports -{ - /** - * Callback function used to notify when all data calls are disconnected. - */ - void notifyDataCallsDisconnected(); -}; - -[scriptable, uuid(e3feec20-36b4-47de-a7a5-e32a65f20186)] -interface nsIDataCallHandler : nsISupports -{ - /** - * PDP APIs - * - * @param networkType - * Mobile network type, that is, - * nsINetworkInterface.NETWORK_TYPE_MOBILE or one of the - * nsINetworkInterface.NETWORK_TYPE_MOBILE_* values. - */ - void setupDataCallByType(in long networkType); - void deactivateDataCallByType(in long networkType); - long getDataCallStateByType(in long networkType); - - /** - * Deactivate all data calls. - * - * @param callback - * Callback to notify when all data calls are disconnected. - */ - void deactivateDataCalls(in nsIDeactivateDataCallsCallback callback); - - /** - * Called to reconsider data call state. - */ - void updateRILNetworkInterface(); -}; - -[scriptable, uuid(2c46e37d-88dc-4d25-bb37-e1c0d3e9cb5f)] -interface nsIDataCallManager : nsISupports -{ - readonly attribute long dataDefaultServiceId; - - /** - * Get the corresponding data call handler. - * - * @param clientId - * clientId of the data call handler to get. - */ - nsIDataCallHandler getDataCallHandler(in unsigned long clientId); -}; \ No newline at end of file diff --git a/dom/system/gonk/nsIGonkDataCallInterfaceService.idl b/dom/system/gonk/nsIGonkDataCallInterfaceService.idl deleted file mode 100644 index 240ca6bab..000000000 --- a/dom/system/gonk/nsIGonkDataCallInterfaceService.idl +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsIDataCallInterfaceService.idl" - -[scriptable, uuid(f008d00c-e2b8-49b2-8f88-19111577938e)] -interface nsIGonkDataCallInterfaceService : nsIDataCallInterfaceService -{ - /** - * Called by RadioInterface or lower layer to notify about data call list - * changes. - */ - void notifyDataCallListChanged(in unsigned long clientId, - in uint32_t count, - [array, size_is(count)] in nsIDataCall - dataCalls); -}; \ No newline at end of file diff --git a/dom/system/gonk/nsINetworkInterface.idl b/dom/system/gonk/nsINetworkInterface.idl deleted file mode 100644 index bd40e751a..000000000 --- a/dom/system/gonk/nsINetworkInterface.idl +++ /dev/null @@ -1,108 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(4816a559-5620-4cb5-8433-ff0b25e6622f)] -interface nsINetworkInfo : nsISupports -{ - const long NETWORK_STATE_UNKNOWN = -1; - const long NETWORK_STATE_CONNECTING = 0; - const long NETWORK_STATE_CONNECTED = 1; - const long NETWORK_STATE_DISCONNECTING = 2; - const long NETWORK_STATE_DISCONNECTED = 3; - const long NETWORK_STATE_ENABLED = 4; - const long NETWORK_STATE_DISABLED = 5; - - /** - * Current network state, one of the NETWORK_STATE_* constants. - * - * When this changes, network interface implementations notify with - * updateNetworkInterface() API. - */ - readonly attribute long state; - - const long NETWORK_TYPE_UNKNOWN = -1; - const long NETWORK_TYPE_WIFI = 0; - const long NETWORK_TYPE_MOBILE = 1; - const long NETWORK_TYPE_MOBILE_MMS = 2; - const long NETWORK_TYPE_MOBILE_SUPL = 3; - const long NETWORK_TYPE_WIFI_P2P = 4; - const long NETWORK_TYPE_MOBILE_IMS = 5; - const long NETWORK_TYPE_MOBILE_DUN = 6; - const long NETWORK_TYPE_MOBILE_FOTA = 7; - const long NETWORK_TYPE_ETHERNET = 8; - - /** - * Network type. One of the NETWORK_TYPE_* constants. - */ - readonly attribute long type; - - /** - * Interface name of the network interface this network info belongs to. - */ - readonly attribute DOMString name; - - /** - * Get the list of ip addresses and prefix lengths, ip address could be IPv4 - * or IPv6, typically 1 IPv4 or 1 IPv6 or one of each. - * - * @param ips - * The list of ip addresses retrieved. - * @param prefixLengths - * The list of prefix lengths retrieved. - * - * @returns the length of the lists. - */ - void getAddresses([array, size_is(count)] out wstring ips, - [array, size_is(count)] out unsigned long prefixLengths, - [retval] out unsigned long count); - - /** - * Get the list of gateways, could be IPv4 or IPv6, typically 1 IPv4 or 1 - * IPv6 or one of each. - * - * @param count - * The length of the list of gateways - * - * @returns the list of gateways. - */ - void getGateways([optional] out unsigned long count, - [array, size_is(count), retval] out wstring gateways); - - /** - * Get the list of dnses, could be IPv4 or IPv6. - * - * @param count - * The length of the list of dnses. - * - * @returns the list of dnses. - */ - void getDnses([optional] out unsigned long count, - [array, size_is(count), retval] out wstring dnses); -}; - -[scriptable, uuid(8b1345fa-b34c-41b3-8d21-09f961bf8887)] -interface nsINetworkInterface : nsISupports -{ - /** - * The network information about this network interface. - */ - readonly attribute nsINetworkInfo info; - - /** - * The host name of the http proxy server. - */ - readonly attribute DOMString httpProxyHost; - - /* - * The port number of the http proxy server. - */ - readonly attribute long httpProxyPort; - - /* - * The Maximun Transmit Unit for this network interface, -1 if not set. - */ - readonly attribute long mtu; -}; diff --git a/dom/system/gonk/nsINetworkInterfaceListService.idl b/dom/system/gonk/nsINetworkInterfaceListService.idl deleted file mode 100644 index 0c224842e..000000000 --- a/dom/system/gonk/nsINetworkInterfaceListService.idl +++ /dev/null @@ -1,40 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsINetworkInfo; - -[scriptable, uuid(55779d32-1e28-4f43-af87-09d04bc3cce9)] -interface nsINetworkInterfaceList : nsISupports -{ - /** - * Number of the network interfaces that is available. - */ - long getNumberOfInterface(); - - /** - * Get the i-th interface info info from the list. - * @param interfaceIndex index of interface, from 0 to number of interface - 1. - */ - nsINetworkInfo getInterfaceInfo(in long interfaceIndex); -}; - -[scriptable, uuid(21d7fc8b-28c4-4a4f-a15e-1f9defbc2cec)] -interface nsINetworkInterfaceListService : nsISupports -{ - const long LIST_NOT_INCLUDE_MMS_INTERFACES = (1 << 0); - const long LIST_NOT_INCLUDE_SUPL_INTERFACES = (1 << 1); - const long LIST_NOT_INCLUDE_IMS_INTERFACES = (1 << 2); - const long LIST_NOT_INCLUDE_DUN_INTERFACES = (1 << 3); - const long LIST_NOT_INCLUDE_FOTA_INTERFACES = (1 << 4); - - /** - * Obtain a list of network interfaces that satisfy the specified condition. - * @param condition flags that specify the interfaces to be returned. This - * can be OR combination of LIST_* flags, or zero to make all available - * interfaces returned. - */ - nsINetworkInterfaceList getDataInterfaceList(in long condition); -}; diff --git a/dom/system/gonk/nsINetworkManager.idl b/dom/system/gonk/nsINetworkManager.idl deleted file mode 100644 index 0da123796..000000000 --- a/dom/system/gonk/nsINetworkManager.idl +++ /dev/null @@ -1,135 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsINetworkInfo; -interface nsINetworkInterface; - -/** - * Manage network interfaces. - */ -[scriptable, uuid(1ba9346b-53b5-4660-9dc6-58f0b258d0a6)] -interface nsINetworkManager : nsISupports -{ - /** - * Register the given network interface with the network manager. - * - * Consumers will be notified with the 'network-interface-registered' - * observer notification. - * - * Throws if there's already an interface registered with the same network id. - * - * @param network - * Network interface to register. - */ - void registerNetworkInterface(in nsINetworkInterface network); - - /** - * Update the routes and DNSes according the state of the given network. - * - * Consumers will be notified with the 'network-connection-state-changed' - * observer notification. - * - * Throws an exception if the specified network interface object isn't - * registered. - * - * @param network - * Network interface to update. - */ - void updateNetworkInterface(in nsINetworkInterface network); - - /** - * Unregister the given network interface from the network manager. - * - * Consumers will be notified with the 'network-interface-unregistered' - * observer notification. - * - * Throws an exception if the specified network interface object isn't - * registered. - * - * @param network - * Network interface to unregister. - */ - void unregisterNetworkInterface(in nsINetworkInterface network); - - /** - * Object containing all known network information, keyed by their - * network id. Network id is composed of a sub-id + '-' + network - * type. For mobile network types, sub-id is 'ril' + service id; for - * non-mobile network types, sub-id is always 'device'. - */ - readonly attribute jsval allNetworkInfo; - - /** - * Priority list of network types. An array of - * nsINetworkInterface::NETWORK_TYPE_* constants. - * - * The piror position of the type indicates the higher priority. The priority - * is used to determine route when there are multiple connected networks. - */ - attribute jsval networkTypePriorityList; - - /** - * The preferred network type. One of the - * nsINetworkInterface::NETWORK_TYPE_* constants. - * - * This attribute is used for setting default route to favor - * interfaces with given type. This can be overriden by calling - * overrideDefaultRoute(). - */ - attribute long preferredNetworkType; - - /** - * The network information of the network interface handling all network - * traffic. - * - * When this changes, the 'network-active-changed' observer - * notification is dispatched. - */ - readonly attribute nsINetworkInfo activeNetworkInfo; - - /** - * Override the default behaviour for preferredNetworkType and route - * all network traffic through the the specified interface. - * - * Consumers can observe changes to the active network by subscribing to - * the 'network-active-changed' observer notification. - * - * @param network - * Network to route all network traffic to. If this is null, - * a previous override is canceled. - */ - long overrideActive(in nsINetworkInterface network); - - /** - * Add host route to the specified network into routing table. - * - * @param network - * The network information for the host to be routed to. - * @param host - * The host to be added. - * The host will be resolved in advance if it's not an ip-address. - * - * @return a Promise - * resolved if added; rejected, otherwise. - */ - jsval addHostRoute(in nsINetworkInfo network, - in DOMString host); - - /** - * Remove host route to the specified network from routing table. - * - * @param network - * The network information for the routing to be removed from. - * @param host - * The host routed to the network. - * The host will be resolved in advance if it's not an ip-address. - * - * @return a Promise - * resolved if removed; rejected, otherwise. - */ - jsval removeHostRoute(in nsINetworkInfo network, - in DOMString host); -}; diff --git a/dom/system/gonk/nsINetworkService.idl b/dom/system/gonk/nsINetworkService.idl deleted file mode 100644 index 50a468494..000000000 --- a/dom/system/gonk/nsINetworkService.idl +++ /dev/null @@ -1,619 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, function, uuid(91824160-fb25-11e1-a21f-0800200c9a66)] -interface nsIWifiTetheringCallback : nsISupports -{ - /** - * Callback function used to report status to WifiManager. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void wifiTetheringEnabledChange(in jsval error); -}; - -[scriptable, function, uuid(9c128e68-5e4b-4626-bb88-84ec54cce5d8)] -interface nsINetworkStatsCallback : nsISupports -{ - void networkStatsAvailable(in boolean success, - in unsigned long rxBytes, - in unsigned long txBytes, - in unsigned long long timestamp); -}; - -[scriptable, function, uuid(0706bfa2-ac2d-11e2-9a8d-7b6d988d4767)] -interface nsINetworkUsageAlarmCallback : nsISupports -{ - void networkUsageAlarmResult(in jsval error); -}; - -[scriptable, function, uuid(9ede8720-f8bc-11e2-b778-0800200c9a66)] -interface nsIWifiOperationModeCallback : nsISupports -{ - /** - * Callback function used to report result to WifiManager. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void wifiOperationModeResult(in jsval error); -}; - -[scriptable, function, uuid(097878b0-19fc-11e3-8ffd-0800200c9a66)] -interface nsISetDhcpServerCallback : nsISupports -{ - /** - * Callback function used to report the DHCP server set result - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void dhcpServerResult(in jsval error); -}; - -[scriptable, function, uuid(32407c50-46c7-11e3-8f96-0800200c9a66)] -interface nsIUsbTetheringCallback : nsISupports -{ - /** - * Callback function used to report status of enabling usb tethering. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void usbTetheringEnabledChange(in jsval error); -}; - -[scriptable, function, uuid(055fd560-46ad-11e3-8f96-0800200c9a66)] -interface nsIEnableUsbRndisCallback : nsISupports -{ - /** - * Callback function used to report the status of enabling/disabling usb rndis. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param enable - * Boolean to indicate if we are enabling or disabling usb rndis. - */ - void enableUsbRndisResult(in boolean success, in boolean enable); -}; - -[scriptable, function, uuid(4f08cc30-46ad-11e3-8f96-0800200c9a66)] -interface nsIUpdateUpStreamCallback : nsISupports -{ - /** - * Callback function used to report the result of updating upstream. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param externalIfname - * The external interface name. - */ - void updateUpStreamResult(in boolean success, in DOMString externalIfname); -}; - -[scriptable, function, uuid(eedca6c0-1310-11e4-9191-0800200c9a66)] -interface nsISetDnsCallback : nsISupports -{ - /** - * Callback function used to report the result of setting DNS server. - * - * @param error - * An error message if the operation wasn't successful, - * or `null` if it was. - */ - void setDnsResult(in jsval error); -}; - -[scriptable, function, uuid(5d0e1a60-1187-11e4-9191-0800200c9a66)] -interface nsINativeCommandCallback : nsISupports -{ - /** - * Callback function used to report the result of a network native command. - * - * @param success - * Boolean to indicate the operation is successful or not. - */ - void nativeCommandResult(in boolean success); -}; - -[scriptable, function, uuid(694abb80-1187-11e4-9191-0800200c9a66)] -interface nsIDhcpRequestCallback : nsISupports -{ - /** - * Callback function used to report the result of DHCP client request. - * - * @param success - * Boolean to indicate the operation is successful or not. - * - * @param dhcpInfo - * An object to represent the successful DHCP request: - * - * - gateway_str: string - * - dns1_str: string - * - dns2_str: string - * - mask_str: string - * - server_str: string - * - vendor_str: string - * - lease: long - * - mask: long - * - ipaddr: long - * - gateway: long - * - dns1: long - * - dns2: long - * - server: long - */ - void dhcpRequestResult(in boolean success, in jsval dhcpInfo); -}; - -[scriptable, function, uuid(88e3ee22-f1b3-4fa0-8a5d-793fb827c42c)] -interface nsIGetInterfacesCallback : nsISupports -{ - /** - * Callback function used to return the list of existing network interfaces. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param interfaceList - * An array of interface name. - */ - void getInterfacesResult(in boolean success, in jsval interfaceList); -}; - -[scriptable, function, uuid(064e02a3-d2c0-42c5-a293-1efa84056100)] -interface nsIGetInterfaceConfigCallback : nsISupports -{ - /** - * Callback function used to return the network config of a given interface. - * - * @param success - * Boolean to indicate the operation is successful or not. - * @param result - * .ip: Ip address. - * .prefix: mask length. - * .link: network link properties. - * .mac: mac address. - */ - void getInterfaceConfigResult(in boolean success, in jsval result); -}; - -[scriptable, function, uuid(b370f360-6ba8-4517-a4f9-31e8f004ee91)] -interface nsISetInterfaceConfigCallback : nsISupports -{ - /** - * Callback function used to set network config for a specified interface. - * - * @param success - * Boolean to indicate the operation is successful or not. - */ - void setInterfaceConfigResult(in boolean success); -}; - -/** - * Provide network services. - */ -[scriptable, uuid(e16fe98f-9f63-48fe-82ba-8d1a1b7c6a57)] -interface nsINetworkService : nsISupports -{ - const long MODIFY_ROUTE_ADD = 0; - const long MODIFY_ROUTE_REMOVE = 1; - - /** - * Enable or disable Wifi Tethering - * - * @param enabled - * Boolean that indicates whether tethering should be enabled (true) or disabled (false). - * @param config - * The Wifi Tethering configuration from settings db. - * @param callback - * Callback function used to report status to WifiManager. - */ - void setWifiTethering(in boolean enabled, - in jsval config, - in nsIWifiTetheringCallback callback); - - /** - * Enable or disable DHCP server - * - * @param enabled - * Boolean that indicates enabling or disabling DHCP server. - * - * @param config - * Config used to enable the DHCP server. It contains - * .startIp start of the ip lease range (string) - * .endIp end of the ip lease range (string) - * .serverIp ip of the DHCP server (string) - * .maskLength the length of the subnet mask - * .ifname the interface name - * - * As for disabling the DHCP server, put this value |null|. - * - * @param callback - * Callback function used to report status. - */ - void setDhcpServer(in boolean enabled, - in jsval config, - in nsISetDhcpServerCallback callback); - - - /** - * Retrieve network interface stats. - * - * @param networkName - * Select the Network interface to request estats. - * - * @param callback - * Callback to notify result and provide stats, connectionType - * and the date when stats are retrieved - */ - void getNetworkInterfaceStats(in DOMString networkName, in nsINetworkStatsCallback callback); - - /** - * Set Alarm of usage per interface - * - * @param networkName - * Select the Network interface to set an alarm. - * - * @param threshold - * Amount of data that will trigger the alarm. - * - * @param callback - * Callback to notify the result. - * - * @return false if there is no interface registered for the networkType param. - */ - boolean setNetworkInterfaceAlarm(in DOMString networkName, - in long long threshold, - in nsINetworkUsageAlarmCallback callback); - - /** - * Reload Wifi firmware to specific operation mode. - * - * @param interfaceName - * Wifi Network interface name. - * - * @param mode - * AP - Access pointer mode. - * P2P - Peer to peer connection mode. - * STA - Station mode. - * - * @param callback - * Callback to notify Wifi firmware reload result. - */ - void setWifiOperationMode(in DOMString interfaceName, - in DOMString mode, - in nsIWifiOperationModeCallback callback); - - /** - * Set USB tethering. - * - * @param enabled - * Boolean to indicate we are going to enable or disable usb tethering. - * @param config - * The usb tethering configuration. - * @param callback - * Callback function used to report the result enabling/disabling usb tethering. - */ - void setUSBTethering(in boolean enabled, - in jsval config, - in nsIUsbTetheringCallback callback); - - /** - * Reset routing table. - * - * @param interfaceName - * The name of the network interface we want to remove from the routing - * table. - * - * @param callback - * Callback to notify the result of resetting routing table. - */ - void resetRoutingTable(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Set DNS. - * - * @param interfaceName - * The network interface name of the DNS we want to set. - * @param dnsesCount - * Number of elements in dnses. - * @param dnses - * Dnses to set. - * @param gatewaysCount - * Number of elements in gateways. - * @param gateways - * Gateways for the dnses, the most suitable, usually the one with the - * same address family, will be selected for each dns. - * - * @param callback - * Callback to notify the result of setting DNS server. - */ - void setDNS(in DOMString interfaceName, - in unsigned long dnsesCount, - [array, size_is(dnsesCount)] in wstring dnses, - in unsigned long gatewaysCount, - [array, size_is(gatewaysCount)] in wstring gateways, - in nsISetDnsCallback callback); - - /** - * Set default route. - * - * @param interfaceName - * The network interface name of the default route we want to set. - * @param count - * Number of elements in gateways. - * @param gateways - * Default gateways for setting default route. - * - * @param callback - * Callback to notify the result of setting default route. - */ - void setDefaultRoute(in DOMString interfaceName, - in unsigned long count, - [array, size_is(count)] in wstring gateways, - in nsINativeCommandCallback callback); - - /** - * Remove default route. - * - * @param interfaceName - * The network interface name of the default route we want to remove. - * @param count - * Number of elements in gateways. - * @param gatways - * Default gateways for removing default route. - * - * @param callback - * Callback to notify the result of removing default route. - */ - void removeDefaultRoute(in DOMString interfaceName, - in unsigned long count, - [array, size_is(count)] in wstring gateways, - in nsINativeCommandCallback callback); - - /** - * Modify route. - * - * @param action - * nsINetworkService.MODIFY_ROUTE_ADD to add route and - * nsINetworkService.MODIFY_ROUTE_REMOVE to remove. - * @param interfaceName - * Network interface name for the output of the host route. - * @param host - * Host ip we want to remove route for. - * @param prefixLength - * The prefix length of the route we'd like to modify. - * @param [optional] gateway - * Gateway ip for the output of the host route. - * - * @return A deferred promise that resolves on success or rejects with a - * specified reason otherwise. - */ - jsval modifyRoute(in long action, - in DOMString interfaceName, - in DOMString host, - in long prefixLength, - [optional] in DOMString gateway); - - /** - * Add route to secondary routing table. - * - * @param interfaceName - * The network interface for this route. - * @param route - * The route info should have the following fields: - * .ip: destination ip address - * .prefix: destination prefix - * .gateway: gateway ip address - */ - void addSecondaryRoute(in DOMString interfaceName, in jsval route, - in nsINativeCommandCallback callback); - - /** - * Remove route from secondary routing table. - * - * @param interfaceName - * The network interface for the route we want to remove. - * @param route - * The route info should have the following fields: - * .ip: destination ip address - * .prefix: destination prefix - * .gateway: gateway ip address - */ - void removeSecondaryRoute(in DOMString interfaceName, in jsval route, - in nsINativeCommandCallback callback); - - /** - * Enable or disable usb rndis. - * - * @param enable - * Boolean to indicate we want enable or disable usb rndis. - * @param callback - * Callback function to report the result. - */ - void enableUsbRndis(in boolean enable, - in nsIEnableUsbRndisCallback callback); - - /** - * Update upstream. - * - * @param previous - * The previous internal and external interface. - * @param current - * The current internal and external interface. - * @param callback - * Callback function to report the result. - */ - void updateUpStream(in jsval previous, - in jsval current, - in nsIUpdateUpStreamCallback callback); - - /* - * Obtain interfaces list. - * - * @param callback - * Callback function to return the result. - */ - void getInterfaces(in nsIGetInterfacesCallback callback); - - /** - * Get config of a network interface. - * - * @param ifname - * Target interface. - * @param callback - * Callback function to report the result. - */ - void getInterfaceConfig(in DOMString ifname, in nsIGetInterfaceConfigCallback callback); - - /** - * Set config for a network interface. - * - * @param config - * .ifname: Target interface. - * .ip: Ip address. - * .prefix: mask length. - * .link: network link properties. - * @param callback - * Callback function to report the result. - */ - void setInterfaceConfig(in jsval config, in nsISetInterfaceConfigCallback callback); - - /** - * Configure a network interface. - * - * @param config - * An object containing the detail that we want to configure the interface: - * - * - ifname: string - * - ipaddr: long - * - mask: long - * - gateway: long - * - dns1: long - * - dns2: long - * - * @param callback - * Callback to notify the result of configurating network interface. - */ - void configureInterface(in jsval config, - in nsINativeCommandCallback callback); - - /** - * Issue a DHCP client request. - * - * @param networkInterface - * The network interface which we wnat to do the DHCP request on. - * - * @param callback - * Callback to notify the result of the DHCP request. - */ - void dhcpRequest(in DOMString interfaceName, - in nsIDhcpRequestCallback callback); - - /** - * Stop Dhcp daemon. - * - * @param ifname - * Target interface. - * - * @param callback - * Callback to notify the result of stopping dhcp request. - */ - void stopDhcp(in DOMString ifname, - in nsINativeCommandCallback callback); - - /** - * Enable a network interface. - * - * @param networkInterface - * The network interface name which we want to enable. - * - * @param callback - * Callback to notify the result of disabling network interface. - */ - void enableInterface(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Disable a network interface. - * - * @param networkInterface - * The network interface name which we want to disable. - * - * @param callback - * Callback to notify the result of disabling network interface. - */ - void disableInterface(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Reset all connections on a specified network interface. - * - * @param interfaceName - * The network interface name which we want to reset. - * - * @param callback - * Callback to notify the result of resetting connections. - */ - void resetConnections(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Create network (required to call prior to any networking operation). - * - * @param interfaceName - * The network interface name which we want to create network for. - * - * @param callback - * Callback to notify the result of creating network. - */ - void createNetwork(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Destroy network. - * - * @param interfaceName - * The network interface name of the network we want to destroy. - * - * @param callback - * Callback to notify the result of destroying network. - */ - void destroyNetwork(in DOMString interfaceName, - in nsINativeCommandCallback callback); - - /** - * Query the netId associated with given network interface name. - * - * @param interfaceName - * The network interface name which we want to query. - * - * @return A deferred promise that resolves with a string to indicate. - * the queried netId on success and rejects if the interface name - * is invalid. - * - */ - jsval getNetId(in DOMString interfaceName); - - /** - * Set maximum transmission unit on a network interface. - * - * @param interfaceName - * The name of the network interface that we want to set mtu. - * @param mtu - * Size of maximum tranmission unit. - * - * @param callback - * Callback to notify the result of setting mtu. - */ - void setMtu(in DOMString interfaceName, in long mtu, - in nsINativeCommandCallback callback); -}; diff --git a/dom/system/gonk/nsINetworkWorker.idl b/dom/system/gonk/nsINetworkWorker.idl deleted file mode 100644 index 8fe19be69..000000000 --- a/dom/system/gonk/nsINetworkWorker.idl +++ /dev/null @@ -1,18 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(98e31d3b-6cad-4cab-b4b3-4afff566ea65)] -interface nsINetworkEventListener : nsISupports { - void onEvent(in jsval result); -}; - -[scriptable, uuid(f9d9c694-0aac-4f9a-98ac-7788f954239a)] -interface nsINetworkWorker : nsISupports { - void start(in nsINetworkEventListener listener); - void shutdown(); - [implicit_jscontext] - void postMessage(in jsval options); -}; diff --git a/dom/system/gonk/nsIRadioInterfaceLayer.idl b/dom/system/gonk/nsIRadioInterfaceLayer.idl deleted file mode 100644 index 168fe3894..000000000 --- a/dom/system/gonk/nsIRadioInterfaceLayer.idl +++ /dev/null @@ -1,53 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsIIccInfo; -interface nsIMobileConnectionInfo; -interface nsIMobileMessageCallback; - -[scriptable, function, uuid(3bc96351-53b0-47a1-a888-c74c64b60f25)] -interface nsIRilSendWorkerMessageCallback : nsISupports -{ - boolean handleResponse(in jsval response); -}; - -[scriptable, uuid(1a3ef88a-e4d1-11e4-8512-176220f2b32b)] -interface nsIRadioInterface : nsISupports -{ - /** - * PDP APIs - * - * @param networkType - * Mobile network type, that is, nsINetworkInterface.NETWORK_TYPE_MOBILE - * or one of the nsINetworkInterface.NETWORK_TYPE_MOBILE_* values. - */ - void setupDataCallByType(in long networkType); - void deactivateDataCallByType(in long networkType); - long getDataCallStateByType(in long networkType); - - void updateRILNetworkInterface(); - - void sendWorkerMessage(in DOMString type, - [optional] in jsval message, - [optional] in nsIRilSendWorkerMessageCallback callback); -}; - -%{C++ -#define NS_RADIOINTERFACELAYER_CID \ - { 0x2d831c8d, 0x6017, 0x435b, \ - { 0xa8, 0x0c, 0xe5, 0xd4, 0x22, 0x81, 0x0c, 0xea } } -#define NS_RADIOINTERFACELAYER_CONTRACTID "@mozilla.org/ril;1" -%} - -[scriptable, uuid(09730e0d-75bb-4f21-8540-062a2eadc8ff)] -interface nsIRadioInterfaceLayer : nsISupports -{ - readonly attribute unsigned long numRadioInterfaces; - - nsIRadioInterface getRadioInterface(in unsigned long clientId); - - void setMicrophoneMuted(in boolean muted); -}; diff --git a/dom/system/gonk/nsISystemWorkerManager.idl b/dom/system/gonk/nsISystemWorkerManager.idl deleted file mode 100644 index a77e253e4..000000000 --- a/dom/system/gonk/nsISystemWorkerManager.idl +++ /dev/null @@ -1,16 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -/** - * Information about networks that is exposed to network manager API consumers. - */ -[scriptable, builtinclass, uuid(4984b669-0ee0-4809-ae96-3358a325a6b0)] -interface nsISystemWorkerManager : nsISupports -{ - [implicit_jscontext] - void registerRilWorker(in unsigned long aClientId, - in jsval aWorker); -}; diff --git a/dom/system/gonk/nsITetheringService.idl b/dom/system/gonk/nsITetheringService.idl deleted file mode 100644 index 530ab0069..000000000 --- a/dom/system/gonk/nsITetheringService.idl +++ /dev/null @@ -1,39 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -interface nsINetworkInterface; -interface nsIWifiTetheringCallback; - -[scriptable, uuid(779de2d3-6d29-4ee6-b069-6251839f757a)] -interface nsITetheringService : nsISupports -{ - const long TETHERING_STATE_INACTIVE = 0; - const long TETHERING_STATE_WIFI = 1; - const long TETHERING_STATE_USB = 2; - - /** - * Current tethering state. One of the TETHERING_STATE_* constants. - */ - readonly attribute long state; - - /** - * Enable or disable Wifi Tethering. - * - * @param enabled - * Boolean that indicates whether tethering should be enabled (true) or - * disabled (false). - * @param interfaceName - * The Wifi network interface name for internal interface. - * @param config - * The Wifi Tethering configuration from settings db. - * @param callback - * Callback function used to report status to WifiManager. - */ - void setWifiTethering(in boolean enabled, - in DOMString interfaceName, - in jsval config, - in nsIWifiTetheringCallback callback); -}; \ No newline at end of file diff --git a/dom/system/gonk/nsIVolume.idl b/dom/system/gonk/nsIVolume.idl deleted file mode 100644 index 60785f0a4..000000000 --- a/dom/system/gonk/nsIVolume.idl +++ /dev/null @@ -1,114 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" -#include "nsIVolumeStat.idl" - -[scriptable, uuid(EE752CB8-8FD7-11E4-A602-70221D5D46B0)] -interface nsIVolume : nsISupports -{ - // These MUST match the states from android's system/vold/Volume.h header - // Note: Changes made to the STATE_xxx names should also be reflected in the - // NS_VolumeStateStr function found in Volume.cpp - const long STATE_INIT = -1; - const long STATE_NOMEDIA = 0; - const long STATE_IDLE = 1; - const long STATE_PENDING = 2; - const long STATE_CHECKING = 3; - const long STATE_MOUNTED = 4; - const long STATE_UNMOUNTING = 5; - const long STATE_FORMATTING = 6; - const long STATE_SHARED = 7; - const long STATE_SHAREDMNT = 8; - const long STATE_CHECKMNT = 100; - const long STATE_MOUNT_FAIL = 101; - - // The name of the volume. Often there is only one volume, called sdcard. - // But some phones support multiple volumes. - readonly attribute DOMString name; - - // The mount point is the path on the system where the volume is mounted - // and is only valid when state == STATE_MOUNTED. - readonly attribute DOMString mountPoint; - - // Reflects the current state of the volume, using STATE_xxx constants - // from above. - readonly attribute long state; - - // mountGeneration is a unique number which is used distinguish between - // periods of time that a volume is in the mounted state. Each time a - // volume transitions to the mounted state, the mountGeneration will - // be different from the last time it transitioned to the mounted state. - readonly attribute long mountGeneration; - - // While a volume is mounted, it can be locked, preventing it from being - // shared with the PC. To lock a volume, acquire an MozWakeLock - // using the name of this attribute. Note that mountLockName changes - // every time the mountGeneration changes, so you'll need to reacquire - // the wakelock every time the volume becomes mounted. - readonly attribute DOMString mountLockName; - - // Determines if a mountlock is currently being held against this volume. - readonly attribute boolean isMountLocked; - - // Determines if media is actually present or not. Note, that when an sdcard - // is ejected, it may go through several tranistory states before finally - // arriving at STATE_NOMEDIA. So isMediaPresent may be false even when the - // current state isn't STATE_NOMEDIA. - readonly attribute boolean isMediaPresent; - - // Determines if the volume is currently being shared. This covers off - // more than just state == STATE_SHARED. isSharing will return true from the - // time that the volume leaves the mounted state, until it gets back to - // mounted, nomedia, or formatting states. This attribute is to allow - // device storage to suppress unwanted 'unavailable' status when - // transitioning from mounted to sharing and back again. - readonly attribute boolean isSharing; - - // Determines if the volume is currently formatting. This sets true once - // mFormatRequest == true and mState == STATE_MOUNTED, and sets false - // once the volume has been formatted and mounted again. - readonly attribute boolean isFormatting; - - readonly attribute boolean isUnmounting; - - nsIVolumeStat getStats(); - - // Formats the volume in IO thread, if the volume is ready to be formatted. - // Automounter will unmount it, format it and then mount it again. - void format(); - - // Mounts the volume in IO thread, if the volume is already unmounted. - // Automounter will mount it. Otherwise Automounter will skip this. - void mount(); - - // Unmounts the volume in IO thread, if the volume is already mounted. - // Automounter will unmount it. Otherwise Automounter will skip this. - void unmount(); - - // Whether this is a fake volume. - readonly attribute boolean isFake; - - // Whether this is a removable volume - readonly attribute boolean isRemovable; - - // Whether this is a hot-swappable volume - readonly attribute boolean isHotSwappable; - -}; - -%{C++ -// For use with the ObserverService -#define NS_VOLUME_STATE_CHANGED "volume-state-changed" -#define NS_VOLUME_REMOVED "volume-removed" - -namespace mozilla { -namespace system { - -// Convert a state into a loggable/printable string. -const char* NS_VolumeStateStr(int32_t aState); - -} // system -} // mozilla -%} diff --git a/dom/system/gonk/nsIVolumeMountLock.idl b/dom/system/gonk/nsIVolumeMountLock.idl deleted file mode 100644 index 0a9a1a5c2..000000000 --- a/dom/system/gonk/nsIVolumeMountLock.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(44449f34-5ca1-4aff-bce6-22c79263de24)] -interface nsIVolumeMountLock : nsISupports -{ - void unlock(); -}; - diff --git a/dom/system/gonk/nsIVolumeService.idl b/dom/system/gonk/nsIVolumeService.idl deleted file mode 100644 index d3752e201..000000000 --- a/dom/system/gonk/nsIVolumeService.idl +++ /dev/null @@ -1,36 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" -#include "nsIVolume.idl" -#include "nsIVolumeMountLock.idl" - -interface nsIArray; - -[scriptable, uuid(cfbf9880-cba5-11e4-8830-0800200c9a66)] -interface nsIVolumeService : nsISupports -{ - nsIVolume getVolumeByName(in DOMString volName); - nsIVolume getVolumeByPath(in DOMString path); - nsIVolume createOrGetVolumeByPath(in DOMString path); - - nsIVolumeMountLock createMountLock(in DOMString volName); - - nsIArray getVolumeNames(); - - void Dump(in DOMString label); - - /* for test case only to simulate sdcard insertion/removal */ - void createFakeVolume(in DOMString name, in DOMString path); - void SetFakeVolumeState(in DOMString name, in long state); - - /* for test case only to test removal of storage area */ - void removeFakeVolume(in DOMString name); -}; - -%{C++ -#define NS_VOLUMESERVICE_CID \ - {0x7c179fb7, 0x67a0, 0x43a3, {0x93, 0x37, 0x29, 0x4e, 0x03, 0x60, 0xb8, 0x58}} -#define NS_VOLUMESERVICE_CONTRACTID "@mozilla.org/telephony/volume-service;1" -%} diff --git a/dom/system/gonk/nsIVolumeStat.idl b/dom/system/gonk/nsIVolumeStat.idl deleted file mode 100644 index 1d725689d..000000000 --- a/dom/system/gonk/nsIVolumeStat.idl +++ /dev/null @@ -1,12 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(b4c050d0-c57a-11e1-9b21-0800200c9a66)] -interface nsIVolumeStat : nsISupports -{ - readonly attribute long long totalBytes; - readonly attribute long long freeBytes; -}; diff --git a/dom/system/gonk/nsIWorkerHolder.idl b/dom/system/gonk/nsIWorkerHolder.idl deleted file mode 100644 index e5cc82c9e..000000000 --- a/dom/system/gonk/nsIWorkerHolder.idl +++ /dev/null @@ -1,11 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(c04f3102-1ce8-4d57-9c27-8aece9c2740a)] -interface nsIWorkerHolder : nsISupports -{ - readonly attribute jsval worker; -}; diff --git a/dom/system/gonk/nsVolume.cpp b/dom/system/gonk/nsVolume.cpp deleted file mode 100644 index 77a1628e4..000000000 --- a/dom/system/gonk/nsVolume.cpp +++ /dev/null @@ -1,467 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolume.h" - -#include "base/message_loop.h" -#include "base/task.h" -#include "nsIPowerManagerService.h" -#include "nsISupportsUtils.h" -#include "nsIVolume.h" -#include "nsServiceManagerUtils.h" -#include "nsThreadUtils.h" -#include "nsVolumeStat.h" -#include "nsXULAppAPI.h" -#include "Volume.h" -#include "AutoMounter.h" -#include "VolumeManager.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "nsVolume" -#include "VolumeManagerLog.h" - -namespace mozilla { -namespace system { - -const char * -NS_VolumeStateStr(int32_t aState) -{ - switch (aState) { - case nsIVolume::STATE_INIT: return "Init"; - case nsIVolume::STATE_NOMEDIA: return "NoMedia"; - case nsIVolume::STATE_IDLE: return "Idle"; - case nsIVolume::STATE_PENDING: return "Pending"; - case nsIVolume::STATE_CHECKING: return "Checking"; - case nsIVolume::STATE_MOUNTED: return "Mounted"; - case nsIVolume::STATE_UNMOUNTING: return "Unmounting"; - case nsIVolume::STATE_FORMATTING: return "Formatting"; - case nsIVolume::STATE_SHARED: return "Shared"; - case nsIVolume::STATE_SHAREDMNT: return "Shared-Mounted"; - case nsIVolume::STATE_CHECKMNT: return "Check-Mounted"; - case nsIVolume::STATE_MOUNT_FAIL: return "Mount-Fail"; - } - return "???"; -} - -// While nsVolumes can only be used on the main thread, in the -// UpdateVolumeRunnable constructor (which is called from IOThread) we -// allocate an nsVolume which is then passed to MainThread. Since we -// have a situation where we allocate on one thread and free on another -// we use a thread safe AddRef implementation. -NS_IMPL_ISUPPORTS(nsVolume, nsIVolume) - -nsVolume::nsVolume(const Volume* aVolume) - : mName(NS_ConvertUTF8toUTF16(aVolume->Name())), - mMountPoint(NS_ConvertUTF8toUTF16(aVolume->MountPoint())), - mState(aVolume->State()), - mMountGeneration(aVolume->MountGeneration()), - mMountLocked(aVolume->IsMountLocked()), - mIsFake(!aVolume->CanBeShared()), - mIsMediaPresent(aVolume->MediaPresent()), - mIsSharing(aVolume->IsSharing()), - mIsFormatting(aVolume->IsFormatting()), - mIsUnmounting(aVolume->IsUnmounting()), - mIsRemovable(aVolume->IsRemovable()), - mIsHotSwappable(aVolume->IsHotSwappable()) -{ -} - -nsVolume::nsVolume(const nsVolume* aVolume) - : mName(aVolume->mName), - mMountPoint(aVolume->mMountPoint), - mState(aVolume->mState), - mMountGeneration(aVolume->mMountGeneration), - mMountLocked(aVolume->mMountLocked), - mIsFake(aVolume->mIsFake), - mIsMediaPresent(aVolume->mIsMediaPresent), - mIsSharing(aVolume->mIsSharing), - mIsFormatting(aVolume->mIsFormatting), - mIsUnmounting(aVolume->mIsUnmounting), - mIsRemovable(aVolume->mIsRemovable), - mIsHotSwappable(aVolume->mIsHotSwappable) -{ -} - -void nsVolume::Dump(const char* aLabel) const -{ - LOG("%s: Volume: %s is %s and %s @ %s gen %d locked %d", - aLabel, - NameStr().get(), - StateStr(), - IsMediaPresent() ? "inserted" : "missing", - MountPointStr().get(), - MountGeneration(), - (int)IsMountLocked()); - LOG("%s: IsSharing %s IsFormating %s IsUnmounting %s", - aLabel, - (IsSharing() ? "y" : "n"), - (IsFormatting() ? "y" : "n"), - (IsUnmounting() ? "y" : "n")); -} - -bool nsVolume::Equals(nsIVolume* aVolume) -{ - nsString volName; - aVolume->GetName(volName); - if (!mName.Equals(volName)) { - return false; - } - - nsString volMountPoint; - aVolume->GetMountPoint(volMountPoint); - if (!mMountPoint.Equals(volMountPoint)) { - return false; - } - - int32_t volState; - aVolume->GetState(&volState); - if (mState != volState){ - return false; - } - - int32_t volMountGeneration; - aVolume->GetMountGeneration(&volMountGeneration); - if (mMountGeneration != volMountGeneration) { - return false; - } - - bool volIsMountLocked; - aVolume->GetIsMountLocked(&volIsMountLocked); - if (mMountLocked != volIsMountLocked) { - return false; - } - - bool isFake; - aVolume->GetIsFake(&isFake); - if (mIsFake != isFake) { - return false; - } - - bool isSharing; - aVolume->GetIsSharing(&isSharing); - if (mIsSharing != isSharing) { - return false; - } - - bool isFormatting; - aVolume->GetIsFormatting(&isFormatting); - if (mIsFormatting != isFormatting) { - return false; - } - - bool isUnmounting; - aVolume->GetIsUnmounting(&isUnmounting); - if (mIsUnmounting != isUnmounting) { - return false; - } - - bool isRemovable; - aVolume->GetIsRemovable(&isRemovable); - if (mIsRemovable != isRemovable) { - return false; - } - - bool isHotSwappable; - aVolume->GetIsHotSwappable(&isHotSwappable); - if (mIsHotSwappable != isHotSwappable) { - return false; - } - - return true; -} - -NS_IMETHODIMP nsVolume::GetIsMediaPresent(bool* aIsMediaPresent) -{ - *aIsMediaPresent = mIsMediaPresent; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsMountLocked(bool* aIsMountLocked) -{ - *aIsMountLocked = mMountLocked; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsSharing(bool* aIsSharing) -{ - *aIsSharing = mIsSharing; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsFormatting(bool* aIsFormatting) -{ - *aIsFormatting = mIsFormatting; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsUnmounting(bool* aIsUnmounting) -{ - *aIsUnmounting = mIsUnmounting; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetName(nsAString& aName) -{ - aName = mName; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetMountGeneration(int32_t* aMountGeneration) -{ - *aMountGeneration = mMountGeneration; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetMountLockName(nsAString& aMountLockName) -{ - aMountLockName = NS_LITERAL_STRING("volume-") + Name(); - aMountLockName.AppendPrintf("-%d", mMountGeneration); - - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetMountPoint(nsAString& aMountPoint) -{ - aMountPoint = mMountPoint; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetState(int32_t* aState) -{ - *aState = mState; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetStats(nsIVolumeStat **aResult) -{ - if (mState != STATE_MOUNTED) { - return NS_ERROR_NOT_AVAILABLE; - } - - NS_IF_ADDREF(*aResult = new nsVolumeStat(mMountPoint)); - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsFake(bool *aIsFake) -{ - *aIsFake = mIsFake; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsRemovable(bool *aIsRemovable) -{ - *aIsRemovable = mIsRemovable; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::GetIsHotSwappable(bool *aIsHotSwappable) -{ - *aIsHotSwappable = mIsHotSwappable; - return NS_OK; -} - -NS_IMETHODIMP nsVolume::Format() -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(FormatVolumeIOThread, NameStr())); - - return NS_OK; -} - -/* static */ -void nsVolume::FormatVolumeIOThread(const nsCString& aVolume) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - - AutoMounterFormatVolume(aVolume); -} - -NS_IMETHODIMP nsVolume::Mount() -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(MountVolumeIOThread, NameStr())); - - return NS_OK; -} - -/* static */ -void nsVolume::MountVolumeIOThread(const nsCString& aVolume) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - - AutoMounterMountVolume(aVolume); -} - -NS_IMETHODIMP nsVolume::Unmount() -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(UnmountVolumeIOThread, NameStr())); - - return NS_OK; -} - -/* static */ -void nsVolume::UnmountVolumeIOThread(const nsCString& aVolume) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { - return; - } - - AutoMounterUnmountVolume(aVolume); -} - -void -nsVolume::LogState() const -{ - if (mState == nsIVolume::STATE_MOUNTED) { - LOG("nsVolume: %s state %s @ '%s' gen %d locked %d fake %d " - "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", - NameStr().get(), StateStr(), MountPointStr().get(), - MountGeneration(), (int)IsMountLocked(), (int)IsFake(), - (int)IsMediaPresent(), (int)IsSharing(), - (int)IsFormatting(), (int)IsUnmounting(), - (int)IsRemovable(), (int)IsHotSwappable()); - return; - } - - LOG("nsVolume: %s state %s", NameStr().get(), StateStr()); -} - -void nsVolume::UpdateMountLock(nsVolume* aOldVolume) -{ - MOZ_ASSERT(NS_IsMainThread()); - - bool oldMountLocked = aOldVolume ? aOldVolume->mMountLocked : false; - if (mState != nsIVolume::STATE_MOUNTED) { - // Since we're not in the mounted state, we need to - // forgot whatever mount generation we may have had. - mMountGeneration = -1; - mMountLocked = oldMountLocked; - return; - } - - int32_t oldMountGeneration = aOldVolume ? aOldVolume->mMountGeneration : -1; - if (mMountGeneration == oldMountGeneration) { - // No change in mount generation, nothing else to do - mMountLocked = oldMountLocked; - return; - } - - if (!XRE_IsParentProcess()) { - // Child processes just track the state, not maintain it. - return; - } - - // Notify the Volume on IOThread whether the volume is locked or not. - nsCOMPtr pmService = - do_GetService(POWERMANAGERSERVICE_CONTRACTID); - if (!pmService) { - return; - } - nsString mountLockName; - GetMountLockName(mountLockName); - nsString mountLockState; - pmService->GetWakeLockState(mountLockName, mountLockState); - UpdateMountLock(mountLockState); -} - -void -nsVolume::UpdateMountLock(const nsAString& aMountLockState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - // There are 3 states, unlocked, locked-background, and locked-foreground - // I figured it was easier to use negtive logic and compare for unlocked. - UpdateMountLock(!aMountLockState.EqualsLiteral("unlocked")); -} - -void -nsVolume::UpdateMountLock(bool aMountLocked) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - if (aMountLocked == mMountLocked) { - return; - } - // The locked/unlocked state changed. Tell IOThread about it. - mMountLocked = aMountLocked; - LogState(); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(Volume::UpdateMountLock, - NS_LossyConvertUTF16toASCII(Name()), - MountGeneration(), aMountLocked)); -} - -void -nsVolume::SetIsFake(bool aIsFake) -{ - mIsFake = aIsFake; - if (mIsFake) { - // The media is always present for fake volumes. - mIsMediaPresent = true; - MOZ_ASSERT(!mIsSharing); - } -} - -void -nsVolume::SetIsRemovable(bool aIsRemovable) -{ - mIsRemovable = aIsRemovable; - if (!mIsRemovable) { - mIsHotSwappable = false; - } -} - -void -nsVolume::SetIsHotSwappable(bool aIsHotSwappable) -{ - mIsHotSwappable = aIsHotSwappable; - if (mIsHotSwappable) { - mIsRemovable = true; - } -} - -void -nsVolume::SetState(int32_t aState) -{ - static int32_t sMountGeneration = 0; - - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsFake()); - - if (aState == mState) { - return; - } - - if (aState == nsIVolume::STATE_MOUNTED) { - mMountGeneration = ++sMountGeneration; - } - - mState = aState; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/nsVolume.h b/dom/system/gonk/nsVolume.h deleted file mode 100644 index 88be425f6..000000000 --- a/dom/system/gonk/nsVolume.h +++ /dev/null @@ -1,114 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolume_h__ -#define mozilla_system_nsvolume_h__ - -#include "nsCOMPtr.h" -#include "nsIVolume.h" -#include "nsString.h" -#include "nsTArray.h" - -namespace mozilla { -namespace system { - -class Volume; - -class nsVolume : public nsIVolume -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIVOLUME - - // This constructor is used by the UpdateVolumeRunnable constructor - nsVolume(const Volume* aVolume); - - // This constructor is used by nsVolumeService::SetFakeVolumeState - nsVolume(const nsVolume* aVolume); - - // This constructor is used by ContentChild::RecvFileSystemUpdate which is - // used to update the volume cache maintained in the child process. - nsVolume(const nsAString& aName, const nsAString& aMountPoint, - const int32_t& aState, const int32_t& aMountGeneration, - const bool& aIsMediaPresent, const bool& aIsSharing, - const bool& aIsFormatting, const bool& aIsFake, - const bool& aIsUnmounting, const bool& aIsRemovable, - const bool& aIsHotSwappable) - : mName(aName), - mMountPoint(aMountPoint), - mState(aState), - mMountGeneration(aMountGeneration), - mMountLocked(false), - mIsFake(aIsFake), - mIsMediaPresent(aIsMediaPresent), - mIsSharing(aIsSharing), - mIsFormatting(aIsFormatting), - mIsUnmounting(aIsUnmounting), - mIsRemovable(aIsRemovable), - mIsHotSwappable(aIsHotSwappable) - { - } - - bool Equals(nsIVolume* aVolume); - void UpdateMountLock(nsVolume* aOldVolume); - - void LogState() const; - - const nsString& Name() const { return mName; } - nsCString NameStr() const { return NS_LossyConvertUTF16toASCII(mName); } - - void Dump(const char* aLabel) const; - - int32_t MountGeneration() const { return mMountGeneration; } - bool IsMountLocked() const { return mMountLocked; } - - const nsString& MountPoint() const { return mMountPoint; } - nsCString MountPointStr() const { return NS_LossyConvertUTF16toASCII(mMountPoint); } - - int32_t State() const { return mState; } - const char* StateStr() const { return NS_VolumeStateStr(mState); } - - bool IsFake() const { return mIsFake; } - bool IsMediaPresent() const { return mIsMediaPresent; } - bool IsSharing() const { return mIsSharing; } - bool IsFormatting() const { return mIsFormatting; } - bool IsUnmounting() const { return mIsUnmounting; } - bool IsRemovable() const { return mIsRemovable; } - bool IsHotSwappable() const { return mIsHotSwappable; } - - typedef nsTArray > Array; - -private: - virtual ~nsVolume() {} // MozExternalRefCountType complains if this is non-virtual - - friend class nsVolumeService; // Calls the following XxxMountLock functions - void UpdateMountLock(const nsAString& aMountLockState); - void UpdateMountLock(bool aMountLocked); - - void SetIsFake(bool aIsFake); - void SetIsRemovable(bool aIsRemovable); - void SetIsHotSwappable(bool aIsHotSwappble); - void SetState(int32_t aState); - static void FormatVolumeIOThread(const nsCString& aVolume); - static void MountVolumeIOThread(const nsCString& aVolume); - static void UnmountVolumeIOThread(const nsCString& aVolume); - - nsString mName; - nsString mMountPoint; - int32_t mState; - int32_t mMountGeneration; - bool mMountLocked; - bool mIsFake; - bool mIsMediaPresent; - bool mIsSharing; - bool mIsFormatting; - bool mIsUnmounting; - bool mIsRemovable; - bool mIsHotSwappable; -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolume_h__ diff --git a/dom/system/gonk/nsVolumeMountLock.cpp b/dom/system/gonk/nsVolumeMountLock.cpp deleted file mode 100644 index 288c0f689..000000000 --- a/dom/system/gonk/nsVolumeMountLock.cpp +++ /dev/null @@ -1,171 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolumeMountLock.h" - -#include "mozilla/dom/ContentChild.h" -#include "mozilla/Services.h" - -#include "nsIObserverService.h" -#include "nsIPowerManagerService.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsString.h" -#include "nsXULAppAPI.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "nsVolumeMountLock" -#include "VolumeManagerLog.h" -#include "nsServiceManagerUtils.h" -#include "mozilla/dom/power/PowerManagerService.h" - -using namespace mozilla::dom; -using namespace mozilla::services; - -namespace mozilla { -namespace system { - -NS_IMPL_ISUPPORTS(nsVolumeMountLock, nsIVolumeMountLock, - nsIObserver, nsISupportsWeakReference) - -// static -already_AddRefed -nsVolumeMountLock::Create(const nsAString& aVolumeName) -{ - DBG("nsVolumeMountLock::Create called"); - - RefPtr mountLock = new nsVolumeMountLock(aVolumeName); - nsresult rv = mountLock->Init(); - NS_ENSURE_SUCCESS(rv, nullptr); - - return mountLock.forget(); -} - -nsVolumeMountLock::nsVolumeMountLock(const nsAString& aVolumeName) - : mVolumeName(aVolumeName), - mVolumeGeneration(-1), - mUnlocked(false) -{ -} - -//virtual -nsVolumeMountLock::~nsVolumeMountLock() -{ - Unlock(); -} - -nsresult nsVolumeMountLock::Init() -{ - LOG("nsVolumeMountLock created for '%s'", - NS_LossyConvertUTF16toASCII(mVolumeName).get()); - - // Add ourselves as an Observer. It's important that we use a weak - // reference here. If we used a strong reference, then that reference - // would prevent this object from being destructed. - nsCOMPtr obs = GetObserverService(); - obs->AddObserver(this, NS_VOLUME_STATE_CHANGED, true /*weak*/); - - // Get the initial mountGeneration and grab a lock. - nsCOMPtr vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID); - NS_ENSURE_TRUE(vs, NS_ERROR_FAILURE); - - nsCOMPtr vol; - nsresult rv = vs->GetVolumeByName(mVolumeName, getter_AddRefs(vol)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - rv = vol->GetMountGeneration(&mVolumeGeneration); - NS_ENSURE_SUCCESS(rv, rv); - - return Lock(vol); -} - -NS_IMETHODIMP nsVolumeMountLock::Unlock() -{ - LOG("nsVolumeMountLock released for '%s'", - NS_LossyConvertUTF16toASCII(mVolumeName).get()); - - mUnlocked = true; - mWakeLock = nullptr; - - // While we don't really need to remove weak observers, we do so anyways - // since it will reduce the number of times Observe gets called. - nsCOMPtr obs = GetObserverService(); - obs->RemoveObserver(this, NS_VOLUME_STATE_CHANGED); - return NS_OK; -} - -NS_IMETHODIMP nsVolumeMountLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData) -{ - if (strcmp(aTopic, NS_VOLUME_STATE_CHANGED) != 0) { - return NS_OK; - } - if (mUnlocked) { - // We're not locked anymore, so we don't need to look at the notifications. - return NS_OK; - } - - nsCOMPtr vol = do_QueryInterface(aSubject); - if (!vol) { - return NS_OK; - } - nsString volName; - vol->GetName(volName); - if (!volName.Equals(mVolumeName)) { - return NS_OK; - } - int32_t state; - nsresult rv = vol->GetState(&state); - NS_ENSURE_SUCCESS(rv, rv); - - if (state != nsIVolume::STATE_MOUNTED) { - mWakeLock = nullptr; - mVolumeGeneration = -1; - return NS_OK; - } - - int32_t mountGeneration; - rv = vol->GetMountGeneration(&mountGeneration); - NS_ENSURE_SUCCESS(rv, rv); - - DBG("nsVolumeMountLock::Observe mountGeneration = %d mVolumeGeneration = %d", - mountGeneration, mVolumeGeneration); - - if (mVolumeGeneration == mountGeneration) { - return NS_OK; - } - - // The generation changed, which means that any wakelock we may have - // been holding is now invalid. Grab a new wakelock for the new generation - // number. - - mWakeLock = nullptr; - mVolumeGeneration = mountGeneration; - - return Lock(vol); -} - -nsresult -nsVolumeMountLock::Lock(nsIVolume* aVolume) -{ - RefPtr pmService = - power::PowerManagerService::GetInstance(); - NS_ENSURE_TRUE(pmService, NS_ERROR_FAILURE); - - nsString mountLockName; - aVolume->GetMountLockName(mountLockName); - - ErrorResult err; - mWakeLock = pmService->NewWakeLock(mountLockName, nullptr, err); - if (err.Failed()) { - return err.StealNSResult(); - } - - LOG("nsVolumeMountLock acquired for '%s' gen %d", - NS_LossyConvertUTF16toASCII(mVolumeName).get(), mVolumeGeneration); - return NS_OK; -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/nsVolumeMountLock.h b/dom/system/gonk/nsVolumeMountLock.h deleted file mode 100644 index caf5b2ad5..000000000 --- a/dom/system/gonk/nsVolumeMountLock.h +++ /dev/null @@ -1,56 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolumemountlock_h__ -#define mozilla_system_nsvolumemountlock_h__ - -#include "nsIVolumeMountLock.h" - -#include "mozilla/dom/WakeLock.h" -#include "nsIObserver.h" -#include "nsString.h" -#include "nsTArray.h" -#include "nsWeakReference.h" - -class nsIVolume; - -namespace mozilla { -namespace system { - -/* The VolumeMountLock is designed so that it can be used in the Child or - * Parent process. While the VolumeMountLock object exists, then the - * VolumeManager/AutoMounter will prevent a mounted volume from being - * shared with the PC. - */ - -class nsVolumeMountLock final : public nsIVolumeMountLock, - public nsIObserver, - public nsSupportsWeakReference -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - NS_DECL_NSIVOLUMEMOUNTLOCK - - static already_AddRefed Create(const nsAString& volumeName); - - const nsString& VolumeName() const { return mVolumeName; } - -private: - nsVolumeMountLock(const nsAString& aVolumeName); - ~nsVolumeMountLock(); - - nsresult Init(); - nsresult Lock(nsIVolume* aVolume); - - RefPtr mWakeLock; - nsString mVolumeName; - int32_t mVolumeGeneration; - bool mUnlocked; -}; - -} // namespace system -} // namespace mozilla - -#endif // mozilla_system_nsvolumemountlock_h__ diff --git a/dom/system/gonk/nsVolumeService.cpp b/dom/system/gonk/nsVolumeService.cpp deleted file mode 100644 index 48d95c26a..000000000 --- a/dom/system/gonk/nsVolumeService.cpp +++ /dev/null @@ -1,553 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolumeService.h" - -#include "Volume.h" -#include "VolumeManager.h" -#include "VolumeServiceIOThread.h" - -#include "nsCOMPtr.h" -#include "nsDependentSubstring.h" -#include "nsIDOMWakeLockListener.h" -#include "nsIMutableArray.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsIPowerManagerService.h" -#include "nsISupportsPrimitives.h" -#include "nsISupportsUtils.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsLocalFile.h" -#include "nsServiceManagerUtils.h" -#include "nsString.h" -#include "nsTArray.h" -#include "nsThreadUtils.h" -#include "nsVolumeMountLock.h" -#include "nsXULAppAPI.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/Services.h" -#include "base/task.h" - -#undef VOLUME_MANAGER_LOG_TAG -#define VOLUME_MANAGER_LOG_TAG "nsVolumeService" -#include "VolumeManagerLog.h" - -#include - -using namespace mozilla::dom; -using namespace mozilla::services; - -namespace mozilla { -namespace system { - -NS_IMPL_ISUPPORTS(nsVolumeService, - nsIVolumeService, - nsIDOMMozWakeLockListener) - -StaticRefPtr nsVolumeService::sSingleton; - -// static -already_AddRefed -nsVolumeService::GetSingleton() -{ - MOZ_ASSERT(NS_IsMainThread()); - - if (!sSingleton) { - sSingleton = new nsVolumeService(); - } - RefPtr volumeService = sSingleton.get(); - return volumeService.forget(); -} - -// static -void -nsVolumeService::Shutdown() -{ - if (!sSingleton) { - return; - } - if (!XRE_IsParentProcess()) { - sSingleton = nullptr; - return; - } - - nsCOMPtr pmService = - do_GetService(POWERMANAGERSERVICE_CONTRACTID); - if (pmService) { - pmService->RemoveWakeLockListener(sSingleton.get()); - } - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownVolumeServiceIOThread)); - - sSingleton = nullptr; -} - -nsVolumeService::nsVolumeService() - : mArrayMonitor("nsVolumeServiceArray"), - mGotVolumesFromParent(false) -{ - sSingleton = this; - - if (!XRE_IsParentProcess()) { - // VolumeServiceIOThread and the WakeLock listener should only run in the - // parent, so we return early. - return; - } - - // Startup the IOThread side of things. The actual volume changes - // are captured by the IOThread and forwarded to main thread. - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(InitVolumeServiceIOThread, this)); - - nsCOMPtr pmService = - do_GetService(POWERMANAGERSERVICE_CONTRACTID); - if (!pmService) { - return; - } - pmService->AddWakeLockListener(this); -} - -nsVolumeService::~nsVolumeService() -{ -} - -// Callback for nsIDOMMozWakeLockListener -NS_IMETHODIMP -nsVolumeService::Callback(const nsAString& aTopic, const nsAString& aState) -{ - CheckMountLock(aTopic, aState); - return NS_OK; -} - -void nsVolumeService::DumpNoLock(const char* aLabel) -{ - mArrayMonitor.AssertCurrentThreadOwns(); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - - if (numVolumes == 0) { - LOG("%s: No Volumes!", aLabel); - return; - } - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = mVolumeArray[volIndex]; - vol->Dump(aLabel); - } -} - -NS_IMETHODIMP -nsVolumeService::Dump(const nsAString& aLabel) -{ - MonitorAutoLock autoLock(mArrayMonitor); - DumpNoLock(NS_LossyConvertUTF16toASCII(aLabel).get()); - return NS_OK; -} - -NS_IMETHODIMP nsVolumeService::GetVolumeByName(const nsAString& aVolName, nsIVolume **aResult) -{ - MonitorAutoLock autoLock(mArrayMonitor); - - RefPtr vol = FindVolumeByName(aVolName); - if (!vol) { - return NS_ERROR_NOT_AVAILABLE; - } - - vol.forget(aResult); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::GetVolumeByPath(const nsAString& aPath, nsIVolume **aResult) -{ - NS_ConvertUTF16toUTF8 utf8Path(aPath); - char realPathBuf[PATH_MAX]; - - while (realpath(utf8Path.get(), realPathBuf) < 0) { - if (errno != ENOENT) { - ERR("GetVolumeByPath: realpath on '%s' failed: %d", utf8Path.get(), errno); - return NSRESULT_FOR_ERRNO(); - } - // The pathname we were passed doesn't exist, so we try stripping off trailing - // components until we get a successful call to realpath, or until we run out - // of components (if we finally get to /something then we also stop). - int32_t slashIndex = utf8Path.RFindChar('/'); - if ((slashIndex == kNotFound) || (slashIndex == 0)) { - errno = ENOENT; - ERR("GetVolumeByPath: realpath on '%s' failed.", utf8Path.get()); - return NSRESULT_FOR_ERRNO(); - } - utf8Path.Assign(Substring(utf8Path, 0, slashIndex)); - } - - // The volume mount point is always a directory. Something like /mnt/sdcard - // Once we have a full qualified pathname with symlinks removed (which is - // what realpath does), we basically check if aPath starts with the mount - // point, but we don't want to have /mnt/sdcard match /mnt/sdcardfoo but we - // do want it to match /mnt/sdcard/foo - // So we add a trailing slash to the mount point and the pathname passed in - // prior to doing the comparison. - - strlcat(realPathBuf, "/", sizeof(realPathBuf)); - - MonitorAutoLock autoLock(mArrayMonitor); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = mVolumeArray[volIndex]; - NS_ConvertUTF16toUTF8 volMountPointSlash(vol->MountPoint()); - volMountPointSlash.Append('/'); - nsDependentCSubstring testStr(realPathBuf, volMountPointSlash.Length()); - if (volMountPointSlash.Equals(testStr)) { - vol.forget(aResult); - return NS_OK; - } - } - return NS_ERROR_FILE_NOT_FOUND; -} - -NS_IMETHODIMP -nsVolumeService::CreateOrGetVolumeByPath(const nsAString& aPath, nsIVolume** aResult) -{ - nsresult rv = GetVolumeByPath(aPath, aResult); - if (rv == NS_OK) { - return NS_OK; - } - - // In order to support queries by the updater, we will fabricate a volume - // from the pathname, so that the caller can determine the volume size. - nsCOMPtr vol = new nsVolume(NS_LITERAL_STRING("fake"), - aPath, nsIVolume::STATE_MOUNTED, - -1 /* generation */, - true /* isMediaPresent*/, - false /* isSharing */, - false /* isFormatting */, - true /* isFake */, - false /* isUnmounting */, - false /* isRemovable */, - false /* isHotSwappable*/); - vol.forget(aResult); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::GetVolumeNames(nsIArray** aVolNames) -{ - NS_ENSURE_ARG_POINTER(aVolNames); - MonitorAutoLock autoLock(mArrayMonitor); - - *aVolNames = nullptr; - - nsresult rv; - nsCOMPtr volNames = - do_CreateInstance(NS_ARRAY_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = mVolumeArray[volIndex]; - nsCOMPtr isupportsString = - do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - rv = isupportsString->SetData(vol->Name()); - NS_ENSURE_SUCCESS(rv, rv); - - rv = volNames->AppendElement(isupportsString, false); - NS_ENSURE_SUCCESS(rv, rv); - } - - volNames.forget(aVolNames); - return NS_OK; -} - -void -nsVolumeService::GetVolumesForIPC(nsTArray* aResult) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - MonitorAutoLock autoLock(mArrayMonitor); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = mVolumeArray[volIndex]; - VolumeInfo* volInfo = aResult->AppendElement(); - - volInfo->name() = vol->mName; - volInfo->mountPoint() = vol->mMountPoint; - volInfo->volState() = vol->mState; - volInfo->mountGeneration() = vol->mMountGeneration; - volInfo->isMediaPresent() = vol->mIsMediaPresent; - volInfo->isSharing() = vol->mIsSharing; - volInfo->isFormatting() = vol->mIsFormatting; - volInfo->isFake() = vol->mIsFake; - volInfo->isUnmounting() = vol->mIsUnmounting; - volInfo->isRemovable() = vol->mIsRemovable; - volInfo->isHotSwappable() = vol->mIsHotSwappable; - } -} - -void -nsVolumeService::RecvVolumesFromParent(const nsTArray& aVolumes) -{ - if (XRE_IsParentProcess()) { - // We are the parent. Therefore our volumes are already correct. - return; - } - if (mGotVolumesFromParent) { - // We've already done this, no need to do it again. - return; - } - - for (uint32_t i = 0; i < aVolumes.Length(); i++) { - const VolumeInfo& volInfo(aVolumes[i]); - RefPtr vol = new nsVolume(volInfo.name(), - volInfo.mountPoint(), - volInfo.volState(), - volInfo.mountGeneration(), - volInfo.isMediaPresent(), - volInfo.isSharing(), - volInfo.isFormatting(), - volInfo.isFake(), - volInfo.isUnmounting(), - volInfo.isRemovable(), - volInfo.isHotSwappable()); - UpdateVolume(vol, false); - } -} - -NS_IMETHODIMP -nsVolumeService::CreateMountLock(const nsAString& aVolumeName, nsIVolumeMountLock **aResult) -{ - nsCOMPtr mountLock = nsVolumeMountLock::Create(aVolumeName); - if (!mountLock) { - return NS_ERROR_NOT_AVAILABLE; - } - mountLock.forget(aResult); - return NS_OK; -} - -void -nsVolumeService::CheckMountLock(const nsAString& aMountLockName, - const nsAString& aMountLockState) -{ - MOZ_ASSERT(XRE_IsParentProcess()); - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr vol = FindVolumeByMountLockName(aMountLockName); - if (vol) { - vol->UpdateMountLock(aMountLockState); - } -} - -already_AddRefed -nsVolumeService::FindVolumeByMountLockName(const nsAString& aMountLockName) -{ - MonitorAutoLock autoLock(mArrayMonitor); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = mVolumeArray[volIndex]; - nsString mountLockName; - vol->GetMountLockName(mountLockName); - if (mountLockName.Equals(aMountLockName)) { - return vol.forget(); - } - } - return nullptr; -} - -already_AddRefed -nsVolumeService::FindVolumeByName(const nsAString& aName, nsVolume::Array::index_type* aIndex) -{ - mArrayMonitor.AssertCurrentThreadOwns(); - - nsVolume::Array::size_type numVolumes = mVolumeArray.Length(); - nsVolume::Array::index_type volIndex; - for (volIndex = 0; volIndex < numVolumes; volIndex++) { - RefPtr vol = mVolumeArray[volIndex]; - if (vol->Name().Equals(aName)) { - if (aIndex) { - *aIndex = volIndex; - } - return vol.forget(); - } - } - return nullptr; -} - -void -nsVolumeService::UpdateVolume(nsVolume* aVolume, bool aNotifyObservers) -{ - MOZ_ASSERT(NS_IsMainThread()); - - { - MonitorAutoLock autoLock(mArrayMonitor); - nsVolume::Array::index_type volIndex; - RefPtr vol = FindVolumeByName(aVolume->Name(), &volIndex); - if (!vol) { - mVolumeArray.AppendElement(aVolume); - } else if (vol->Equals(aVolume) || (!vol->IsFake() && aVolume->IsFake())) { - // Ignore if nothing changed or if a fake tries to override a real volume. - return; - } else { - mVolumeArray.ReplaceElementAt(volIndex, aVolume); - } - aVolume->UpdateMountLock(vol); - } - - if (!aNotifyObservers) { - return; - } - - nsCOMPtr obs = GetObserverService(); - if (!obs) { - return; - } - NS_ConvertUTF8toUTF16 stateStr(aVolume->StateStr()); - obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get()); -} - -NS_IMETHODIMP -nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path) -{ - if (XRE_IsParentProcess()) { - RefPtr vol = new nsVolume(name, path, nsIVolume::STATE_INIT, - -1 /* mountGeneration */, - true /* isMediaPresent */, - false /* isSharing */, - false /* isFormatting */, - true /* isFake */, - false /* isUnmounting */, - false /* isRemovable */, - false /* isHotSwappable */); - vol->SetState(nsIVolume::STATE_MOUNTED); - vol->LogState(); - UpdateVolume(vol.get()); - return NS_OK; - } - - ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path)); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state) -{ - if (XRE_IsParentProcess()) { - RefPtr vol; - { - MonitorAutoLock autoLock(mArrayMonitor); - vol = FindVolumeByName(name); - } - if (!vol || !vol->IsFake()) { - return NS_ERROR_NOT_AVAILABLE; - } - - // Clone the existing volume so we can replace it - RefPtr volume = new nsVolume(vol); - volume->SetState(state); - volume->LogState(); - UpdateVolume(volume.get()); - return NS_OK; - } - - ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state); - return NS_OK; -} - -NS_IMETHODIMP -nsVolumeService::RemoveFakeVolume(const nsAString& name) -{ - if (XRE_IsParentProcess()) { - SetFakeVolumeState(name, nsIVolume::STATE_NOMEDIA); - RemoveVolumeByName(name); - return NS_OK; - } - - ContentChild::GetSingleton()->SendRemoveFakeVolume(nsString(name)); - return NS_OK; -} - -void -nsVolumeService::RemoveVolumeByName(const nsAString& aName) -{ - { - MonitorAutoLock autoLock(mArrayMonitor); - nsVolume::Array::index_type volIndex; - RefPtr vol = FindVolumeByName(aName, &volIndex); - if (!vol) { - return; - } - mVolumeArray.RemoveElementAt(volIndex); - } - - if (XRE_IsParentProcess()) { - nsCOMPtr obs = GetObserverService(); - if (!obs) { - return; - } - obs->NotifyObservers(nullptr, NS_VOLUME_REMOVED, nsString(aName).get()); - } -} - -/*************************************************************************** -* The UpdateVolumeRunnable creates an nsVolume and updates the main thread -* data structure while running on the main thread. -*/ -class UpdateVolumeRunnable : public Runnable -{ -public: - UpdateVolumeRunnable(nsVolumeService* aVolumeService, const Volume* aVolume) - : mVolumeService(aVolumeService), - mVolume(new nsVolume(aVolume)) - { - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - DBG("UpdateVolumeRunnable::Run '%s' state %s gen %d locked %d " - "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", - mVolume->NameStr().get(), mVolume->StateStr(), - mVolume->MountGeneration(), (int)mVolume->IsMountLocked(), - (int)mVolume->IsMediaPresent(), mVolume->IsSharing(), - mVolume->IsFormatting(), mVolume->IsUnmounting(), - (int)mVolume->IsRemovable(), (int)mVolume->IsHotSwappable()); - - mVolumeService->UpdateVolume(mVolume); - mVolumeService = nullptr; - mVolume = nullptr; - return NS_OK; - } - -private: - RefPtr mVolumeService; - RefPtr mVolume; -}; - -void -nsVolumeService::UpdateVolumeIOThread(const Volume* aVolume) -{ - DBG("UpdateVolumeIOThread: Volume '%s' state %s mount '%s' gen %d locked %d " - "media %d sharing %d formatting %d unmounting %d removable %d hotswappable %d", - aVolume->NameStr(), aVolume->StateStr(), aVolume->MountPoint().get(), - aVolume->MountGeneration(), (int)aVolume->IsMountLocked(), - (int)aVolume->MediaPresent(), (int)aVolume->IsSharing(), - (int)aVolume->IsFormatting(), (int)aVolume->IsUnmounting(), - (int)aVolume->IsRemovable(), (int)aVolume->IsHotSwappable()); - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - NS_DispatchToMainThread(new UpdateVolumeRunnable(this, aVolume)); -} - -} // namespace system -} // namespace mozilla diff --git a/dom/system/gonk/nsVolumeService.h b/dom/system/gonk/nsVolumeService.h deleted file mode 100644 index 9bddc0b8f..000000000 --- a/dom/system/gonk/nsVolumeService.h +++ /dev/null @@ -1,78 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolumeservice_h__ -#define mozilla_system_nsvolumeservice_h__ - -#include "mozilla/Monitor.h" -#include "mozilla/RefPtr.h" -#include "mozilla/StaticPtr.h" -#include "nsCOMPtr.h" -#include "nsIDOMWakeLockListener.h" -#include "nsIVolume.h" -#include "nsIVolumeService.h" -#include "nsVolume.h" - -namespace mozilla { - -namespace dom { -class VolumeInfo; -} // dom - -namespace system { - -class Volume; - -/*************************************************************************** -* The nsVolumeData class encapsulates the data that is updated/maintained -* on the main thread in order to support the nsIVolume and nsIVolumeService -* classes. -*/ - -class nsVolumeService final : public nsIVolumeService, - public nsIDOMMozWakeLockListener -{ -public: - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIVOLUMESERVICE - NS_DECL_NSIDOMMOZWAKELOCKLISTENER - - nsVolumeService(); - - static already_AddRefed GetSingleton(); - //static nsVolumeService* GetSingleton(); - static void Shutdown(); - - void DumpNoLock(const char* aLabel); - - // To use this function, you have to create a new volume and pass it in. - void UpdateVolume(nsVolume* aVolume, bool aNotifyObservers = true); - void UpdateVolumeIOThread(const Volume* aVolume); - - void RecvVolumesFromParent(const nsTArray& aVolumes); - void GetVolumesForIPC(nsTArray* aResult); - - void RemoveVolumeByName(const nsAString& aName); - -private: - ~nsVolumeService(); - - void CheckMountLock(const nsAString& aMountLockName, - const nsAString& aMountLockState); - already_AddRefed FindVolumeByMountLockName(const nsAString& aMountLockName); - - already_AddRefed FindVolumeByName(const nsAString& aName, - nsVolume::Array::index_type* aIndex = nullptr); - - Monitor mArrayMonitor; - nsVolume::Array mVolumeArray; - - static StaticRefPtr sSingleton; - bool mGotVolumesFromParent; -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolumeservice_h__ diff --git a/dom/system/gonk/nsVolumeStat.cpp b/dom/system/gonk/nsVolumeStat.cpp deleted file mode 100644 index 11976237f..000000000 --- a/dom/system/gonk/nsVolumeStat.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsVolumeStat.h" -#include "nsString.h" - -namespace mozilla { -namespace system { - -NS_IMPL_ISUPPORTS(nsVolumeStat, nsIVolumeStat) - -nsVolumeStat::nsVolumeStat(const nsAString& aPath) -{ - if (statfs(NS_ConvertUTF16toUTF8(aPath).get(), &mStat) != 0) { - memset(&mStat, 0, sizeof(mStat)); - } -} - -NS_IMETHODIMP nsVolumeStat::GetTotalBytes(int64_t* aTotalBytes) -{ - *aTotalBytes = mStat.f_blocks * mStat.f_bsize; - return NS_OK; -} - -NS_IMETHODIMP nsVolumeStat::GetFreeBytes(int64_t* aFreeBytes) -{ - *aFreeBytes = mStat.f_bfree * mStat.f_bsize; - return NS_OK; -} - -} // system -} // mozilla diff --git a/dom/system/gonk/nsVolumeStat.h b/dom/system/gonk/nsVolumeStat.h deleted file mode 100644 index 2ca03ed46..000000000 --- a/dom/system/gonk/nsVolumeStat.h +++ /dev/null @@ -1,33 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_system_nsvolumestat_h__ -#define mozilla_system_nsvolumestat_h__ - -#include "nsIVolumeStat.h" -#include "nsString.h" -#include - -namespace mozilla { -namespace system { - -class nsVolumeStat final : public nsIVolumeStat -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSIVOLUMESTAT - - nsVolumeStat(const nsAString& aPath); - -protected: - ~nsVolumeStat() {} - -private: - struct statfs mStat; -}; - -} // system -} // mozilla - -#endif // mozilla_system_nsvolumestat_h__ diff --git a/dom/system/gonk/ril_consts.js b/dom/system/gonk/ril_consts.js deleted file mode 100644 index af5b9d8e1..000000000 --- a/dom/system/gonk/ril_consts.js +++ /dev/null @@ -1,3338 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -// Set to true to debug all RIL layers -this.DEBUG_ALL = false; - -// Set individually to debug specific layers -this.DEBUG_WORKER = false || DEBUG_ALL; -this.DEBUG_CONTENT_HELPER = false || DEBUG_ALL; -this.DEBUG_RIL = false || DEBUG_ALL; - -this.REQUEST_GET_SIM_STATUS = 1; -this.REQUEST_ENTER_SIM_PIN = 2; -this.REQUEST_ENTER_SIM_PUK = 3; -this.REQUEST_ENTER_SIM_PIN2 = 4; -this.REQUEST_ENTER_SIM_PUK2 = 5; -this.REQUEST_CHANGE_SIM_PIN = 6; -this.REQUEST_CHANGE_SIM_PIN2 = 7; -this.REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE = 8; -this.REQUEST_GET_CURRENT_CALLS = 9; -this.REQUEST_DIAL = 10; -this.REQUEST_GET_IMSI = 11; -this.REQUEST_HANGUP = 12; -this.REQUEST_HANGUP_WAITING_OR_BACKGROUND = 13; -this.REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND = 14; -this.REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE = 15; -this.REQUEST_CONFERENCE = 16; -this.REQUEST_UDUB = 17; -this.REQUEST_LAST_CALL_FAIL_CAUSE = 18; -this.REQUEST_SIGNAL_STRENGTH = 19; -this.REQUEST_VOICE_REGISTRATION_STATE = 20; -this.REQUEST_DATA_REGISTRATION_STATE = 21; -this.REQUEST_OPERATOR = 22; -this.REQUEST_RADIO_POWER = 23; -this.REQUEST_DTMF = 24; -this.REQUEST_SEND_SMS = 25; -this.REQUEST_SEND_SMS_EXPECT_MORE = 26; -this.REQUEST_SETUP_DATA_CALL = 27; -this.REQUEST_SIM_IO = 28; -this.REQUEST_SEND_USSD = 29; -this.REQUEST_CANCEL_USSD = 30; -this.REQUEST_GET_CLIR = 31; -this.REQUEST_SET_CLIR = 32; -this.REQUEST_QUERY_CALL_FORWARD_STATUS = 33; -this.REQUEST_SET_CALL_FORWARD = 34; -this.REQUEST_QUERY_CALL_WAITING = 35; -this.REQUEST_SET_CALL_WAITING = 36; -this.REQUEST_SMS_ACKNOWLEDGE = 37; -this.REQUEST_GET_IMEI = 38; -this.REQUEST_GET_IMEISV = 39; -this.REQUEST_ANSWER = 40; -this.REQUEST_DEACTIVATE_DATA_CALL = 41; -this.REQUEST_QUERY_FACILITY_LOCK = 42; -this.REQUEST_SET_FACILITY_LOCK = 43; -this.REQUEST_CHANGE_BARRING_PASSWORD = 44; -this.REQUEST_QUERY_NETWORK_SELECTION_MODE = 45; -this.REQUEST_SET_NETWORK_SELECTION_AUTOMATIC = 46; -this.REQUEST_SET_NETWORK_SELECTION_MANUAL = 47; -this.REQUEST_QUERY_AVAILABLE_NETWORKS = 48; -this.REQUEST_DTMF_START = 49; -this.REQUEST_DTMF_STOP = 50; -this.REQUEST_BASEBAND_VERSION = 51; -this.REQUEST_SEPARATE_CONNECTION = 52; -this.REQUEST_SET_MUTE = 53; -this.REQUEST_GET_MUTE = 54; -this.REQUEST_QUERY_CLIP = 55; -this.REQUEST_LAST_DATA_CALL_FAIL_CAUSE = 56; -this.REQUEST_DATA_CALL_LIST = 57; -this.REQUEST_RESET_RADIO = 58; -this.REQUEST_OEM_HOOK_RAW = 59; -this.REQUEST_OEM_HOOK_STRINGS = 60; -this.REQUEST_SCREEN_STATE = 61; -this.REQUEST_SET_SUPP_SVC_NOTIFICATION = 62; -this.REQUEST_WRITE_SMS_TO_SIM = 63; -this.REQUEST_DELETE_SMS_ON_SIM = 64; -this.REQUEST_SET_BAND_MODE = 65; -this.REQUEST_QUERY_AVAILABLE_BAND_MODE = 66; -this.REQUEST_STK_GET_PROFILE = 67; -this.REQUEST_STK_SET_PROFILE = 68; -this.REQUEST_STK_SEND_ENVELOPE_COMMAND = 69; -this.REQUEST_STK_SEND_TERMINAL_RESPONSE = 70; -this.REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM = 71; -this.REQUEST_EXPLICIT_CALL_TRANSFER = 72; -this.REQUEST_SET_PREFERRED_NETWORK_TYPE = 73; -this.REQUEST_GET_PREFERRED_NETWORK_TYPE = 74; -this.REQUEST_GET_NEIGHBORING_CELL_IDS = 75; -this.REQUEST_SET_LOCATION_UPDATES = 76; -this.REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE = 77; -this.REQUEST_CDMA_SET_ROAMING_PREFERENCE = 78; -this.REQUEST_CDMA_QUERY_ROAMING_PREFERENCE = 79; -this.REQUEST_SET_TTY_MODE = 80; -this.REQUEST_QUERY_TTY_MODE = 81; -this.REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE = 82; -this.REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE = 83; -this.REQUEST_CDMA_FLASH = 84; -this.REQUEST_CDMA_BURST_DTMF = 85; -this.REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY = 86; -this.REQUEST_CDMA_SEND_SMS = 87; -this.REQUEST_CDMA_SMS_ACKNOWLEDGE = 88; -this.REQUEST_GSM_GET_BROADCAST_SMS_CONFIG = 89; -this.REQUEST_GSM_SET_BROADCAST_SMS_CONFIG = 90; -this.REQUEST_GSM_SMS_BROADCAST_ACTIVATION = 91; -this.REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG = 92; -this.REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG = 93; -this.REQUEST_CDMA_SMS_BROADCAST_ACTIVATION = 94; -this.REQUEST_CDMA_SUBSCRIPTION = 95; -this.REQUEST_CDMA_WRITE_SMS_TO_RUIM = 96; -this.REQUEST_CDMA_DELETE_SMS_ON_RUIM = 97; -this.REQUEST_DEVICE_IDENTITY = 98; -this.REQUEST_EXIT_EMERGENCY_CALLBACK_MODE = 99; -this.REQUEST_GET_SMSC_ADDRESS = 100; -this.REQUEST_SET_SMSC_ADDRESS = 101; -this.REQUEST_REPORT_SMS_MEMORY_STATUS = 102; -this.REQUEST_REPORT_STK_SERVICE_IS_RUNNING = 103; -this.REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE = 104; -this.REQUEST_ISIM_AUTHENTICATION = 105; -this.REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU = 106; -this.REQUEST_STK_SEND_ENVELOPE_WITH_STATUS = 107; -this.REQUEST_VOICE_RADIO_TECH = 108; -this.REQUEST_GET_CELL_INFO_LIST = 109; -this.REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE = 110; -this.REQUEST_SET_INITIAL_ATTACH_APN = 111; -this.REQUEST_IMS_REGISTRATION_STATE = 112; -this.REQUEST_IMS_SEND_SMS = 113; -this.REQUEST_SIM_TRANSMIT_APDU_BASIC = 114; -this.REQUEST_SIM_OPEN_CHANNEL = 115; -this.REQUEST_SIM_CLOSE_CHANNEL = 116; -this.REQUEST_SIM_TRANSMIT_APDU_CHANNEL = 117; -this.REQUEST_NV_READ_ITEM = 118; -this.REQUEST_NV_WRITE_ITEM = 119; -this.REQUEST_NV_WRITE_CDMA_PRL = 120; -this.REQUEST_NV_RESET_CONFIG = 121; -this.REQUEST_SET_UICC_SUBSCRIPTION = 122; -this.REQUEST_ALLOW_DATA = 123; -this.REQUEST_GET_HARDWARE_CONFIG = 124; -this.REQUEST_SIM_AUTHENTICATION = 125; -this.REQUEST_GET_DC_RT_INFO = 126; -this.REQUEST_SET_DC_RT_INFO_RATE = 127; -this.REQUEST_SET_DATA_PROFILE = 128; -this.REQUEST_SHUTDOWN = 129; - -// CAF specific parcel type. It should be synced with latest version. But CAF -// doesn't have l version for b2g yet, so we set REQUEST_SET_DATA_SUBSCRIPTION -// to a value that won't get conflict with known AOSP parcel. -this.REQUEST_SET_DATA_SUBSCRIPTION = 130; - -// Mozilla specific parcel type. -this.REQUEST_GET_UNLOCK_RETRY_COUNT = 150; - -// Fugu specific parcel types. -this.RIL_REQUEST_GPRS_ATTACH = 5018; -this.RIL_REQUEST_GPRS_DETACH = 5019; - -// Galaxy S2 specific parcel type. -this.REQUEST_DIAL_EMERGENCY_CALL = 10016; - -this.RESPONSE_TYPE_SOLICITED = 0; -this.RESPONSE_TYPE_UNSOLICITED = 1; - -this.UNSOLICITED_RESPONSE_BASE = 1000; -this.UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED = 1000; -this.UNSOLICITED_RESPONSE_CALL_STATE_CHANGED = 1001; -this.UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED = 1002; -this.UNSOLICITED_RESPONSE_NEW_SMS = 1003; -this.UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT = 1004; -this.UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM = 1005; -this.UNSOLICITED_ON_USSD = 1006; -this.UNSOLICITED_ON_USSD_REQUEST = 1007; -this.UNSOLICITED_NITZ_TIME_RECEIVED = 1008; -this.UNSOLICITED_SIGNAL_STRENGTH = 1009; -this.UNSOLICITED_DATA_CALL_LIST_CHANGED = 1010; -this.UNSOLICITED_SUPP_SVC_NOTIFICATION = 1011; -this.UNSOLICITED_STK_SESSION_END = 1012; -this.UNSOLICITED_STK_PROACTIVE_COMMAND = 1013; -this.UNSOLICITED_STK_EVENT_NOTIFY = 1014; -this.UNSOLICITED_STK_CALL_SETUP = 1015; -this.UNSOLICITED_SIM_SMS_STORAGE_FULL = 1016; -this.UNSOLICITED_SIM_REFRESH = 1017; -this.UNSOLICITED_CALL_RING = 1018; -this.UNSOLICITED_RESPONSE_SIM_STATUS_CHANGED = 1019; -this.UNSOLICITED_RESPONSE_CDMA_NEW_SMS = 1020; -this.UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS = 1021; -this.UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FULL = 1022; -this.UNSOLICITED_RESTRICTED_STATE_CHANGED = 1023; -this.UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE = 1024; -this.UNSOLICITED_CDMA_CALL_WAITING = 1025; -this.UNSOLICITED_CDMA_OTA_PROVISION_STATUS = 1026; -this.UNSOLICITED_CDMA_INFO_REC = 1027; -this.UNSOLICITED_OEM_HOOK_RAW = 1028; -this.UNSOLICITED_RINGBACK_TONE = 1029; -this.UNSOLICITED_RESEND_INCALL_MUTE = 1030; -this.UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED = 1031; -this.UNSOLICITED_CDMA_PRL_CHANGED = 1032; -this.UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE = 1033; -this.UNSOLICITED_RIL_CONNECTED = 1034; -this.UNSOLICITED_VOICE_RADIO_TECH_CHANGED = 1035; -this.UNSOLICITED_CELL_INFO_LIST = 1036; -this.UNSOLICITED_RESPONSE_IMS_NETWORK_STATE_CHANGED = 1037; -this.UNSOLICITED_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038; -this.UNSOLICITED_SRVCC_STATE_NOTIFY = 1039; -this.UNSOLICITED_HARDWARE_CONFIG_CHANGED = 1040; -this.UNSOLICITED_DC_RT_INFO_CHANGED = 1041; - -this.ERROR_SUCCESS = 0; -this.ERROR_RADIO_NOT_AVAILABLE = 1; -this.ERROR_GENERIC_FAILURE = 2; -this.ERROR_PASSWORD_INCORRECT = 3; -this.ERROR_SIM_PIN2 = 4; -this.ERROR_SIM_PUK2 = 5; -this.ERROR_REQUEST_NOT_SUPPORTED = 6; -this.ERROR_CANCELLED = 7; -this.ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL = 8; -this.ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = 9; -this.ERROR_SMS_SEND_FAIL_RETRY = 10; -this.ERROR_SIM_ABSENT = 11; -this.ERROR_SUBSCRIPTION_NOT_AVAILABLE = 12; -this.ERROR_MODE_NOT_SUPPORTED = 13; -this.ERROR_FDN_CHECK_FAILURE = 14; -this.ERROR_ILLEGAL_SIM_OR_ME = 15; -this.ERROR_MISSING_RESOURCE = 16; -this.ERROR_NO_SUCH_ELEMENT = 17; - -this.GECKO_ERROR_RADIO_NOT_AVAILABLE = "RadioNotAvailable"; -this.GECKO_ERROR_GENERIC_FAILURE = "GenericFailure"; -this.GECKO_ERROR_PASSWORD_INCORRECT = "IncorrectPassword"; -this.GECKO_ERROR_SIM_PIN2 = "SimPin2"; -this.GECKO_ERROR_SIM_PUK2 = "SimPuk2"; -this.GECKO_ERROR_REQUEST_NOT_SUPPORTED = "RequestNotSupported"; -this.GECKO_ERROR_CANCELLED = "Cancelled"; -this.GECKO_ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL = "OpNotAllowedDuringVoiceCall"; -this.GECKO_ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW = "OpNotAllowedBeforeRegToNw"; -this.GECKO_ERROR_SMS_SEND_FAIL_RETRY = "SmsSendFailRetry"; -this.GECKO_ERROR_SIM_ABSENT = "SimAbsent"; -this.GECKO_ERROR_SUBSCRIPTION_NOT_AVAILABLE = "SubscriptionNotAvailable"; -this.GECKO_ERROR_MODE_NOT_SUPPORTED = "ModeNotSupported"; -this.GECKO_ERROR_FDN_CHECK_FAILURE = "FdnCheckFailure"; -this.GECKO_ERROR_ILLEGAL_SIM_OR_ME = "IllegalSIMorME"; -this.GECKO_ERROR_MISSING_RESOURCE = "MissingResource"; -this.GECKO_ERROR_NO_SUCH_ELEMENT = "NoSuchElement"; -this.GECKO_ERROR_INVALID_PARAMETER = "InvalidParameter"; -this.GECKO_ERROR_UNSPECIFIED_ERROR = "UnspecifiedError"; - -this.RIL_ERROR_TO_GECKO_ERROR = {}; -RIL_ERROR_TO_GECKO_ERROR[ERROR_RADIO_NOT_AVAILABLE] = GECKO_ERROR_RADIO_NOT_AVAILABLE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_GENERIC_FAILURE] = GECKO_ERROR_GENERIC_FAILURE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_PASSWORD_INCORRECT] = GECKO_ERROR_PASSWORD_INCORRECT; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SIM_PIN2] = GECKO_ERROR_SIM_PIN2; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SIM_PUK2] = GECKO_ERROR_SIM_PUK2; -RIL_ERROR_TO_GECKO_ERROR[ERROR_REQUEST_NOT_SUPPORTED] = GECKO_ERROR_REQUEST_NOT_SUPPORTED; -RIL_ERROR_TO_GECKO_ERROR[ERROR_CANCELLED] = GECKO_ERROR_CANCELLED; -RIL_ERROR_TO_GECKO_ERROR[ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL] = GECKO_ERROR_OP_NOT_ALLOWED_DURING_VOICE_CALL; -RIL_ERROR_TO_GECKO_ERROR[ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW] = GECKO_ERROR_OP_NOT_ALLOWED_BEFORE_REG_TO_NW; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SMS_SEND_FAIL_RETRY] = GECKO_ERROR_SMS_SEND_FAIL_RETRY; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SIM_ABSENT] = GECKO_ERROR_SIM_ABSENT; -RIL_ERROR_TO_GECKO_ERROR[ERROR_SUBSCRIPTION_NOT_AVAILABLE] = GECKO_ERROR_SUBSCRIPTION_NOT_AVAILABLE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_MODE_NOT_SUPPORTED] = GECKO_ERROR_MODE_NOT_SUPPORTED; -RIL_ERROR_TO_GECKO_ERROR[ERROR_FDN_CHECK_FAILURE] = GECKO_ERROR_FDN_CHECK_FAILURE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_ILLEGAL_SIM_OR_ME] = GECKO_ERROR_ILLEGAL_SIM_OR_ME; -RIL_ERROR_TO_GECKO_ERROR[ERROR_MISSING_RESOURCE] = GECKO_ERROR_MISSING_RESOURCE; -RIL_ERROR_TO_GECKO_ERROR[ERROR_NO_SUCH_ELEMENT] = GECKO_ERROR_NO_SUCH_ELEMENT; - -// 3GPP 23.040 clause 9.2.3.6 TP-Message-Reference(TP-MR): -// The number of times the MS automatically repeats the SMS-SUBMIT shall be in -// the range 1 to 3 but the precise number is an implementation matter. -this.SMS_RETRY_MAX = 3; - -this.RADIO_STATE_OFF = 0; -this.RADIO_STATE_UNAVAILABLE = 1; -this.RADIO_STATE_ON = 10; // since RIL v7 - -this.CARD_STATE_ABSENT = 0; -this.CARD_STATE_PRESENT = 1; -this.CARD_STATE_ERROR = 2; - -this.CARD_PERSOSUBSTATE_UNKNOWN = 0; -this.CARD_PERSOSUBSTATE_IN_PROGRESS = 1; -this.CARD_PERSOSUBSTATE_READY = 2; -this.CARD_PERSOSUBSTATE_SIM_NETWORK = 3; -this.CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET = 4; -this.CARD_PERSOSUBSTATE_SIM_CORPORATE = 5; -this.CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER = 6; -this.CARD_PERSOSUBSTATE_SIM_SIM = 7; -this.CARD_PERSOSUBSTATE_SIM_NETWORK_PUK = 8; -this.CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK = 9; -this.CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK = 10; -this.CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK = 11; -this.CARD_PERSOSUBSTATE_SIM_SIM_PUK = 12; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK1 = 13; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK2 = 14; -this.CARD_PERSOSUBSTATE_RUIM_HRPD = 15; -this.CARD_PERSOSUBSTATE_RUIM_CORPORATE = 16; -this.CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER = 17; -this.CARD_PERSOSUBSTATE_RUIM_RUIM = 18; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK = 19; -this.CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK = 20; -this.CARD_PERSOSUBSTATE_RUIM_HRPD_PUK = 21; -this.CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK = 22; -this.CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK = 23; -this.CARD_PERSOSUBSTATE_RUIM_RUIM_PUK = 24; - -this.CARD_APPSTATE_ILLEGAL = -1; -this.CARD_APPSTATE_UNKNOWN = 0; -this.CARD_APPSTATE_DETECTED = 1; -this.CARD_APPSTATE_PIN = 2; // If PIN1 or UPin is required. -this.CARD_APPSTATE_PUK = 3; // If PUK1 or Puk for UPin is required. -this.CARD_APPSTATE_SUBSCRIPTION_PERSO = 4; // perso_substate should be looked - // at when app_state is assigned - // to this value. -this.CARD_APPSTATE_READY = 5; - -this.CARD_PINSTATE_UNKNOWN = 0; -this.CARD_PINSTATE_ENABLED_NOT_VERIFIED = 1; -this.CARD_PINSTATE_ENABLED_VERIFIED = 2; -this.CARD_PINSTATE_DISABLED = 3; -this.CARD_PINSTATE_ENABLED_BLOCKED = 4; -this.CARD_PINSTATE_ENABLED_PERM_BLOCKED = 5; - -this.CARD_APPTYPE_UNKNOWN = 0; -this.CARD_APPTYPE_SIM = 1; -this.CARD_APPTYPE_USIM = 2; -this.CARD_APPTYPE_RUIM = 3; -this.CARD_APPTYPE_CSIM = 4; -this.CARD_APPTYPE_ISIM = 5; - -this.CARD_MAX_APPS = 8; - -this.GECKO_CARD_TYPE = [ - null, - "sim", - "usim", - "ruim", - "csim", - "isim" -]; - - -// Used for QUERY_AVAILABLE_NETWORKS status. -this.QAN_STATE_UNKNOWN = "unknown"; -this.QAN_STATE_AVAILABLE = "available"; -this.QAN_STATE_CURRENT = "current"; -this.QAN_STATE_FORBIDDEN = "forbidden"; - -// Must be in sync with MobileNetworkState of MozMobileNetworkInfo.webidl -this.GECKO_QAN_STATE_UNKNOWN = null; -this.GECKO_QAN_STATE_AVAILABLE = "available"; -this.GECKO_QAN_STATE_CONNECTED = "connected"; -this.GECKO_QAN_STATE_FORBIDDEN = "forbidden"; - -this.RIL_QAN_STATE_TO_GECKO_STATE = {}; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_UNKNOWN] = this.GECKO_QAN_STATE_UNKNOWN; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_AVAILABLE] = this.GECKO_QAN_STATE_AVAILABLE; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_CURRENT] = this.GECKO_QAN_STATE_CONNECTED; -this.RIL_QAN_STATE_TO_GECKO_STATE[this.QAN_STATE_FORBIDDEN] = this.GECKO_QAN_STATE_FORBIDDEN; - -this.NETWORK_SELECTION_MODE_AUTOMATIC = 0; -this.NETWORK_SELECTION_MODE_MANUAL = 1; - -this.NETWORK_INFO_VOICE_REGISTRATION_STATE = "voiceRegistrationState"; -this.NETWORK_INFO_DATA_REGISTRATION_STATE = "dataRegistrationState"; -this.NETWORK_INFO_OPERATOR = "operator"; -this.NETWORK_INFO_NETWORK_SELECTION_MODE = "networkSelectionMode"; -this.NETWORK_INFO_SIGNAL = "signal"; -this.NETWORK_INFO_MESSAGE_TYPES = [ - NETWORK_INFO_VOICE_REGISTRATION_STATE, - NETWORK_INFO_DATA_REGISTRATION_STATE, - NETWORK_INFO_OPERATOR, - NETWORK_INFO_NETWORK_SELECTION_MODE, - NETWORK_INFO_SIGNAL -]; - -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM = "wcdma/gsm"; -this.GECKO_PREFERRED_NETWORK_TYPE_GSM_ONLY = "gsm"; -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_ONLY = "wcdma"; -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_AUTO = "wcdma/gsm-auto"; -this.GECKO_PREFERRED_NETWORK_TYPE_CDMA_EVDO = "cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_CDMA_ONLY = "cdma"; -this.GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY = "evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO = "wcdma/gsm/cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO = "lte/cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM = "lte/wcdma/gsm"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA = "lte/wcdma"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO = "lte/wcdma/gsm/cdma/evdo"; -this.GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY = "lte"; -this.RIL_PREFERRED_NETWORK_TYPE_TO_GECKO = [ - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM, - GECKO_PREFERRED_NETWORK_TYPE_GSM_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_AUTO, - GECKO_PREFERRED_NETWORK_TYPE_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_CDMA_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_EVDO_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_WCDMA_GSM_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM, - GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA_GSM_CDMA_EVDO, - GECKO_PREFERRED_NETWORK_TYPE_LTE_ONLY, - GECKO_PREFERRED_NETWORK_TYPE_LTE_WCDMA -]; - -this.GECKO_SUPPORTED_NETWORK_TYPES_DEFAULT = "gsm,wcdma"; -// Index-item pair must be in sync with nsIMobileConnection.MOBILE_NETWORK_TYPE_* -this.GECKO_SUPPORTED_NETWORK_TYPES = [ - "gsm", - "wcdma", - "cdma", - "evdo", - "lte" -]; - -// Network registration states. See TS 27.007 7.2 -this.NETWORK_CREG_STATE_NOT_SEARCHING = 0; -this.NETWORK_CREG_STATE_REGISTERED_HOME = 1; -this.NETWORK_CREG_STATE_SEARCHING = 2; -this.NETWORK_CREG_STATE_DENIED = 3; -this.NETWORK_CREG_STATE_UNKNOWN = 4; -this.NETWORK_CREG_STATE_REGISTERED_ROAMING = 5; -this.NETWORK_CREG_STATE_NOT_SEARCHING_EMERGENCY_CALLS = 10; -this.NETWORK_CREG_STATE_SEARCHING_EMERGENCY_CALLS = 12; -this.NETWORK_CREG_STATE_DENIED_EMERGENCY_CALLS = 13; -this.NETWORK_CREG_STATE_UNKNOWN_EMERGENCY_CALLS = 14; - -this.NETWORK_CREG_TECH_UNKNOWN = 0; -this.NETWORK_CREG_TECH_GPRS = 1; -this.NETWORK_CREG_TECH_EDGE = 2; -this.NETWORK_CREG_TECH_UMTS = 3; -this.NETWORK_CREG_TECH_IS95A = 4; -this.NETWORK_CREG_TECH_IS95B = 5; -this.NETWORK_CREG_TECH_1XRTT = 6; -this.NETWORK_CREG_TECH_EVDO0 = 7; -this.NETWORK_CREG_TECH_EVDOA = 8; -this.NETWORK_CREG_TECH_HSDPA = 9; -this.NETWORK_CREG_TECH_HSUPA = 10; -this.NETWORK_CREG_TECH_HSPA = 11; -this.NETWORK_CREG_TECH_EVDOB = 12; -this.NETWORK_CREG_TECH_EHRPD = 13; -this.NETWORK_CREG_TECH_LTE = 14; -this.NETWORK_CREG_TECH_HSPAP = 15; -this.NETWORK_CREG_TECH_GSM = 16; -this.NETWORK_CREG_TECH_DCHSPAP_1 = 18; // Some devices reports as 18 -this.NETWORK_CREG_TECH_DCHSPAP_2 = 19; // Some others report it as 19 - -this.CELL_INFO_TYPE_GSM = 1; -this.CELL_INFO_TYPE_CDMA = 2; -this.CELL_INFO_TYPE_LTE = 3; -this.CELL_INFO_TYPE_WCDMA = 4; - -this.CALL_STATE_UNKNOWN = -1; -this.CALL_STATE_ACTIVE = 0; -this.CALL_STATE_HOLDING = 1; -this.CALL_STATE_DIALING = 2; -this.CALL_STATE_ALERTING = 3; -this.CALL_STATE_INCOMING = 4; -this.CALL_STATE_WAITING = 5; - -this.TOA_INTERNATIONAL = 0x91; -this.TOA_UNKNOWN = 0x81; - -this.CALL_PRESENTATION_ALLOWED = 0; -this.CALL_PRESENTATION_RESTRICTED = 1; -this.CALL_PRESENTATION_UNKNOWN = 2; -this.CALL_PRESENTATION_PAYPHONE = 3; - -// Call forwarding actions, see TS 27.007 7.11 "mode" -this.CALL_FORWARD_ACTION_QUERY_STATUS = 2; - -// ICC commands, see TS 27.007 +CRSM commands -this.ICC_COMMAND_SEEK = 0xa2; -this.ICC_COMMAND_READ_BINARY = 0xb0; -this.ICC_COMMAND_READ_RECORD = 0xb2; -this.ICC_COMMAND_GET_RESPONSE = 0xc0; -this.ICC_COMMAND_UPDATE_BINARY = 0xd6; -this.ICC_COMMAND_UPDATE_RECORD = 0xdc; - -// ICC constants, GSM SIM file ids from TS 51.011 -this.ICC_EF_ICCID = 0x2fe2; -this.ICC_EF_IMG = 0x4f20; -this.ICC_EF_PBR = 0x4f30; -this.ICC_EF_PLMNsel = 0x6f30; // PLMN for SIM -this.ICC_EF_SST = 0x6f38; -this.ICC_EF_UST = 0x6f38; // For USIM -this.ICC_EF_ADN = 0x6f3a; -this.ICC_EF_FDN = 0x6f3b; -this.ICC_EF_SMS = 0x6f3c; -this.ICC_EF_GID1 = 0x6f3e; -this.ICC_EF_MSISDN = 0x6f40; -this.ICC_EF_CBMI = 0x6f45; -this.ICC_EF_SPN = 0x6f46; -this.ICC_EF_CBMID = 0x6f48; -this.ICC_EF_SDN = 0x6f49; -this.ICC_EF_EXT1 = 0x6f4a; -this.ICC_EF_EXT2 = 0x6f4b; -this.ICC_EF_EXT3 = 0x6f4c; -this.ICC_EF_CBMIR = 0x6f50; -this.ICC_EF_AD = 0x6fad; -this.ICC_EF_PHASE = 0x6fae; -this.ICC_EF_PNN = 0x6fc5; -this.ICC_EF_OPL = 0x6fc6; -this.ICC_EF_MBDN = 0x6fc7; -this.ICC_EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN] -this.ICC_EF_MBI = 0x6fc9; -this.ICC_EF_MWIS = 0x6fca; -this.ICC_EF_CFIS = 0x6fcb; -this.ICC_EF_SPDI = 0x6fcd; - -// CPHS files to be supported -this.ICC_EF_CPHS_INFO = 0x6f16; // CPHS Information -this.ICC_EF_CPHS_MBN = 0x6f17; // Mailbox Numbers - -// CSIM files -this.ICC_EF_CSIM_IMSI_M = 0x6f22; -this.ICC_EF_CSIM_CDMAHOME = 0x6f28; -this.ICC_EF_CSIM_CST = 0x6f32; // CDMA Service table -this.ICC_EF_CSIM_SPN = 0x6f41; - -this.ICC_PHASE_1 = 0x00; -this.ICC_PHASE_2 = 0x02; -this.ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED = 0x03; - -// Types of files TS 11.11 9.3 -this.TYPE_RFU = 0; -this.TYPE_MF = 1; -this.TYPE_DF = 2; -this.TYPE_EF = 4; - -this.RESPONSE_DATA_FILE_SIZE = 2; -this.RESPONSE_DATA_FILE_ID_1 = 4; -this.RESPONSE_DATA_FILE_ID_2 = 5; -this.RESPONSE_DATA_FILE_TYPE = 6; -this.RESPONSE_DATA_RFU_3 = 7; -this.RESPONSE_DATA_ACCESS_CONDITION_1 = 8; -this.RESPONSE_DATA_ACCESS_CONDITION_2 = 9; -this.RESPONSE_DATA_ACCESS_CONDITION_3 = 10; -this.RESPONSE_DATA_FILE_STATUS = 11; -this.RESPONSE_DATA_LENGTH = 12; -this.RESPONSE_DATA_STRUCTURE = 13; -this.RESPONSE_DATA_RECORD_LENGTH = 14; - -// Structure of files TS 11.11 9.3 -this.EF_STRUCTURE_TRANSPARENT = 0; -this.EF_STRUCTURE_LINEAR_FIXED = 1; -this.EF_STRUCTURE_CYCLIC = 3; - -// TS 102.221 11.1.1.4.3 Table 11.5: File descriptor byte. -this.UICC_EF_STRUCTURE = {}; -this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_TRANSPARENT]= 1; -this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_LINEAR_FIXED]= 2; -this.UICC_EF_STRUCTURE[this.EF_STRUCTURE_CYCLIC]= 6; - -// Status code of EFsms -// see 3GPP TS 51.011 clause 10.5.3 -this.EFSMS_STATUS_FREE = 0x00; -this.EFSMS_STATUS_READ = 0x01; -this.EFSMS_STATUS_TO_BE_READ = 0x03; -this.EFSMS_STATUS_TO_BE_SENT = 0x07; - -// Total size of ADN footer(the size of Alpha identifier excluded). -// See TS 151.011 clause 10.5.1 EF_ADN. -this.ADN_FOOTER_SIZE_BYTES = 14; -// Maximum size of BCD numbers in ADN. -// See TS 151.011 clause 10.5.1 EF_ADN, 'Length of BCD number/SSC contents'. -this.ADN_MAX_BCD_NUMBER_BYTES = 11; -// Maximum digits of the Dialling Number in ADN. -// See TS 151.011 clause 10.5.1 EF_ADN, 'Dialling Number'. -this.ADN_MAX_NUMBER_DIGITS = 20; -// Maximum size of BCD numbers in EXT. -// See TS 151.011 clause 10.5.10 EF_EXT1, 'Extension data'. -this.EXT_MAX_BCD_NUMBER_BYTES = 10; -// Maximum digits of the Dialling Number in EXT. -// See TS 151.011 clause 10.5.10 EF_EXT1, 'Extension data'. -this.EXT_MAX_NUMBER_DIGITS = 20; - -// READ_RECORD mode, TS 102.221 -this.READ_RECORD_ABSOLUTE_MODE = 4; - -// TS 102.221 Table 11.2, return FCP template -this.GET_RESPONSE_FCP_TEMPLATE = 4; - -// GET_RESPONSE mandatory response size for EF, see TS 51.011 clause 9, -// 'Response data in case of an EF.' -this.GET_RESPONSE_EF_SIZE_BYTES = 15; - -// EF path -this.EF_PATH_MF_SIM = "3f00"; -this.EF_PATH_DF_PHONEBOOK = "5f3a"; -this.EF_PATH_GRAPHICS = "5f50"; -this.EF_PATH_DF_TELECOM = "7f10"; -this.EF_PATH_DF_GSM = "7f20"; -this.EF_PATH_DF_CDMA = "7f25"; -this.EF_PATH_ADF_USIM = "7fff"; - -// Status code of sw1 for ICC I/O, -// see GSM11.11 and TS 51.011 clause 9.4, and ISO 7816-4 -this.ICC_STATUS_NORMAL_ENDING = 0x90; -this.ICC_STATUS_NORMAL_ENDING_WITH_EXTRA = 0x91; -this.ICC_STATUS_SAT_BUSY = 0x93; -this.ICC_STATUS_WITH_SIM_DATA = 0x9e; -this.ICC_STATUS_WITH_RESPONSE_DATA = 0x9f; -this.ICC_STATUS_ERROR_WRONG_LENGTH = 0x67; -this.ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED = 0x69; -this.ICC_STATUS_ERROR_WRONG_PARAMETERS = 0x6a; - -// ICC call barring facility. -// TS 27.007, clause 7.4, +CLCK -this.ICC_CB_FACILITY_SIM = "SC"; -this.ICC_CB_FACILITY_FDN = "FD"; -this.ICC_CB_FACILITY_BAOC = "AO"; -this.ICC_CB_FACILITY_BAOIC = "OI"; -this.ICC_CB_FACILITY_BAOICxH = "OX"; -this.ICC_CB_FACILITY_BAIC = "AI"; -this.ICC_CB_FACILITY_BAICr = "IR"; -this.ICC_CB_FACILITY_BA_ALL = "AB"; -this.ICC_CB_FACILITY_BA_MO = "AG"; -this.ICC_CB_FACILITY_BA_MT = "AC"; - -// ICC service class -// TS 27.007, clause 7.4, +CLCK -this.ICC_SERVICE_CLASS_NONE = 0; // no user input -this.ICC_SERVICE_CLASS_VOICE = (1 << 0); -this.ICC_SERVICE_CLASS_DATA = (1 << 1); -this.ICC_SERVICE_CLASS_FAX = (1 << 2); -this.ICC_SERVICE_CLASS_SMS = (1 << 3); -this.ICC_SERVICE_CLASS_DATA_SYNC = (1 << 4); -this.ICC_SERVICE_CLASS_DATA_ASYNC = (1 << 5); -this.ICC_SERVICE_CLASS_PACKET = (1 << 6); -this.ICC_SERVICE_CLASS_PAD = (1 << 7); -this.ICC_SERVICE_CLASS_MAX = (1 << 7); // Max ICC_SERVICE_CLASS value - -// ICC lock-selection codes -// TS 27.007, clause 8.65, +CPINR -this.ICC_SEL_CODE_SIM_PIN = "SIM PIN"; -this.ICC_SEL_CODE_SIM_PUK = "SIM PUK"; -this.ICC_SEL_CODE_PH_SIM_PIN = "PH-SIM PIN"; -this.ICC_SEL_CODE_PH_FSIM_PIN = "PH-FSIM PIN"; -this.ICC_SEL_CODE_PH_FSIM_PUK = "PH-FSIM PUK"; -this.ICC_SEL_CODE_SIM_PIN2 = "SIM PIN2"; -this.ICC_SEL_CODE_SIM_PUK2 = "SIM PUK2"; -this.ICC_SEL_CODE_PH_NET_PIN = "PH-NET PIN"; -this.ICC_SEL_CODE_PH_NET_PUK = "PH-NET PUK"; -this.ICC_SEL_CODE_PH_NETSUB_PIN = "PH-NETSUB PIN"; -this.ICC_SEL_CODE_PH_NETSUB_PUK = "PH-NETSUB PUK"; -this.ICC_SEL_CODE_PH_SP_PIN = "PH-SP PIN"; -this.ICC_SEL_CODE_PH_SP_PUK = "PH-SP PUK"; -this.ICC_SEL_CODE_PH_CORP_PIN = "PH-CORP PIN"; -this.ICC_SEL_CODE_PH_CORP_PUK = "PH-CORP PUK"; -// TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM @ -// ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_PCK. - -this.ICC_USIM_TYPE1_TAG = 0xa8; -this.ICC_USIM_TYPE2_TAG = 0xa9; -this.ICC_USIM_TYPE3_TAG = 0xaa; -this.ICC_USIM_EFADN_TAG = 0xc0; -this.ICC_USIM_EFIAP_TAG = 0xc1; -this.ICC_USIM_EFEXT1_TAG = 0xc2; -this.ICC_USIM_EFSNE_TAG = 0xc3; -this.ICC_USIM_EFANR_TAG = 0xc4; -this.ICC_USIM_EFPBC_TAG = 0xc5; -this.ICC_USIM_EFGRP_TAG = 0xc6; -this.ICC_USIM_EFAAS_TAG = 0xc7; -this.ICC_USIM_EFGSD_TAG = 0xc8; -this.ICC_USIM_EFUID_TAG = 0xc9; -this.ICC_USIM_EFEMAIL_TAG = 0xca; -this.ICC_USIM_EFCCP1_TAG = 0xcb; - -// ICC image coding scheme -// TS 31.102, sub-clause 4.6.1.1 -this.ICC_IMG_CODING_SCHEME_BASIC = 0x11; -this.ICC_IMG_CODING_SCHEME_COLOR = 0x21; -this.ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY = 0x22; - -// Must be in sync with enum IccImageCodingScheme in MozStkCommandEvent.webidl. -this.GECKO_IMG_CODING_SCHEME_BASIC = "basic"; -this.GECKO_IMG_CODING_SCHEME_COLOR = "color"; -this.GECKO_IMG_CODING_SCHEME_COLOR_TRANSPARENCY = "color-transparency"; - -this.ICC_IMG_CODING_SCHEME_TO_GECKO = {}; -ICC_IMG_CODING_SCHEME_TO_GECKO[ICC_IMG_CODING_SCHEME_BASIC] = GECKO_IMG_CODING_SCHEME_BASIC; -ICC_IMG_CODING_SCHEME_TO_GECKO[ICC_IMG_CODING_SCHEME_COLOR] = GECKO_IMG_CODING_SCHEME_COLOR; -ICC_IMG_CODING_SCHEME_TO_GECKO[ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY] = GECKO_IMG_CODING_SCHEME_COLOR_TRANSPARENCY; - -// ICC image header size per coding scheme -// TS 31.102, Annex B -this.ICC_IMG_HEADER_SIZE_BASIC = 2; -this.ICC_IMG_HEADER_SIZE_COLOR = 6; - -this.ICC_CLUT_ENTRY_SIZE = 3; - -this.USIM_PBR_ANR = "anr"; -this.USIM_PBR_ANR0 = "anr0"; -this.USIM_PBR_EMAIL = "email"; - -// Current supported fields. Adding more fields to read will increasing I/O -// time dramatically, do check the performance is acceptable when you add -// more fields. -this.USIM_PBR_FIELDS = [USIM_PBR_EMAIL, USIM_PBR_ANR0]; - -this.USIM_TAG_NAME = {}; -this.USIM_TAG_NAME[ICC_USIM_EFADN_TAG] = "adn"; -this.USIM_TAG_NAME[ICC_USIM_EFIAP_TAG] ="iap"; -this.USIM_TAG_NAME[ICC_USIM_EFEXT1_TAG] = "ext1"; -this.USIM_TAG_NAME[ICC_USIM_EFSNE_TAG] = "sne"; -this.USIM_TAG_NAME[ICC_USIM_EFANR_TAG] = "anr"; -this.USIM_TAG_NAME[ICC_USIM_EFPBC_TAG] = "pbc"; -this.USIM_TAG_NAME[ICC_USIM_EFGRP_TAG] = "grp"; -this.USIM_TAG_NAME[ICC_USIM_EFAAS_TAG] = "aas"; -this.USIM_TAG_NAME[ICC_USIM_EFGSD_TAG] = "gsd"; -this.USIM_TAG_NAME[ICC_USIM_EFUID_TAG] = "uid"; -this.USIM_TAG_NAME[ICC_USIM_EFEMAIL_TAG] = "email"; -this.USIM_TAG_NAME[ICC_USIM_EFCCP1_TAG] = "ccp1"; - -// Error message for ICC contact. -this.CONTACT_ERR_REQUEST_NOT_SUPPORTED = GECKO_ERROR_REQUEST_NOT_SUPPORTED; -this.CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED = "ContactTypeNotSupported"; -this.CONTACT_ERR_FIELD_NOT_SUPPORTED = "FieldNotSupported"; -this.CONTACT_ERR_NO_FREE_RECORD_FOUND = "NoFreeRecordFound"; -this.CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK = "CannotAccessPhoneBook"; - -// CDMA IMSI_M's byte const. -// 3GPP2 C.S0065 Sec. 5.2.2 -this.CSIM_IMSI_M_MIN2_BYTE = 1; -this.CSIM_IMSI_M_MIN1_BYTE = 3; -this.CSIM_IMSI_M_MNC_BYTE = 6; -this.CSIM_IMSI_M_PROGRAMMED_BYTE = 7; -this.CSIM_IMSI_M_MCC_BYTE = 8; - -/** - * Tags for Ber Tlv. - * See 3GPP TS 101 220 clause 7.2 - Assigned TLV tag values. - */ -this.BER_UNKNOWN_TAG = 0x00; -this.BER_FCP_TEMPLATE_TAG = 0x62; -this.BER_FCP_FILE_SIZE_DATA_TAG = 0x80; -this.BER_FCP_FILE_SIZE_TOTAL_TAG = 0x81; -this.BER_FCP_FILE_DESCRIPTOR_TAG = 0x82; -this.BER_FCP_FILE_IDENTIFIER_TAG = 0x83; -this.BER_FCP_DF_NAME_TAG = 0x84; // AID. -this.BER_FCP_PROPRIETARY_PRIMITIVE_TAG = 0x85; -this.BER_FCP_SFI_SUPPORT_TAG = 0x88; -this.BER_FCP_LIFE_CYCLE_STATUS_TAG = 0x8a; -this.BER_FCP_SA_REFERENCE_FORMAT_TAG = 0x8b; // Security Attribute - Reference Format. -this.BER_FCP_SA_COMPACT_FORMAT_TAG = 0x8c; // Security Attribute - Compact Format. -this.BER_FCP_SAT_EXPANDED_FORMAT_TAG = 0xab; // Security Attribute Template - Expanded Format. -this.BER_FCP_PROPRIETARY_TEMPLATE_TAG = 0xa5; -this.BER_FCP_PIN_STATUS_DATA_OBJECTS_TAG = 0xc6; -this.BER_PROACTIVE_COMMAND_TAG = 0xd0; -this.BER_SMS_PP_DOWNLOAD_TAG = 0xd1; -this.BER_MENU_SELECTION_TAG = 0xd3; -this.BER_EVENT_DOWNLOAD_TAG = 0xd6; -this.BER_TIMER_EXPIRATION_TAG = 0xd7; - -// Flags in Comprehension TLV. -this.COMPREHENSIONTLV_FLAG_CR = 0x80; // Comprehension required. - -// Tags for Comprehension TLV. -this.COMPREHENSIONTLV_TAG_COMMAND_DETAILS = 0x01; -this.COMPREHENSIONTLV_TAG_DEVICE_ID = 0x02; -this.COMPREHENSIONTLV_TAG_RESULT = 0x03; -this.COMPREHENSIONTLV_TAG_DURATION = 0x04; -this.COMPREHENSIONTLV_TAG_ALPHA_ID = 0x05; -this.COMPREHENSIONTLV_TAG_ADDRESS = 0x06; -this.COMPREHENSIONTLV_TAG_SUBADDRESS = 0x08; -this.COMPREHENSIONTLV_TAG_SMS_TPDU = 0x0b; -this.COMPREHENSIONTLV_TAG_TEXT_STRING = 0x0d; -this.COMPREHENSIONTLV_TAG_TONE = 0x0e; -this.COMPREHENSIONTLV_TAG_ITEM = 0x0f; -this.COMPREHENSIONTLV_TAG_ITEM_ID = 0x10; -this.COMPREHENSIONTLV_TAG_RESPONSE_LENGTH = 0x11; -this.COMPREHENSIONTLV_TAG_FILE_LIST = 0x12; -this.COMPREHENSIONTLV_TAG_LOCATION_INFO = 0x13; -this.COMPREHENSIONTLV_TAG_IMEI = 0x14; -this.COMPREHENSIONTLV_TAG_HELP_REQUEST = 0x15; -this.COMPREHENSIONTLV_TAG_NMR = 0x16; -this.COMPREHENSIONTLV_TAG_DEFAULT_TEXT = 0x17; -this.COMPREHENSIONTLV_TAG_NEXT_ACTION_IND = 0x18; -this.COMPREHENSIONTLV_TAG_CAUSE = 0x1a; -this.COMPREHENSIONTLV_TAG_LOCATION_STATUS = 0x1b; -this.COMPREHENSIONTLV_TAG_TRANSACTION_ID = 0x1c; -this.COMPREHENSIONTLV_TAG_EVENT_LIST = 0x19; -this.COMPREHENSIONTLV_TAG_ICON_ID = 0x1e; -this.COMPREHENSIONTLV_TAG_ICON_ID_LIST = 0x1f; -this.COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER = 0x24; -this.COMPREHENSIONTLV_TAG_TIMER_VALUE = 0x25; -this.COMPREHENSIONTLV_TAG_DATE_TIME_ZONE = 0x26; -this.COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE = 0x2b; -this.COMPREHENSIONTLV_TAG_LANGUAGE = 0x2d; -this.COMPREHENSIONTLV_TAG_URL = 0x31; -this.COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE = 0x34; -this.COMPREHENSIONTLV_TAG_ACCESS_TECH = 0x3f; -this.COMPREHENSIONTLV_TAG_SERVICE_RECORD = 0x41; -this.COMPREHENSIONTLV_TAG_IMEISV = 0x62; -this.COMPREHENSIONTLV_TAG_BATTERY_STATE = 0x63; -this.COMPREHENSIONTLV_TAG_NETWORK_SEARCH_MODE = 0x65; -this.COMPREHENSIONTLV_TAG_MEID = 0x6d; -this.COMPREHENSIONTLV_TAG_BROADCAST_NETWORK_INFO = 0x7a; - -// Tags for Service Provider Display Information TLV -this.SPDI_TAG_SPDI = 0xa3; -this.SPDI_TAG_PLMN_LIST = 0x80; - -// MM INFORMATION message content IEIs -// See 3GPP TS 24.008 table 9.2.18 -this.PNN_IEI_FULL_NETWORK_NAME = 0x43; -this.PNN_IEI_SHORT_NETWORK_NAME = 0x45; - -// Device identifiers, see TS 11.14, clause 12.7 -this.STK_DEVICE_ID_KEYPAD = 0x01; -this.STK_DEVICE_ID_DISPLAY = 0x02; -this.STK_DEVICE_ID_EARPIECE = 0x03; -this.STK_DEVICE_ID_SIM = 0x81; -this.STK_DEVICE_ID_ME = 0x82; -this.STK_DEVICE_ID_NETWORK = 0x83; - -// STK Proactive commands. -this.STK_CMD_REFRESH = 0x01; -this.STK_CMD_MORE_TIME = 0x02; -this.STK_CMD_POLL_INTERVAL = 0x03; -this.STK_CMD_POLL_OFF = 0x04; -this.STK_CMD_SET_UP_EVENT_LIST = 0x05; -this.STK_CMD_SET_UP_CALL = 0x10; -this.STK_CMD_SEND_SS = 0x11; -this.STK_CMD_SEND_USSD = 0x12; -this.STK_CMD_SEND_SMS = 0x13; -this.STK_CMD_SEND_DTMF = 0x14; -this.STK_CMD_LAUNCH_BROWSER = 0x15; -this.STK_CMD_PLAY_TONE = 0x20; -this.STK_CMD_DISPLAY_TEXT = 0x21; -this.STK_CMD_GET_INKEY = 0x22; -this.STK_CMD_GET_INPUT = 0x23; -this.STK_CMD_SELECT_ITEM = 0x24; -this.STK_CMD_SET_UP_MENU = 0x25; -this.STK_CMD_PROVIDE_LOCAL_INFO = 0x26; -this.STK_CMD_TIMER_MANAGEMENT = 0x27; -this.STK_CMD_SET_UP_IDLE_MODE_TEXT = 0x28; -this.STK_CMD_OPEN_CHANNEL = 0x40; -this.STK_CMD_CLOSE_CHANNEL = 0x41; -this.STK_CMD_RECEIVE_DATA = 0x42; -this.STK_CMD_SEND_DATA = 0x43; - -// STK Result code. -// TS 11.14, clause 12.12 - -// Results '0X' and '1X' indicate that the command has been performed. - -// Command performed successfully. -this.STK_RESULT_OK = 0x00; - -// Command performed with partial comprehension. -this.STK_RESULT_PRFRMD_WITH_PARTIAL_COMPREHENSION = 0x01; - -// Command performed, with missing information. -this.STK_RESULT_PRFRMD_WITH_MISSING_INFO = 0x02; - -// REFRESH performed with additional EFs read. -this.STK_RESULT_PRFRMD_WITH_ADDITIONAL_EFS_READ = 0x03; - -// Command performed successfully, but requested icon could not be -// displayed. -this.STK_RESULT_PRFRMD_ICON_NOT_DISPLAYED = 0x04; - -// Command performed, but modified by call control by NAA. -this.STK_RESULT_PRFRMD_MODIFIED_BY_NAA = 0x05; - -// Command performed successfully, limited service. -this.STK_RESULT_PRFRMD_LIMITED_SERVICE = 0x06; - -// Command performed with modification. -this.STK_RESULT_PRFRMD_WITH_MODIFICATION = 0x07; - -// REFRESH performed but indicated NAA was not active. -this.STK_RESULT_PRFRMD_NAA_NOT_ACTIVE = 0x08; - -// Command performed successfully; tone not played. -this.STK_RESULT_PRFRMD_TONE_NOT_PLAYED = 0x09; - -// Proactive UICC session terminated by the user. -this.STK_RESULT_UICC_SESSION_TERM_BY_USER = 0x10; - -// Backward move in the proactive UICC session requested by the user. -this.STK_RESULT_BACKWARD_MOVE_BY_USER = 0x11; - -// No response from user. -this.STK_RESULT_NO_RESPONSE_FROM_USER = 0x12; - -// Help information required by the user. -this.STK_RESULT_HELP_INFO_REQUIRED = 0x13; - -// USSD or SS transaction terminated by the user. -this.STK_RESULT_USSD_SS_SESSION_TERM_BY_USER = 0x14; - -// Results '2X' indicate to the UICC that it may be worth re-trying the -// command at a later opportunity. - -// Terminal currently unable to process command. -this.STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS = 0x20; - -// Network currently unable to process command. -this.STK_RESULT_NETWORK_CRNTLY_UNABLE_TO_PROCESS = 0x21; - -// User did not accept the proactive command. -this.STK_RESULT_USER_NOT_ACCEPT = 0x22; - -// User cleared down call before connection or network release. -this.STK_RESULT_USER_CLEAR_DOWN_CALL = 0x23; - -// Action in contradiction with the current timer state. -this.STK_RESULT_CONTRADICTION_WITH_TIMER = 0x24; - -// Interaction with call control by NAA; temporary problem. -this.STK_RESULT_NAA_CALL_CONTROL_TEMPORARY = 0x25; - -// Launch browser generic error code. -this.STK_RESULT_LAUNCH_BROWSER_ERROR = 0x26; - -// MMS temporary problem. -this.STK_RESULT_MMS_TEMPORARY = 0x27; - -// Results '3X' indicate that it is not worth the UICC re-trying with an -// identical command; as it will only get the same response. However, the -// decision to retry lies with the application. - -// Command beyond terminal's capabilities. -this.STK_RESULT_BEYOND_TERMINAL_CAPABILITY = 0x30; - -// Command type not understood by terminal. -this.STK_RESULT_CMD_TYPE_NOT_UNDERSTOOD = 0x31; - -// Command data not understood by terminal. -this.STK_RESULT_CMD_DATA_NOT_UNDERSTOOD = 0x32; - -// Command number not known by terminal. -this.STK_RESULT_CMD_NUM_NOT_KNOWN = 0x33; - -// SS Return Error. -this.STK_RESULT_SS_RETURN_ERROR = 0x34; - -// SMS RP-ERROR. -this.STK_RESULT_SMS_RP_ERROR = 0x35; - -// Error, required values are missing. -this.STK_RESULT_REQUIRED_VALUES_MISSING = 0x36; - -// USSD Return Error. -this.STK_RESULT_USSD_RETURN_ERROR = 0x37; - -// MultipleCard commands error. -this.STK_RESULT_MULTI_CARDS_CMD_ERROR = 0x38; - -// Interaction with call control by USIM or MO short message control by -// USIM; permanent problem. -this.STK_RESULT_USIM_CALL_CONTROL_PERMANENT = 0x39; - -// Bearer Independent Protocol error. -this.STK_RESULT_BIP_ERROR = 0x3a; - -// Access Technology unable to process command. -this.STK_RESULT_ACCESS_TECH_UNABLE_TO_PROCESS = 0x3b; - -// Frames error. -this.STK_RESULT_FRAMES_ERROR = 0x3c; - -// MMS Error. -this.STK_RESULT_MMS_ERROR = 0x3d; - -// STK presentation types, TS 11.14, clause 12.6, Command Qualifier: Select Item -this.STK_PRESENTATION_TYPE_NOT_SPECIFIED = 0x00; // Bit 1 is 0. -this.STK_PRESENTATION_TYPE_DATA_VALUES = 0x01; // Bit 1 is 1, bit 2 is 0. -this.STK_PRESENTATION_TYPE_NAVIGATION_OPTIONS = 0x03; // Bit 1 is 1, bit 2 is 1. - -// STK Coding Scheme. -this.STK_TEXT_CODING_GSM_7BIT_PACKED = 0x00; -this.STK_TEXT_CODING_GSM_8BIT = 0x04; -this.STK_TEXT_CODING_UCS2 = 0x08; - -// STK Event List. -this.STK_EVENT_TYPE_MT_CALL = 0x00; -this.STK_EVENT_TYPE_CALL_CONNECTED = 0x01; -this.STK_EVENT_TYPE_CALL_DISCONNECTED = 0x02; -this.STK_EVENT_TYPE_LOCATION_STATUS = 0x03; -this.STK_EVENT_TYPE_USER_ACTIVITY = 0x04; -this.STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE = 0x05; -this.STK_EVENT_TYPE_CARD_READER_STATUS = 0x06; -this.STK_EVENT_TYPE_LANGUAGE_SELECTION = 0x07; -this.STK_EVENT_TYPE_BROWSER_TERMINATION = 0x08; -this.STK_EVENT_TYPE_DATA_AVAILABLE = 0x09; -this.STK_EVENT_TYPE_CHANNEL_STATUS = 0x0a; -this.STK_EVENT_TYPE_SINGLE_ACCESS_TECHNOLOGY_CHANGED = 0x0b; -this.STK_EVENT_TYPE_DISPLAY_PARAMETER_CHANGED = 0x0c; -this.STK_EVENT_TYPE_LOCAL_CONNECTION = 0x0d; -this.STK_EVENT_TYPE_NETWORK_SEARCH_MODE_CHANGED = 0x0e; -this.STK_EVENT_TYPE_BROWSING_STATUS = 0x0f; - -// STK Service state of Location Status. -this.STK_SERVICE_STATE_NORMAL = 0x00; -this.STK_SERVICE_STATE_LIMITED = 0x01; -this.STK_SERVICE_STATE_UNAVAILABLE = 0x02; - -// Refresh mode. -this.STK_REFRESH_NAA_INIT_AND_FULL_FILE_CHANGE = 0x00; -this.STK_REFRESH_FILE_CHANGE = 0x01; -this.STK_REFRESH_NAA_INIT_AND_FILE_CHANGE = 0x02; -this.STK_REFRESH_NAA_INIT = 0x03; -this.STK_REFRESH_UICC_RESET = 0x04; - -// Tone type. -this.STK_TONE_TYPE_DIAL_TONE = 0x01; -this.STK_TONE_TYPE_CALLED_SUBSCRIBER_BUSY = 0x02; -this.STK_TONE_TYPE_CONGESTION = 0x03; -this.STK_TONE_TYPE_RADIO_PATH_ACK = 0x04; -this.STK_TONE_TYPE_RADIO_PATH_NOT_AVAILABLE = 0x05; -this.STK_TONE_TYPE_ERROR = 0x06; -this.STK_TONE_TYPE_CALL_WAITING_TONE = 0x07; -this.STK_TONE_TYPE_RINGING_TONE = 0x08; -this.STK_TONE_TYPE_GENERAL_BEEP = 0x10; -this.STK_TONE_TYPE_POSITIVE_ACK_TONE = 0x11; -this.STK_TONE_TYPE_NEGATIVE_ACK_TONE = 0x12; - -// Time unit. -this.STK_TIME_UNIT_MINUTE = 0x00; -this.STK_TIME_UNIT_SECOND = 0x01; -this.STK_TIME_UNIT_TENTH_SECOND = 0x02; - -// Local Information type. -this.STK_LOCAL_INFO_NNA = 0x00; -this.STK_LOCAL_INFO_IMEI = 0x01; -this.STK_LOCAL_INFO_NMR_FOR_NNA = 0x02; -this.STK_LOCAL_INFO_DATE_TIME_ZONE = 0x03; -this.STK_LOCAL_INFO_LANGUAGE = 0x04; -this.STK_LOCAL_INFO_ACCESS_TECH = 0x06; -this.STK_LOCAL_INFO_ESN = 0x07; -this.STK_LOCAL_INFO_IMEISV = 0x08; -this.STK_LOCAL_INFO_SEARCH_MODE = 0x09; -this.STK_LOCAL_INFO_CHARGE_STATE = 0x0A; -this.STK_LOCAL_INFO_MEID = 0x0B; -this.STK_LOCAL_INFO_BROADCAST_NETWORK_INFO = 0x0D; -this.STK_LOCAL_INFO_MULTIPLE_ACCESS_TECH = 0x0E; -this.STK_LOCAL_INFO_INFO_FOR_MULTIPLE_ACCESS_TECH = 0x0F; -this.STK_LOCAL_INFO_NMR_FOR_MULTIPLE_ACCESS_TECH = 0x10; - -// Timer Management. -this.STK_TIMER_START = 0x00; -this.STK_TIMER_DEACTIVATE = 0x01; -this.STK_TMIER_GET_CURRENT_VALUE = 0x02; - -// Browser Launch Mode. -this.STK_BROWSER_MODE_LAUNCH_IF_NOT_ALREADY_LAUNCHED = 0x00; -this.STK_BROWSER_MODE_USING_EXISTING_BROWSER = 0x02; -this.STK_BROWSER_MODE_USING_NEW_BROWSER = 0x03; - -// Browser Termination Cause. -this.STK_BROWSER_TERMINATION_CAUSE_USER = 0x00; -this.STK_BROWSER_TERMINATION_CAUSE_ERROR = 0x01; - -// Next Action Indicator. -this.STK_NEXT_ACTION_NULL = 0x00; -this.STK_NEXT_ACTION_END_PROACTIVE_SESSION = 0x81; - -/** - * Supported Terminal Facilities. - * - * value = 1, supported. - * 0, not supported. - */ -this.STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD = 1; -this.STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD = 1; -this.STK_TERMINAL_SUPPORT_CELL_BROADCAST_DATA_DOWNLOAD = 0; -this.STK_TERMINAL_SUPPORT_MENU_SELECTION = 1; -this.STK_TERMINAL_SUPPORT_SIM_DATA_DOWNLOAD_ERROR = 0; -this.STK_TERMINAL_SUPPORT_TIMER_EXPIRATION = 1; -this.STK_TERMINAL_SUPPORT_USSD_IN_CALL_CONTROL = 0; -this.STK_TERMINAL_SUPPORT_CALL_CONTROL_IN_REDIAL = 0; - -this.STK_TERMINAL_SUPPORT_COMMAND_RESULT = 1; -this.STK_TERMINAL_SUPPORT_CALL_CONTROL = 1; -this.STK_TERMINAL_SUPPORT_CALL_ID_INCLUDED = 0; -this.STK_TERMINAL_SUPPORT_MO_SMS_CONTROL = 0; -this.STK_TERMINAL_SUPPORT_ALPHA_ID_INDICATION = 0; -this.STK_TERMINAL_SUPPORT_UCS2_ENTRY = 1; -this.STK_TERMINAL_SUPPORT_UCS2_DISPLAY = 1; -this.STK_TERMINAL_SUPPORT_EXTENSION_TEXT = 1; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_DISPLAY_TEXT = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_GET_INKEY = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_GET_INPUT = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_MORE_TIME = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_PLAY_TONE = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_POLL_INTERVAL = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_POLL_OFF = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_REFRESH = 1; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_SELECT_ITEM = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SMS = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SS = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SEND_USSD = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_CALL = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_MENU = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR = 0; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_EVENT_LIST = 1; -this.STK_TERMINAL_SUPPORT_EVENT_MT_CALL = 1; -this.STK_TERMINAL_SUPPORT_EVENT_CALL_CONNECTED = 1; -this.STK_TERMINAL_SUPPORT_EVENT_CALL_DISCONNECTED = 1; -this.STK_TERMINAL_SUPPORT_EVENT_LOCATION_STATUS = 1; -this.STK_TERMINAL_SUPPORT_EVENT_USER_ACTIVITY = 1; -this.STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE = 1; -this.STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS = 0; - -this.STK_TERMINAL_SUPPORT_EVENT_LANGUAGE_SELECTION = 1; -this.STK_TERMINAL_SUPPORT_EVENT_BROWSER_TERMINATION = 1; -this.STK_TERMINAL_SUPPORT_EVENT_DATA_AVAILABLE = 0; -this.STK_TERMINAL_SUPPORT_EVENT_CHANNEL_STATUS = 0; - -this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE = 1; -this.STK_TERMINAL_SUPPORT_GET_INKEY = 1; -this.STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT = 1; -this.STK_TERMINAL_SUPPORT_RUN_AT_COMMAND = 0; -this.STK_TERMINAL_SUPPORT_SET_UP_CALL = 1; -this.STK_TERMINAL_SUPPORT_CALL_CONTROL_BY_NNA = 0; - -this.STK_TERMINAL_SUPPORT_DISPLAY_TEXT = 1; -this.STK_TERMINAL_SUPPORT_SEND_DTMF_COMMAND = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR = 0; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_LANGUAGE = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_TIME_ADVANCE = 0; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LANGUAGE_NOTIFICATION = 0; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LAUNCH_BROWSER = 1; -this.STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_ACCESS_TECH = 0; - -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_OPEN_CHANNEL = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_CLOSE_CHANNEL = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_RECEIVE_DATA = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_SEND_DATA = 1; -this.STK_TERMINAL_SUPPORT_BIP_COMMAND_GET_CHANNEL_STATUS = 0; - -/** - * SAT profile - * - * @see ETSI TS 101.267, section 5.2. - */ -this.STK_TERMINAL_PROFILE_DOWNLOAD = - (STK_TERMINAL_SUPPORT_PROFILE_DOWNLOAD << 0) | - (STK_TERMINAL_SUPPORT_SMS_PP_DOWNLOAD << 1) | - (STK_TERMINAL_SUPPORT_CELL_BROADCAST_DATA_DOWNLOAD << 2) | - (STK_TERMINAL_SUPPORT_MENU_SELECTION << 3) | - (STK_TERMINAL_SUPPORT_SIM_DATA_DOWNLOAD_ERROR << 4) | - (STK_TERMINAL_SUPPORT_TIMER_EXPIRATION << 5) | - (STK_TERMINAL_SUPPORT_USSD_IN_CALL_CONTROL << 6) | - (STK_TERMINAL_SUPPORT_CALL_CONTROL_IN_REDIAL << 7); - -this.STK_TERMINAL_PROFILE_OTHER = - (STK_TERMINAL_SUPPORT_COMMAND_RESULT << 0) | - (STK_TERMINAL_SUPPORT_CALL_CONTROL << 1) | - (STK_TERMINAL_SUPPORT_CALL_ID_INCLUDED << 2) | - (STK_TERMINAL_SUPPORT_MO_SMS_CONTROL << 3) | - (STK_TERMINAL_SUPPORT_ALPHA_ID_INDICATION << 4) | - (STK_TERMINAL_SUPPORT_UCS2_ENTRY << 5) | - (STK_TERMINAL_SUPPORT_UCS2_DISPLAY << 6) | - (STK_TERMINAL_SUPPORT_EXTENSION_TEXT << 7); - -this.STK_TERMINAL_PROFILE_PROACTIVE_1 = - (STK_TERMINAL_SUPPORT_PROACTIVE_DISPLAY_TEXT << 0) | - (STK_TERMINAL_SUPPORT_PROACTIVE_GET_INKEY << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_GET_INPUT << 2) | - (STK_TERMINAL_SUPPORT_PROACTIVE_MORE_TIME << 3) | - (STK_TERMINAL_SUPPORT_PROACTIVE_PLAY_TONE << 4) | - (STK_TERMINAL_SUPPORT_PROACTIVE_POLL_INTERVAL << 5) | - (STK_TERMINAL_SUPPORT_PROACTIVE_POLL_OFF << 6) | - (STK_TERMINAL_SUPPORT_PROACTIVE_REFRESH << 7); - -this.STK_TERMINAL_PROFILE_PROACTIVE_2 = - (STK_TERMINAL_SUPPORT_PROACTIVE_SELECT_ITEM << 0) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SMS << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SEND_SS << 2) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SEND_USSD << 3) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_CALL << 4) | - (STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_MENU << 5) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO << 6) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR << 7); - -this.STK_TERMINAL_PROFILE_EVENT = - (STK_TERMINAL_SUPPORT_PROACTIVE_SET_UP_EVENT_LIST << 0) | - (STK_TERMINAL_SUPPORT_EVENT_MT_CALL << 1) | - (STK_TERMINAL_SUPPORT_EVENT_CALL_CONNECTED << 2) | - (STK_TERMINAL_SUPPORT_EVENT_CALL_DISCONNECTED << 3) | - (STK_TERMINAL_SUPPORT_EVENT_LOCATION_STATUS << 4) | - (STK_TERMINAL_SUPPORT_EVENT_USER_ACTIVITY << 5) | - (STK_TERMINAL_SUPPORT_EVENT_IDLE_SCREEN_AVAILABLE << 6) | - (STK_TERMINAL_SUPPORT_EVENT_CARD_READER_STATUS << 7); - -this.STK_TERMINAL_PROFILE_EVENT_EXT = - (STK_TERMINAL_SUPPORT_EVENT_LANGUAGE_SELECTION << 0) | - (STK_TERMINAL_SUPPORT_EVENT_BROWSER_TERMINATION << 1) | - (STK_TERMINAL_SUPPORT_EVENT_DATA_AVAILABLE << 2) | - (STK_TERMINAL_SUPPORT_EVENT_CHANNEL_STATUS << 3); - -this.STK_TERMINAL_PROFILE_PROACTIVE_3 = - (STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_START_STOP << 0) | - (STK_TERMINAL_SUPPORT_PROACTIVE_TIMER_GET_CURRENT << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_DATE << 2) | - (STK_TERMINAL_SUPPORT_GET_INKEY << 3) | - (STK_TERMINAL_SUPPORT_SET_UP_IDLE_MODE_TEXT << 4) | - (STK_TERMINAL_SUPPORT_RUN_AT_COMMAND << 5) | - (STK_TERMINAL_SUPPORT_SET_UP_CALL << 6) | - (STK_TERMINAL_SUPPORT_CALL_CONTROL_BY_NNA << 7); - -this.STK_TERMINAL_PROFILE_PROACTIVE_4 = - (STK_TERMINAL_SUPPORT_DISPLAY_TEXT << 0) | - (STK_TERMINAL_SUPPORT_SEND_DTMF_COMMAND << 1) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_NMR << 2) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_LANGUAGE << 3) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_TIME_ADVANCE << 4) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LANGUAGE_NOTIFICATION << 5) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LAUNCH_BROWSER << 6) | - (STK_TERMINAL_SUPPORT_PROACTIVE_LOCAL_INFO_ACCESS_TECH << 7); - -this.STK_TERMINAL_PROFILE_BIP_COMMAND = - (STK_TERMINAL_SUPPORT_BIP_COMMAND_OPEN_CHANNEL << 0) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_CLOSE_CHANNEL << 1) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_RECEIVE_DATA << 2) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_SEND_DATA << 3) | - (STK_TERMINAL_SUPPORT_BIP_COMMAND_GET_CHANNEL_STATUS << 4); - -this.STK_SUPPORTED_TERMINAL_PROFILE = [ - STK_TERMINAL_PROFILE_DOWNLOAD, - STK_TERMINAL_PROFILE_OTHER, - STK_TERMINAL_PROFILE_PROACTIVE_1, - STK_TERMINAL_PROFILE_PROACTIVE_2, - STK_TERMINAL_PROFILE_EVENT, - STK_TERMINAL_PROFILE_EVENT_EXT, // Event extension - 0x00, // Multiple card proactive commands - STK_TERMINAL_PROFILE_PROACTIVE_3, - STK_TERMINAL_PROFILE_PROACTIVE_4, - 0x00, // Softkey support - 0x00, // Softkey information - STK_TERMINAL_PROFILE_BIP_COMMAND, - 0x00, // BIP supported bearers - 0x00, // Screen height - 0x00, // Screen width - 0x00, // 16, Screen effects - 0x00, // 17, BIP supported transport interface - 0x00, // 18, RFU - 0x00, // 19, RFU - 0x00, // 20, RFU -]; - -/** - * ICC Services Table. - * - * @see 3GPP TS 51.011 10.3.7 (SIM) and 3GPP TS 31.102 4.2.8 (USIM). - */ -this.GECKO_ICC_SERVICES = { - // @see 3GPP TS 51.011 10.3.7 (SIM). - sim: { - ADN: 2, - FDN: 3, - PLMNSEL: 7, - MSISDN: 9, - EXT1: 10, - EXT2: 11, - CBMI: 14, - GID1: 15, - SPN: 17, - SDN: 18, - EXT3: 19, - DATA_DOWNLOAD_SMS_CB: 25, - DATA_DOWNLOAD_SMS_PP: 26, - CBMIR: 30, - BDN: 31, - IMG: 39, - PNN: 51, - OPL: 52, - MDN: 53, - MWIS: 54, - SPDI: 56 - }, - // @see 3GPP TS 31.102 4.2.8 (USIM). - usim: { - FDN: 2, - EXT2: 3, - SDN: 4, - EXT3: 5, - BDN: 6, - CBMI: 15, - CBMIR: 16, - GID1: 17, - SPN: 19, - MSISDN: 21, - IMG: 22, - DATA_DOWNLOAD_SMS_PP: 28, - DATA_DOWNLOAD_SMS_CB: 29, - PNN: 45, - OPL: 46, - MDN: 47, - MWIS: 48, - SPDI: 51 - }, - // @see 3GPP2 C.S0023-D 3.4.18 (RUIM). - ruim: { - FDN: 3, - ENHANCED_PHONEBOOK: 6, - EXT1: 10, - EXT2: 11, - SPN: 17, - SDN: 18, - EXT3: 19, - }, - // @see B.3.1.1 CPHS Information in CPHS Phase 2: - // Indicates which of the CPHS 'optional' data-fields are present in the SIM card: - // EF_CPHS_CSP, EF_CPHS_SST, EF_CPHS_MBN, EF_CPHS_ONSF, EF_CPHS_INFO_NUM - // Note: Mandatory EFs are: (B.3.1 Enhanced SIM Requirements) - // EF_CPHS_CFF, EF_CPHS_VMI, EF_CPHS_ONS, EF_CPHS_INFO - cphs: { - CSP: 1, - SST: 2, - MBN: 3, - ONSF: 4, - INFO_NUM: 5 - } -}; - -/** - * Cell Broadcast constants - */ - -this.CB_FORMAT_GSM = 0; -this.CB_FORMAT_ETWS = 1; -this.CB_FORMAT_CMAS = 2; -this.CB_FORMAT_UMTS = 3; - -// CBS Data Coding Scheme: Language groups -// see 3GPP TS 23.038 section 5 -this.CB_DCS_LANG_GROUP_1 = [ - "de", "en", "it", "fr", "es", "nl", "sv", "da", "pt", "fi", - "no", "el", "tr", "hu", "pl", null -]; -this.CB_DCS_LANG_GROUP_2 = [ - "cs", "he", "ar", "ru", "is", null, null, null, null, null, - null, null, null, null, null, null -]; - -// See 3GPP TS 23.041 v11.2.0 section 9.4.1.2.2 -this.CB_NON_MMI_SETTABLE_RANGES = [ - /*0x1000 - 0x107F*/4096, 4224, /*0x1080 - 0x10FF*/4224, 4352, - /*0x1112 - 0x1112*/4370, 4371, /*0x111F - 0x111F*/4383, 4384, - /*0xF000 - 0xFFFE*/61440, 65535, /*0xFFFF - 0xFFFF*/65535, 65536 -]; - -// User Data max length in septets -this.CB_MAX_CONTENT_7BIT = 93; -// User Data max length in octets -this.CB_MAX_CONTENT_8BIT = 82; -// User Data max length in chars -this.CB_MAX_CONTENT_UCS2 = 41; - -// See 3GPP TS 23.041 v11.6.0 senction 9.3.19 -this.CB_MSG_PAGE_INFO_SIZE = 82; - -this.CB_MESSAGE_SIZE_ETWS = 56; -this.CB_MESSAGE_SIZE_GSM = 88; -this.CB_MESSAGE_SIZE_UMTS_MIN = 90; -this.CB_MESSAGE_SIZE_UMTS_MAX = 1252; - - - -// GSM Cell Broadcast Geographical Scope -// See 3GPP TS 23.041 clause 9.4.1.2.1 -this.CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE = 0; -this.CB_GSM_GEOGRAPHICAL_SCOPE_PLMN_WIDE = 1; -this.CB_GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE = 2; -this.CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE = 3; - -// GSM Cell Broadcast Geographical Scope -// See 3GPP TS 23.041 clause 9.4.1.2.1 -this.CB_GSM_GEOGRAPHICAL_SCOPE_NAMES = [ - "cell-immediate", - "plmn", - "location-area", - "cell" -]; - -// GSM Cell Broadcast Message Identifiers -// see 3GPP TS 23.041 clause 9.4.1.2.2 -this.CB_GSM_MESSAGEID_ETWS_BEGIN = 0x1100; -this.CB_GSM_MESSAGEID_ETWS_END = 0x1107; - -// ETWS Warning-Type -// see 3GPP TS 23.041 clause 9.3.24 -this.CB_ETWS_WARNING_TYPE_NAMES = [ - "earthquake", - "tsunami", - "earthquake-tsunami", - "test", - "other" -]; - -// UMTS Message Type -// see 3GPP TS 25.324 section 11.1 -this.CB_UMTS_MESSAGE_TYPE_CBS = 1; -this.CB_UMTS_MESSAGE_TYPE_SCHEDULE = 2; -this.CB_UMTS_MESSAGE_TYPE_CBS41 = 3; - -/** - * Number plan identification defined in - * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008. - */ -this.CALLED_PARTY_BCD_NPI_UNKNOWN = 0; -this.CALLED_PARTY_BCD_NPI_ISDN = 1; -this.CALLED_PARTY_BCD_NPI_DATA = 3; -this.CALLED_PARTY_BCD_NPI_TELEX = 4; -this.CALLED_PARTY_BCD_NPI_NATIONAL = 8; -this.CALLED_PARTY_BCD_NPI_PRIVATE = 9; - -/** - * Array of number plan identification values which can be used to map an - * enumeration to the corresponding value. The indices should be consistent - * with nsISmsService::NUMBER_PLAN_IDENTIFICATION_* constants. - */ -this.CALLED_PARTY_BCD_NPI = [ - CALLED_PARTY_BCD_NPI_UNKNOWN, - CALLED_PARTY_BCD_NPI_ISDN, - CALLED_PARTY_BCD_NPI_DATA, - CALLED_PARTY_BCD_NPI_TELEX, - CALLED_PARTY_BCD_NPI_NATIONAL, - CALLED_PARTY_BCD_NPI_PRIVATE -]; - -/** - * GSM PDU constants - */ - -// PDU TYPE-OF-ADDRESS -this.PDU_TOA_UNKNOWN = 0x80; // Unknown. This is used when the user or - // network has no a priori information - // about the numbering plan. -this.PDU_TOA_ISDN = 0x81; // ISDN/Telephone numbering -this.PDU_TOA_DATA_NUM = 0x83; // Data numbering plan -this.PDU_TOA_TELEX_NUM = 0x84; // Telex numbering plan -this.PDU_TOA_NATIONAL_NUM = 0x88; // National numbering plan -this.PDU_TOA_PRIVATE_NUM = 0x89; // Private numbering plan -this.PDU_TOA_ERMES_NUM = 0x8A; // Ermes numbering plan -this.PDU_TOA_INTERNATIONAL = 0x90; // International number -this.PDU_TOA_NATIONAL = 0xA0; // National number. Prefix or escape digits - // shall not be included -this.PDU_TOA_NETWORK_SPEC = 0xB0; // Network specific number This is used to - // indicate administration/service number - // specific to the serving network -this.PDU_TOA_SUBSCRIBER = 0xC0; // Subscriber number. This is used when a - // specific short number representation is - // stored in one or more SCs as part of a - // higher layer application -this.PDU_TOA_ALPHANUMERIC = 0xD0; // Alphanumeric, (coded according to GSM TS - // 03.38 7-bit default alphabet) -this.PDU_TOA_ABBREVIATED = 0xE0; // Abbreviated number - -/** - * First octet of the SMS-DELIVER PDU - * - * RP: 0 Reply Path parameter is not set in this PDU - * 1 Reply Path parameter is set in this PDU - * - * UDHI: 0 The UD field contains only the short message - * 1 The beginning of the UD field contains a header in addition of - * the short message - * - * SRI: (is only set by the SMSC) - * 0 A status report will not be returned to the SME - * 1 A status report will be returned to the SME - * - * MMS: (is only set by the SMSC) - * 0 More messages are waiting for the MS in the SMSC - * 1 No more messages are waiting for the MS in the SMSC - * - * MTI: bit1 bit0 Message type - * 0 0 SMS-DELIVER (SMSC ==> MS) - * 0 0 SMS-DELIVER REPORT (MS ==> SMSC, is generated - * automatically by the M20, after receiving a - * SMS-DELIVER) - * 0 1 SMS-SUBMIT (MS ==> SMSC) - * 0 1 SMS-SUBMIT REPORT (SMSC ==> MS) - * 1 0 SMS-STATUS REPORT (SMSC ==> MS) - * 1 0 SMS-COMMAND (MS ==> SMSC) - * 1 1 Reserved - */ -this.PDU_RP = 0x80; // Reply path. Parameter indicating that - // reply path exists. -this.PDU_UDHI = 0x40; // User data header indicator. This bit is - // set to 1 if the User Data field starts - // with a header -this.PDU_SRI_SRR = 0x20; // Status report indication (SMS-DELIVER) - // or request (SMS-SUBMIT) -this.PDU_VPF_ABSOLUTE = 0x18;// Validity period aboslute format - // (SMS-SUBMIT only) -this.PDU_VPF_RELATIVE = 0x10;// Validity period relative format - // (SMS-SUBMIT only) -this.PDU_VPF_ENHANCED = 0x8; // Validity period enhance format - // (SMS-SUBMIT only) -this.PDU_MMS_RD = 0x04;// More messages to send. (SMS-DELIVER only) or - // Reject duplicates (SMS-SUBMIT only) - -// MTI - Message Type Indicator -this.PDU_MTI_SMS_RESERVED = 0x03; -this.PDU_MTI_SMS_STATUS_REPORT = 0x02; -this.PDU_MTI_SMS_COMMAND = 0x02; -this.PDU_MTI_SMS_SUBMIT = 0x01; -this.PDU_MTI_SMS_DELIVER = 0x00; - -// PI - Parameter Indicator -this.PDU_PI_EXTENSION = 0x80; -this.PDU_PI_USER_DATA_LENGTH = 0x04; -this.PDU_PI_DATA_CODING_SCHEME = 0x02; -this.PDU_PI_PROTOCOL_IDENTIFIER = 0x01; -this.PDU_PI_RESERVED = 0x78; - -// FCS - Failure Cause -// 0...127 see 3GPP TS 24.011 clause E.2 -// 128...255 see 3GPP TS 23.040 clause 9.2.3.22 -// others see 3GPP TS 27.005 clause 3.2.5 -this.PDU_FCS_OK = 0x00; -this.PDU_FCS_PROTOCOL_ERROR = 0x6F; -this.PDU_FCS_MEMORY_CAPACITY_EXCEEDED = 0XD3; -this.PDU_FCS_USAT_BUSY = 0XD4; -this.PDU_FCS_USIM_DATA_DOWNLOAD_ERROR = 0xD5; -this.PDU_FCS_RESERVED = 0xE0; -this.PDU_FCS_UNSPECIFIED = 0xFF; -// Special internal value that means we should not acknowledge an -// incoming text right away, but need to wait for other components -// (e.g. storage) to complete. This can be any value, so long it -// doesn't conflict with the PDU_FCS_* constants above. -this.MOZ_FCS_WAIT_FOR_EXPLICIT_ACK = 0x0F; - -// ST - Status -// Bit 7..0 = 000xxxxx, short message transaction completed -this.PDU_ST_0_RECEIVED = 0x00; -this.PDU_ST_0_FORWARDED_NO_CONFIRM = 0x01; -this.PDU_ST_0_REPLACED_BY_SC = 0x02; -this.PDU_ST_0_RESERVED_BEGIN = 0x03; -this.PDU_ST_0_SC_SPECIFIC_BEGIN = 0x10; -this.PDU_ST_0_SC_SPECIFIC_END = 0x1F; -// Bit 7..0 = 001xxxxx, temporary error, SC still trying to transfer SM -this.PDU_ST_1_CONGESTION = 0x20; -this.PDU_ST_1_SME_BUSY = 0x21; -this.PDU_ST_1_SME_NO_RESPONSE = 0x22; -this.PDU_ST_1_SERVICE_REJECTED = 0x23; -this.PDU_ST_1_QOS_UNAVAILABLE = 0x24; -this.PDU_ST_1_SME_ERROR = 0x25; -this.PDU_ST_1_RESERVED_BEGIN = 0x26; -this.PDU_ST_1_SC_SPECIFIC_BEGIN = 0x30; -this.PDU_ST_1_SC_SPECIFIC_END = 0x3F; -// Bit 7..0 = 010xxxxx, permanent error, SC is not making any more transfer -// attempts -this.PDU_ST_2_RPC_ERROR = 0x40; -this.PDU_ST_2_DEST_INCOMPATIBLE = 0x41; -this.PDU_ST_2_CONNECTION_REJECTED = 0x42; -this.PDU_ST_2_NOT_OBTAINABLE = 0x43; -this.PDU_ST_2_QOS_UNAVAILABLE = 0x44; -this.PDU_ST_2_INTERWORKING_UNAVALIABLE = 0x45; -this.PDU_ST_2_VALIDITY_EXPIRED = 0x46; -this.PDU_ST_2_DELETED_BY_SME = 0x47; -this.PDU_ST_2_DELETED_BY_SC = 0x48; -this.PDU_ST_2_SM_MISSING = 0x49; -this.PDU_ST_2_RESERVED_BEGIN = 0x4A; -this.PDU_ST_2_SC_SPECIFIC_BEGIN = 0x50; -this.PDU_ST_2_SC_SPECIFIC_END = 0x5F; -// Bit 7..0 = 011xxxxx, temporary error, SC is not making any more transfer -// attempts -this.PDU_ST_3_CONGESTION = 0x60; -this.PDU_ST_3_SME_BUSY = 0x61; -this.PDU_ST_3_SME_NO_RESPONSE = 0x62; -this.PDU_ST_3_SERVICE_REJECTED = 0x63; -this.PDU_ST_3_QOS_UNAVAILABLE = 0x64; -this.PDU_ST_3_SME_ERROR = 0x65; -this.PDU_ST_3_RESERVED_BEGIN = 0x66; -this.PDU_ST_3_SC_SPECIFIC_BEGIN = 0x70; -this.PDU_ST_3_SC_SPECIFIC_END = 0x7F; - -this.GECKO_SMS_DELIVERY_STATUS_NOT_APPLICABLE = "not-applicable"; -this.GECKO_SMS_DELIVERY_STATUS_SUCCESS = "success"; -this.GECKO_SMS_DELIVERY_STATUS_PENDING = "pending"; -this.GECKO_SMS_DELIVERY_STATUS_ERROR = "error"; - -// User Data max length in septets -this.PDU_MAX_USER_DATA_7BIT = 160; -// User Data max length in octets -this.PDU_MAX_USER_DATA_8BIT = 140; -// User Data max length in chars -this.PDU_MAX_USER_DATA_UCS2 = 70; - -// PID - Protocol Indicator -this.PDU_PID_DEFAULT = 0x00; -this.PDU_PID_TELEMATIC_INTERWORKING = 0x20; -this.PDU_PID_SHORT_MESSAGE_TYPE_0 = 0x40; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_1 = 0x41; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_2 = 0x42; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_3 = 0x43; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_4 = 0x44; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_5 = 0x45; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_6 = 0x46; -this.PDU_PID_REPLACE_SHORT_MESSAGE_TYPE_7 = 0x47; -this.PDU_PID_ENHANDED_MESSAGE_SERVICE = 0x5E; -this.PDU_PID_RETURN_CALL_MESSAGE = 0x5F; -this.PDU_PID_ANSI_136_R_DATA = 0x7C; -this.PDU_PID_ME_DATA_DOWNLOAD = 0x7D; -this.PDU_PID_ME_DEPERSONALIZATION = 0x7E; -this.PDU_PID_USIM_DATA_DOWNLOAD = 0x7F; - -// DCS - Data Coding Scheme -this.PDU_DCS_MSG_CODING_7BITS_ALPHABET = 0x00; -this.PDU_DCS_MSG_CODING_8BITS_ALPHABET = 0x04; -this.PDU_DCS_MSG_CODING_16BITS_ALPHABET = 0x08; -this.PDU_DCS_MSG_CLASS_0 = 0x00; -this.PDU_DCS_MSG_CLASS_1 = 0x01; -this.PDU_DCS_MSG_CLASS_2 = 0x02; -this.PDU_DCS_MSG_CLASS_3 = 0x03; -this.PDU_DCS_MSG_CLASS_USER_1 = 0x04; -this.PDU_DCS_MSG_CLASS_USER_2 = 0x05; -this.PDU_DCS_MSG_CLASS_NORMAL = 0x06; -this.PDU_DCS_CODING_GROUP_BITS = 0xF0; -this.PDU_DCS_MSG_CLASS_BITS = 0x03; -this.PDU_DCS_MWI_ACTIVE_BITS = 0x08; -this.PDU_DCS_MWI_ACTIVE_VALUE = 0x08; -this.PDU_DCS_MWI_TYPE_BITS = 0x03; -this.PDU_DCS_MWI_TYPE_VOICEMAIL = 0x00; -this.PDU_DCS_MWI_TYPE_FAX = 0x01; -this.PDU_DCS_MWI_TYPE_EMAIL = 0x02; -this.PDU_DCS_MWI_TYPE_OTHER = 0x03; - -// Set as Array instead of Object for reversed-mapping with Array.indexOf(). -this.GECKO_SMS_MESSAGE_CLASSES = []; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0] = "class-0"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1] = "class-1"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2] = "class-2"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3] = "class-3"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_1] = "user-1"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_USER_2] = "user-2"; -GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL] = "normal"; - -// Because service center timestamp omit the century. Yay. -this.PDU_TIMESTAMP_YEAR_OFFSET = 2000; - -// See 9.2.3.24 TP‑User Data (TP‑UD) -this.PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT = 0x00; -this.PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION = 0x01; -this.PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT = 0x04; -this.PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT = 0x05; -this.PDU_IEI_SMSC_CONTROL_PARAMS = 0x06; -this.PDU_IEI_UDH_SOURCE_INDICATOR = 0x07; -this.PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT = 0x08; -this.PDU_IEI_WIRELESS_CONTROL_MESSAGE_PROTOCOL = 0x09; -this.PDU_IEI_TEXT_FORMATING = 0x0A; -this.PDU_IEI_PREDEFINED_SOUND = 0x0B; -this.PDU_IEI_USER_DATA_SOUND = 0x0C; -this.PDU_IEI_PREDEFINED_ANIMATION = 0x0D; -this.PDU_IEI_LARGE_ANIMATION = 0x0E; -this.PDU_IEI_SMALL_ANIMATION = 0x0F; -this.PDU_IEI_LARGE_PICTURE = 0x10; -this.PDU_IEI_SMALL_PICTURE = 0x11; -this.PDU_IEI_VARIABLE_PICTURE = 0x12; -this.PDU_IEI_USER_PROMPT_INDICATOR = 0x13; -this.PDU_IEI_EXTENDED_OBJECT = 0x14; -this.PDU_IEI_REUSED_EXTENDED_OBJECT = 0x15; -this.PDU_IEI_COMPRESS_CONTROL = 0x16; -this.PDU_IEI_OBJECT_DISTRIBUTION_INDICATOR = 0x17; -this.PDU_IEI_STANDARD_WVG_OBJECT = 0x18; -this.PDU_IEI_CHARACTER_SIZE_WVG_OBJECT = 0x19; -this.PDU_IEI_EXTENDED_OBJECT_DATA_REQUEST_COMMAND = 0x1A; -this.PDU_IEI_RFC822_EMAIL_HEADER = 0x20; -this.PDU_IEI_HYPERLINK_FORMAT_ELEMENT = 0x21; -this.PDU_IEI_REPLY_ADDRESS_ELEMENT = 0x22; -this.PDU_IEI_ENHANCED_VOICE_MAIL_INFORMATION = 0x23; -this.PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT = 0x24; -this.PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT = 0x25; - -// Application Port Addressing, see 3GPP TS 23.040 9.2.3.24.3 -this.PDU_APA_RESERVED_8BIT_PORTS = 240; -this.PDU_APA_VALID_16BIT_PORTS = 49152; - -// 7bit alphabet escape character. The encoded value of this code point is left -// undefined in official spec. Its code value is internally assigned to \uffff, -// in Unicode basic multilingual plane. -this.PDU_NL_EXTENDED_ESCAPE = 0x1B; - -// , , are only defined in locking shift tables. -this.PDU_NL_SPACE = 0x20; -this.PDU_NL_LINE_FEED = 0x0A; -this.PDU_NL_CARRIAGE_RETURN = 0x0D; - -// 7bit alphabet page break character, only defined in single shift tables. -// The encoded value of this code point is left undefined in official spec, but -// the code point itself maybe be used for example in compressed CBS messages. -// Its code value is internally assigned to \u000c, ASCII form feed, or new page. -this.PDU_NL_PAGE_BREAK = 0x0A; -// 7bit alphabet reserved control character, only defined in single shift -// tables. The encoded value of this code point is left undefined in official -// spec. Its code value is internally assigned to \ufffe, -// in Unicode basic multilingual plane. -this.PDU_NL_RESERVED_CONTROL = 0x0D; - -this.PDU_NL_IDENTIFIER_DEFAULT = 0; -this.PDU_NL_IDENTIFIER_TURKISH = 1; -this.PDU_NL_IDENTIFIER_SPANISH = 2; -this.PDU_NL_IDENTIFIER_PORTUGUESE = 3; -this.PDU_NL_IDENTIFIER_BENGALI = 4; -this.PDU_NL_IDENTIFIER_GUJARATI = 5; -this.PDU_NL_IDENTIFIER_HINDI = 6; -this.PDU_NL_IDENTIFIER_KANNADA = 7; -this.PDU_NL_IDENTIFIER_MALAYALAM = 8; -this.PDU_NL_IDENTIFIER_ORIYA = 9; -this.PDU_NL_IDENTIFIER_PUNJABI = 10; -this.PDU_NL_IDENTIFIER_TAMIL = 11; -this.PDU_NL_IDENTIFIER_TELUGU = 12; -this.PDU_NL_IDENTIFIER_URDU = 13; - -// The mapping of mcc and their extra GSM national language locking / single -// shift table tuples to enable. The default GSM alphabet and extension table -// are always enabled and need not to be list here. -// -// The content should be updated when a relevant national regulatory body -// requests. See 'NOTE 2' of 6.2.1.2.5 in 3GPP TS 23.038: -// " -// Encoding of a message using the national locking shift mechanism is not -// intended to be implemented until a formal request is issued by the -// relevant national regulatory body. This is because a receiving entity -// not supporting the relevant locking-shift decoding will present different -// characters from the ones intended by the sending entity. -// " -this.PDU_MCC_NL_TABLE_TUPLES_MAPPING = { - // Configuration for Turkey. - // - // The Turkish single shift table contains 7 extra characters - // (Ğ, İ, Ş, ç, ğ, ı, ş) than the GSM default alphabet extension table. Since - // all the 7 characters are also included in Turkish locking shift table, it's - // not necessary to enable Turkish single shift table. Using GSM default - // alphabet extension table instead saves 3 octets when these extension table - // characters present in a message. - 286: [[PDU_NL_IDENTIFIER_TURKISH, PDU_NL_IDENTIFIER_DEFAULT]] -}; - -/* - * 3GPP TS 23.038 - 6.2.1 GSM 7 bit Default Alphabet - */ -this.PDU_NL_GSM_DEFAULT_ALPHABET = - // 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "@\u00a3$\u00a5\u00e8\u00e9\u00f9\u00ec\u00f2\u00c7\n\u00d8\u00f8\r\u00c5\u00e5" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0394_\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e\uffff\u00c6\u00e6\u00df\u00c9" - // 012.34.....56789ABCDEF - + " !\"#\u00a4%&'()*+,-./" - // 0123456789ABCDEF - + "0123456789:;<=>?" - // 0.....123456789ABCDEF - + "\u00a1ABCDEFGHIJKLMNO" - // 0123456789AB.....C.....D.....E.....F..... - + "PQRSTUVWXYZ\u00c4\u00d6\u00d1\u00dc\u00a7" - // 0.....123456789ABCDEF - + "\u00bfabcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0"; - -// National Language Locking Shift Tables, see 3GPP TS 23.038 -this.PDU_NL_LOCKING_SHIFT_TABLES = [ - /** - * National Language Identifier: 0x00 - * 6.2.1 GSM 7 bit Default Alphabet - */ - PDU_NL_GSM_DEFAULT_ALPHABET, - - /** - * National Language Identifier: 0x01 - * A.3.1 Turkish National Language Locking Shift Table - */ - // 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "@\u00a3$\u00a5\u20ac\u00e9\u00f9\u0131\u00f2\u00c7\n\u011e\u011f\r\u00c5\u00e5" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0394_\u03a6\u0393\u039b\u03a9\u03a0\u03a8\u03a3\u0398\u039e\uffff\u015e\u015f\u00df\u00c9" - // 012.34.....56789ABCDEF - + " !\"#\u00a4%&'()*+,-./" - // 0123456789ABCDEF - + "0123456789:;<=>?" - // 0.....123456789ABCDEF - + "\u0130ABCDEFGHIJKLMNO" - // 0123456789AB.....C.....D.....E.....F..... - + "PQRSTUVWXYZ\u00c4\u00d6\u00d1\u00dc\u00a7" - // 0.....123456789ABCDEF - + "\u00e7abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u00e4\u00f6\u00f1\u00fc\u00e0", - - /** - * National Language Identifier: 0x02 - * A.3.2 Void - * Fallback to GSM Default Alphabet - */ - PDU_NL_GSM_DEFAULT_ALPHABET, - - /** - * National Language Identifier: 0x03 - * A.3.3 Portuguese National Language Locking Shift Table - */ - // 01.....23.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "@\u00a3$\u00a5\u00ea\u00e9\u00fa\u00ed\u00f3\u00e7\n\u00d4\u00f4\r\u00c1\u00e1" - // 0.....12.....3.....4.....5.....67.8.....9.....AB.....C.....D.....E.....F..... - + "\u0394_\u00aa\u00c7\u00c0\u221e^\\\u20ac\u00d3|\uffff\u00c2\u00e2\u00ca\u00c9" - // 012.34.....56789ABCDEF - + " !\"#\u00ba%&'()*+,-./" - // 0123456789ABCDEF - + "0123456789:;<=>?" - // 0.....123456789ABCDEF - + "\u00cdABCDEFGHIJKLMNO" - // 0123456789AB.....C.....D.....E.....F..... - + "PQRSTUVWXYZ\u00c3\u00d5\u00da\u00dc\u00a7" - // 0123456789ABCDEF - + "~abcdefghijklmno" - // 0123456789AB.....C.....DE.....F..... - + "pqrstuvwxyz\u00e3\u00f5`\u00fc\u00e0", - - /** - * National Language Identifier: 0x04 - * A.3.4 Bengali National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.EF..... - "\u0981\u0982\u0983\u0985\u0986\u0987\u0988\u0989\u098a\u098b\n\u098c \r \u098f" - // 0.....123.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0990 \u0993\u0994\u0995\u0996\u0997\u0998\u0999\u099a\uffff\u099b\u099c\u099d\u099e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u099f\u09a0\u09a1\u09a2\u09a3\u09a4)(\u09a5\u09a6,\u09a7.\u09a8" - // 0123456789ABCD.....E.....F - + "0123456789:; \u09aa\u09ab?" - // 0.....1.....2.....3.....4.....56.....789A.....B.....C.....D.....E.....F..... - + "\u09ac\u09ad\u09ae\u09af\u09b0 \u09b2 \u09b6\u09b7\u09b8\u09b9\u09bc\u09bd" - // 0.....1.....2.....3.....4.....5.....6.....789.....A.....BCD.....E.....F..... - + "\u09be\u09bf\u09c0\u09c1\u09c2\u09c3\u09c4 \u09c7\u09c8 \u09cb\u09cc\u09cd" - // 0.....123456789ABCDEF - + "\u09ceabcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u09d7\u09dc\u09dd\u09f0\u09f1", - - /** - * National Language Identifier: 0x05 - * A.3.5 Gujarati National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.EF..... - "\u0a81\u0a82\u0a83\u0a85\u0a86\u0a87\u0a88\u0a89\u0a8a\u0a8b\n\u0a8c\u0a8d\r \u0a8f" - // 0.....1.....23.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0a90\u0a91 \u0a93\u0a94\u0a95\u0a96\u0a97\u0a98\u0a99\u0a9a\uffff\u0a9b\u0a9c\u0a9d\u0a9e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0a9f\u0aa0\u0aa1\u0aa2\u0aa3\u0aa4)(\u0aa5\u0aa6,\u0aa7.\u0aa8" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0aaa\u0aab?" - // 0.....1.....2.....3.....4.....56.....7.....89.....A.....B.....C.....D.....E.....F..... - + "\u0aac\u0aad\u0aae\u0aaf\u0ab0 \u0ab2\u0ab3 \u0ab5\u0ab6\u0ab7\u0ab8\u0ab9\u0abc\u0abd" - // 0.....1.....2.....3.....4.....5.....6.....7.....89.....A.....B.....CD.....E.....F..... - + "\u0abe\u0abf\u0ac0\u0ac1\u0ac2\u0ac3\u0ac4\u0ac5 \u0ac7\u0ac8\u0ac9 \u0acb\u0acc\u0acd" - // 0.....123456789ABCDEF - + "\u0ad0abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0ae0\u0ae1\u0ae2\u0ae3\u0af1", - - /** - * National Language Identifier: 0x06 - * A.3.6 Hindi National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "\u0901\u0902\u0903\u0905\u0906\u0907\u0908\u0909\u090a\u090b\n\u090c\u090d\r\u090e\u090f" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0910\u0911\u0912\u0913\u0914\u0915\u0916\u0917\u0918\u0919\u091a\uffff\u091b\u091c\u091d\u091e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u091f\u0920\u0921\u0922\u0923\u0924)(\u0925\u0926,\u0927.\u0928" - // 0123456789ABC.....D.....E.....F - + "0123456789:;\u0929\u092a\u092b?" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u092c\u092d\u092e\u092f\u0930\u0931\u0932\u0933\u0934\u0935\u0936\u0937\u0938\u0939\u093c\u093d" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u093e\u093f\u0940\u0941\u0942\u0943\u0944\u0945\u0946\u0947\u0948\u0949\u094a\u094b\u094c\u094d" - // 0.....123456789ABCDEF - + "\u0950abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0972\u097b\u097c\u097e\u097f", - - /** - * National Language Identifier: 0x07 - * A.3.7 Kannada National Language Locking Shift Table - */ - // 01.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.E.....F..... - " \u0c82\u0c83\u0c85\u0c86\u0c87\u0c88\u0c89\u0c8a\u0c8b\n\u0c8c \r\u0c8e\u0c8f" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0c90 \u0c92\u0c93\u0c94\u0c95\u0c96\u0c97\u0c98\u0c99\u0c9a\uffff\u0c9b\u0c9c\u0c9d\u0c9e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0c9f\u0ca0\u0ca1\u0ca2\u0ca3\u0ca4)(\u0ca5\u0ca6,\u0ca7.\u0ca8" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0caa\u0cab?" - // 0.....1.....2.....3.....4.....5.....6.....7.....89.....A.....B.....C.....D.....E.....F..... - + "\u0cac\u0cad\u0cae\u0caf\u0cb0\u0cb1\u0cb2\u0cb3 \u0cb5\u0cb6\u0cb7\u0cb8\u0cb9\u0cbc\u0cbd" - // 0.....1.....2.....3.....4.....5.....6.....78.....9.....A.....BC.....D.....E.....F..... - + "\u0cbe\u0cbf\u0cc0\u0cc1\u0cc2\u0cc3\u0cc4 \u0cc6\u0cc7\u0cc8 \u0cca\u0ccb\u0ccc\u0ccd" - // 0.....123456789ABCDEF - + "\u0cd5abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0cd6\u0ce0\u0ce1\u0ce2\u0ce3", - - /** - * National Language Identifier: 0x08 - * A.3.8 Malayalam National Language Locking Shift Table - */ - // 01.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.E.....F..... - " \u0d02\u0d03\u0d05\u0d06\u0d07\u0d08\u0d09\u0d0a\u0d0b\n\u0d0c \r\u0d0e\u0d0f" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0d10 \u0d12\u0d13\u0d14\u0d15\u0d16\u0d17\u0d18\u0d19\u0d1a\uffff\u0d1b\u0d1c\u0d1d\u0d1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0d1f\u0d20\u0d21\u0d22\u0d23\u0d24)(\u0d25\u0d26,\u0d27.\u0d28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0d2a\u0d2b?" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....EF..... - + "\u0d2c\u0d2d\u0d2e\u0d2f\u0d30\u0d31\u0d32\u0d33\u0d34\u0d35\u0d36\u0d37\u0d38\u0d39 \u0d3d" - // 0.....1.....2.....3.....4.....5.....6.....78.....9.....A.....BC.....D.....E.....F..... - + "\u0d3e\u0d3f\u0d40\u0d41\u0d42\u0d43\u0d44 \u0d46\u0d47\u0d48 \u0d4a\u0d4b\u0d4c\u0d4d" - // 0.....123456789ABCDEF - + "\u0d57abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0d60\u0d61\u0d62\u0d63\u0d79", - - /** - * National Language Identifier: 0x09 - * A.3.9 Oriya National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.EF..... - "\u0b01\u0b02\u0b03\u0b05\u0b06\u0b07\u0b08\u0b09\u0b0a\u0b0b\n\u0b0c \r \u0b0f" - // 0.....123.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0b10 \u0b13\u0b14\u0b15\u0b16\u0b17\u0b18\u0b19\u0b1a\uffff\u0b1b\u0b1c\u0b1d\u0b1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0b1f\u0b20\u0b21\u0b22\u0b23\u0b24)(\u0b25\u0b26,\u0b27.\u0b28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0b2a\u0b2b?" - // 0.....1.....2.....3.....4.....56.....7.....89.....A.....B.....C.....D.....E.....F..... - + "\u0b2c\u0b2d\u0b2e\u0b2f\u0b30 \u0b32\u0b33 \u0b35\u0b36\u0b37\u0b38\u0b39\u0b3c\u0b3d" - // 0.....1.....2.....3.....4.....5.....6.....789.....A.....BCD.....E.....F..... - + "\u0b3e\u0b3f\u0b40\u0b41\u0b42\u0b43\u0b44 \u0b47\u0b48 \u0b4b\u0b4c\u0b4d" - // 0.....123456789ABCDEF - + "\u0b56abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0b57\u0b60\u0b61\u0b62\u0b63", - - /** - * National Language Identifier: 0x0A - * A.3.10 Punjabi National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9A.BCD.EF..... - "\u0a01\u0a02\u0a03\u0a05\u0a06\u0a07\u0a08\u0a09\u0a0a \n \r \u0a0f" - // 0.....123.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0a10 \u0a13\u0a14\u0a15\u0a16\u0a17\u0a18\u0a19\u0a1a\uffff\u0a1b\u0a1c\u0a1d\u0a1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0a1f\u0a20\u0a21\u0a22\u0a23\u0a24)(\u0a25\u0a26,\u0a27.\u0a28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0a2a\u0a2b?" - // 0.....1.....2.....3.....4.....56.....7.....89.....A.....BC.....D.....E.....F - + "\u0a2c\u0a2d\u0a2e\u0a2f\u0a30 \u0a32\u0a33 \u0a35\u0a36 \u0a38\u0a39\u0a3c " - // 0.....1.....2.....3.....4.....56789.....A.....BCD.....E.....F..... - + "\u0a3e\u0a3f\u0a40\u0a41\u0a42 \u0a47\u0a48 \u0a4b\u0a4c\u0a4d" - // 0.....123456789ABCDEF - + "\u0a51abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0a70\u0a71\u0a72\u0a73\u0a74", - - /** - * National Language Identifier: 0x0B - * A.3.11 Tamil National Language Locking Shift Table - */ - // 01.....2.....3.....4.....5.....6.....7.....8.....9A.BCD.E.....F..... - " \u0b82\u0b83\u0b85\u0b86\u0b87\u0b88\u0b89\u0b8a \n \r\u0b8e\u0b8f" - // 0.....12.....3.....4.....5.....6789.....A.....B.....CD.....EF..... - + "\u0b90 \u0b92\u0b93\u0b94\u0b95 \u0b99\u0b9a\uffff \u0b9c \u0b9e" - // 012.....3456.....7.....89ABCDEF..... - + " !\u0b9f \u0ba3\u0ba4)( , .\u0ba8" - // 0123456789ABC.....D.....EF - + "0123456789:;\u0ba9\u0baa ?" - // 012.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....EF - + " \u0bae\u0baf\u0bb0\u0bb1\u0bb2\u0bb3\u0bb4\u0bb5\u0bb6\u0bb7\u0bb8\u0bb9 " - // 0.....1.....2.....3.....4.....5678.....9.....A.....BC.....D.....E.....F..... - + "\u0bbe\u0bbf\u0bc0\u0bc1\u0bc2 \u0bc6\u0bc7\u0bc8 \u0bca\u0bcb\u0bcc\u0bcd" - // 0.....123456789ABCDEF - + "\u0bd0abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0bd7\u0bf0\u0bf1\u0bf2\u0bf9", - - /** - * National Language Identifier: 0x0C - * A.3.12 Telugu National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....CD.E.....F..... - "\u0c01\u0c02\u0c03\u0c05\u0c06\u0c07\u0c08\u0c09\u0c0a\u0c0b\n\u0c0c \r\u0c0e\u0c0f" - // 0.....12.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0c10 \u0c12\u0c13\u0c14\u0c15\u0c16\u0c17\u0c18\u0c19\u0c1a\uffff\u0c1b\u0c1c\u0c1d\u0c1e" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u0c1f\u0c20\u0c21\u0c22\u0c23\u0c24)(\u0c25\u0c26,\u0c27.\u0c28" - // 0123456789ABCD.....E.....F - + "0123456789:; \u0c2a\u0c2b?" - // 0.....1.....2.....3.....4.....5.....6.....7.....89.....A.....B.....C.....D.....EF..... - + "\u0c2c\u0c2d\u0c2e\u0c2f\u0c30\u0c31\u0c32\u0c33 \u0c35\u0c36\u0c37\u0c38\u0c39 \u0c3d" - // 0.....1.....2.....3.....4.....5.....6.....78.....9.....A.....BC.....D.....E.....F..... - + "\u0c3e\u0c3f\u0c40\u0c41\u0c42\u0c43\u0c44 \u0c46\u0c47\u0c48 \u0c4a\u0c4b\u0c4c\u0c4d" - // 0.....123456789ABCDEF - + "\u0c55abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0c56\u0c60\u0c61\u0c62\u0c63", - - /** - * National Language Identifier: 0x0D - * A.3.13 Urdu National Language Locking Shift Table - */ - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.B.....C.....D.E.....F..... - "\u0627\u0622\u0628\u067b\u0680\u067e\u06a6\u062a\u06c2\u067f\n\u0679\u067d\r\u067a\u067c" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u062b\u062c\u0681\u0684\u0683\u0685\u0686\u0687\u062d\u062e\u062f\uffff\u068c\u0688\u0689\u068a" - // 012.....3.....4.....5.....6.....7.....89A.....B.....CD.....EF..... - + " !\u068f\u068d\u0630\u0631\u0691\u0693)(\u0699\u0632,\u0696.\u0698" - // 0123456789ABC.....D.....E.....F - + "0123456789:;\u069a\u0633\u0634?" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u0635\u0636\u0637\u0638\u0639\u0641\u0642\u06a9\u06aa\u06ab\u06af\u06b3\u06b1\u0644\u0645\u0646" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....C.....D.....E.....F..... - + "\u06ba\u06bb\u06bc\u0648\u06c4\u06d5\u06c1\u06be\u0621\u06cc\u06d0\u06d2\u064d\u0650\u064f\u0657" - // 0.....123456789ABCDEF - + "\u0654abcdefghijklmno" - // 0123456789AB.....C.....D.....E.....F..... - + "pqrstuvwxyz\u0655\u0651\u0653\u0656\u0670" -]; - -// National Language Single Shift Tables, see 3GPP TS 23.038 -this.PDU_NL_SINGLE_SHIFT_TABLES = [ - /** - * National Language Identifier: 0x00 - * 6.2.1.1 GSM 7 bit default alphabet extension table - */ - // 0123456789A.....BCD.....EF - " \u000c \ufffe " - // 0123456789AB.....CDEF - + " ^ \uffff " - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "| " - // 0123456789ABCDEF - + " " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x01 - * A.2.1 Turkish National Language Single Shift Table - */ - // 0123456789A.....BCD.....EF - " \u000c \ufffe " - // 0123456789AB.....CDEF - + " ^ \uffff " - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 01234567.....89.....ABCDEF - + "| \u011e \u0130 " - // 0123.....456789ABCDEF - + " \u015e " - // 0123.....45.....67.....89.....ABCDEF - + " \u00e7 \u20ac \u011f \u0131 " - // 0123.....456789ABCDEF - + " \u015f ", - - /** - * National Language Identifier: 0x02 - * A.2.2 Spanish National Language Single Shift Table - */ - // 0123456789.....A.....BCD.....EF - " \u00e7\u000c \ufffe " - // 0123456789AB.....CDEF - + " ^ \uffff " - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 01.....23456789.....ABCDEF..... - + "|\u00c1 \u00cd \u00d3" - // 012345.....6789ABCDEF - + " \u00da " - // 01.....2345.....6789.....ABCDEF..... - + " \u00e1 \u20ac \u00ed \u00f3" - // 012345.....6789ABCDEF - + " \u00fa ", - - /** - * National Language Identifier: 0x03 - * A.2.3 Portuguese National Language Single Shift Table - */ - // 012345.....6789.....A.....B.....C.....D.....E.....F..... - " \u00ea \u00e7\u000c\u00d4\u00f4\ufffe\u00c1\u00e1" - // 012.....3.....45.....6.....7.....8.....9.....AB.....CDEF..... - + " \u03a6\u0393^\u03a9\u03a0\u03a8\u03a3\u0398 \uffff \u00ca" - // 0123456789ABCDEF. - + " {} \\" - // 0123456789ABCDEF - + " [~] " - // 01.....23456789.....ABCDEF..... - + "|\u00c0 \u00cd \u00d3" - // 012345.....6789AB.....C.....DEF - + " \u00da \u00c3\u00d5 " - // 01.....2345.....6789.....ABCDEF..... - + " \u00c2 \u20ac \u00ed \u00f3" - // 012345.....6789AB.....C.....DEF..... - + " \u00fa \u00e3\u00f5 \u00e2", - - /** - * National Language Identifier: 0x04 - * A.2.4 Bengali National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u09e6\u09e7\uffff\u09e8\u09e9\u09ea\u09eb" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u09ec\u09ed\u09ee\u09ef\u09df\u09e0\u09e1\u09e2{}\u09e3\u09f2\u09f3\u09f4\u09f5\\" - // 0.....1.....2.....3.....4.....56789ABCDEF - + "\u09f6\u09f7\u09f8\u09f9\u09fa [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x05 - * A.2.5 Gujarati National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0ae6\u0ae7\u0ae8\u0ae9" - // 0.....1.....2.....3.....4.....5.....6789ABCDEF. - + "\u0aea\u0aeb\u0aec\u0aed\u0aee\u0aef {} \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x06 - * A.2.6 Hindi National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0966\u0967\u0968\u0969" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u096a\u096b\u096c\u096d\u096e\u096f\u0951\u0952{}\u0953\u0954\u0958\u0959\u095a\\" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....BCDEF - + "\u095b\u095c\u095d\u095e\u095f\u0960\u0961\u0962\u0963\u0970\u0971 [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x07 - * A.2.7 Kannada National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0ce6\u0ce7\u0ce8\u0ce9" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....BCDEF. - + "\u0cea\u0ceb\u0cec\u0ced\u0cee\u0cef\u0cde\u0cf1{}\u0cf2 \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x08 - * A.2.8 Malayalam National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0d66\u0d67\u0d68\u0d69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u0d6a\u0d6b\u0d6c\u0d6d\u0d6e\u0d6f\u0d70\u0d71{}\u0d72\u0d73\u0d74\u0d75\u0d7a\\" - // 0.....1.....2.....3.....4.....56789ABCDEF - + "\u0d7b\u0d7c\u0d7d\u0d7e\u0d7f [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x09 - * A.2.9 Oriya National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0b66\u0b67\u0b68\u0b69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....DEF. - + "\u0b6a\u0b6b\u0b6c\u0b6d\u0b6e\u0b6f\u0b5c\u0b5d{}\u0b5f\u0b70\u0b71 \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0A - * A.2.10 Punjabi National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0a66\u0a67\u0a68\u0a69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....EF. - + "\u0a6a\u0a6b\u0a6c\u0a6d\u0a6e\u0a6f\u0a59\u0a5a{}\u0a5b\u0a5c\u0a5e\u0a75 \\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0B - * A.2.11 Tamil National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0964\u0965\uffff\u0be6\u0be7\u0be8\u0be9" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u0bea\u0beb\u0bec\u0bed\u0bee\u0bef\u0bf3\u0bf4{}\u0bf5\u0bf6\u0bf7\u0bf8\u0bfa\\" - // 0123456789ABCDEF - + " [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0C - * A.2.12 Telugu National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789AB.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#* \uffff\u0c66\u0c67\u0c68\u0c69" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u0c6a\u0c6b\u0c6c\u0c6d\u0c6e\u0c6f\u0c58\u0c59{}\u0c78\u0c79\u0c7a\u0c7b\u0c7c\\" - // 0.....1.....2.....3456789ABCDEF - + "\u0c7d\u0c7e\u0c7f [~] " - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " ", - - /** - * National Language Identifier: 0x0D - * A.2.13 Urdu National Language Single Shift Table - */ - // 01.....23.....4.....5.6.....789A.....BCD.....EF - "@\u00a3$\u00a5\u00bf\"\u00a4%&'\u000c*+\ufffe-/" - // 0123.....45.....6789.....A.....B.....C.....D.....E.....F..... - + "<=>\u00a1^\u00a1_#*\u0600\u0601\uffff\u06f0\u06f1\u06f2\u06f3" - // 0.....1.....2.....3.....4.....5.....6.....7.....89A.....B.....C.....D.....E.....F. - + "\u06f4\u06f5\u06f6\u06f7\u06f8\u06f9\u060c\u060d{}\u060e\u060f\u0610\u0611\u0612\\" - // 0.....1.....2.....3.....4.....5.....6.....7.....8.....9.....A.....B.....CDEF..... - + "\u0613\u0614\u061b\u061f\u0640\u0652\u0658\u066b\u066c\u0672\u0673\u06cd[~]\u06d4" - // 0123456789ABCDEF - + "|ABCDEFGHIJKLMNO" - // 0123456789ABCDEF - + "PQRSTUVWXYZ " - // 012345.....6789ABCDEF - + " \u20ac " - // 0123456789ABCDEF - + " " -]; - -// Special SMS Message Indication constants -this.PDU_MWI_STORE_TYPE_BIT = 0x80; -this.PDU_MWI_STORE_TYPE_DISCARD = 0x00; -this.PDU_MWI_STORE_TYPE_STORE = 0x80; - -this.GSM_SMS_STRICT_7BIT_CHARMAP = { -//"\u0024": "\u0024", // "$" => "$", already in default alphabet -//"\u00a5": "\u00a5", // "¥" => "¥", already in default alphabet - "\u00c0": "\u0041", // "À" => "A" - "\u00c1": "\u0041", // "Á" => "A" - "\u00c2": "\u0041", // "Â" => "A" - "\u00c3": "\u0041", // "Ã" => "A" -//"\u00c4": "\u00c4", // "Ä" => "Ä", already in default alphabet -//"\u00c5": "\u00c5", // "Å" => "Å", already in default alphabet -//"\u00c6": "\u00c6", // "Æ" => "Æ", already in default alphabet -//"\u00c7": "\u00c7", // "Ç" => "Ç", already in default alphabet - "\u00c8": "\u0045", // "È" => "E" -//"\u00c9": "\u00c9", // "É" => "É", already in default alphabet - "\u00ca": "\u0045", // "Ê" => "E" - "\u00cb": "\u0045", // "Ë" => "E" - "\u00cc": "\u0049", // "Ì" => "I" - "\u00cd": "\u0049", // "Í" => "I" - "\u00ce": "\u0049", // "Î" => "I" - "\u00cf": "\u0049", // "Ï" => "I" -//"\u00d1": "\u00d1", // "Ñ" => "Ñ", already in default alphabet - "\u00d2": "\u004f", // "Ò" => "O" - "\u00d3": "\u004f", // "Ó" => "O" - "\u00d4": "\u004f", // "Ô" => "O" - "\u00d5": "\u004f", // "Õ" => "O" -//"\u00d6": "\u00d6", // "Ö" => "Ö", already in default alphabet - "\u00d9": "\u0055", // "Ù" => "U" - "\u00da": "\u0055", // "Ú" => "U" - "\u00db": "\u0055", // "Û" => "U" -//"\u00dc": "\u00dc", // "Ü" => "Ü", already in default alphabet -//"\u00df": "\u00df", // "ß" => "ß", already in default alphabet -//"\u00e0": "\u00e0", // "à" => "à", already in default alphabet - "\u00e1": "\u0061", // "á" => "a" - "\u00e2": "\u0061", // "â" => "a" - "\u00e3": "\u0061", // "ã" => "a" -//"\u00e4": "\u00e4", // "ä" => "ä", already in default alphabet -//"\u00e5": "\u00e5", // "å" => "å", already in default alphabet -//"\u00e6": "\u00e6", // "æ" => "æ", already in default alphabet - "\u00e7": "\u00c7", // "ç" => "Ç" -//"\u00e8": "\u00e8", // "è" => "è", already in default alphabet -//"\u00e9": "\u00e9", // "é" => "é", already in default alphabet - "\u00ea": "\u0065", // "ê" => "e" - "\u00eb": "\u0065", // "ë" => "e" -//"\u00ec": "\u00ec", // "ì" => "ì", already in default alphabet - "\u00ed": "\u0069", // "í" => "i" - "\u00ee": "\u0069", // "î" => "i" - "\u00ef": "\u0069", // "ï" => "i" -//"\u00f1": "\u00f1", // "ñ" => "ñ", already in default alphabet -//"\u00f2": "\u00f2", // "ò" => "ò", already in default alphabet - "\u00f3": "\u006f", // "ó" => "o" - "\u00f4": "\u006f", // "ô" => "o" - "\u00f5": "\u006f", // "õ" => "o" -//"\u00f6": "\u00f6", // "ö" => "ö", already in default alphabet -//"\u00f8": "\u00f8", // "ø" => "ø", already in default alphabet -//"\u00f9": "\u00f9", // "ù" => "ù", already in default alphabet - "\u00fa": "\u0075", // "ú" => "u" - "\u00fb": "\u0075", // "û" => "u" -//"\u00fc": "\u00fc", // "ü" => "ü", already in default alphabet - "\u00fe": "\u0074", // "þ" => "t" - "\u0100": "\u0041", // "Ā" => "A" - "\u0101": "\u0061", // "ā" => "a" - "\u0106": "\u0043", // "Ć" => "C" - "\u0107": "\u0063", // "ć" => "c" - "\u010c": "\u0043", // "Č" => "C" - "\u010d": "\u0063", // "č" => "c" - "\u010f": "\u0064", // "ď" => "d" - "\u0110": "\u0044", // "Đ" => "D" - "\u0111": "\u0064", // "đ" => "d" - "\u0112": "\u0045", // "Ē" => "E" - "\u0113": "\u0065", // "ē" => "e" - "\u0118": "\u0045", // "Ę" => "E" - "\u0119": "\u0065", // "ę" => "e" - "\u0128": "\u0049", // "Ĩ" => "I" - "\u0129": "\u0069", // "ĩ" => "i" - "\u012a": "\u0049", // "Ī" => "I" - "\u012b": "\u0069", // "ī" => "i" - "\u012e": "\u0049", // "Į" => "I" - "\u012f": "\u0069", // "į" => "i" - "\u0141": "\u004c", // "Ł" => "L" - "\u0142": "\u006c", // "ł" => "l" - "\u0143": "\u004e", // "Ń" => "N" - "\u0144": "\u006e", // "ń" => "n" - "\u0147": "\u004e", // "Ň" => "N" - "\u0148": "\u006e", // "ň" => "n" - "\u014c": "\u004f", // "Ō" => "O" - "\u014d": "\u006f", // "ō" => "o" - "\u0152": "\u004f", // "Œ" => "O" - "\u0153": "\u006f", // "œ" => "o" - "\u0158": "\u0052", // "Ř" => "R" - "\u0159": "\u0072", // "ř" => "r" - "\u0160": "\u0053", // "Š" => "S" - "\u0161": "\u0073", // "š" => "s" - "\u0165": "\u0074", // "ť" => "t" - "\u0168": "\u0055", // "Ū" => "U" - "\u0169": "\u0075", // "ū" => "u" - "\u016a": "\u0055", // "Ū" => "U" - "\u016b": "\u0075", // "ū" => "u" - "\u0178": "\u0059", // "Ÿ" => "Y" - "\u0179": "\u005a", // "Ź" => "Z" - "\u017a": "\u007a", // "ź" => "z" - "\u017b": "\u005a", // "Ż" => "Z" - "\u017c": "\u007a", // "ż" => "z" - "\u017d": "\u005a", // "Ž" => "Z" - "\u017e": "\u007a", // "ž" => "z" - "\u025b": "\u0045", // "ɛ" => "E" -//"\u0398": "\u0398", // "Θ" => "Θ", already in default alphabet - "\u1e7c": "\u0056", // "Ṽ" => "V" - "\u1e7d": "\u0076", // "ṽ" => "v" - "\u1ebc": "\u0045", // "Ẽ" => "E" - "\u1ebd": "\u0065", // "ẽ" => "e" - "\u1ef8": "\u0059", // "Ỹ" => "Y" - "\u1ef9": "\u0079", // "ỹ" => "y" - "\u20a4": "\u00a3", // "₤" => "£" -//"\u20ac": "\u20ac", // "€" => "€", already in default alphabet -}; - -this.RADIOTECH_FAMILY_3GPP = 1; // GSM, WCDMA, LTE -this.RADIOTECH_FAMILY_3GPP2 = 2; // CDMA, EVDO - -this.DATACALL_RADIOTECHNOLOGY_CDMA = 0; -this.DATACALL_RADIOTECHNOLOGY_GSM = 1; - -this.DATACALL_AUTH_NONE = 0; -this.DATACALL_AUTH_PAP = 1; -this.DATACALL_AUTH_CHAP = 2; -this.DATACALL_AUTH_PAP_OR_CHAP = 3; - -this.GECKO_DATACALL_AUTH_NONE = "none"; -this.GECKO_DATACALL_AUTH_PAP = "pap"; -this.GECKO_DATACALL_AUTH_CHAP = "chap"; -this.GECKO_DATACALL_AUTH_PAP_OR_CHAP = "papOrChap"; -this.GECKO_DATACALL_AUTH_DEFAULT = GECKO_DATACALL_AUTH_PAP_OR_CHAP; -this.RIL_DATACALL_AUTH_TO_GECKO = [ - GECKO_DATACALL_AUTH_NONE, // DATACALL_AUTH_NONE - GECKO_DATACALL_AUTH_PAP, // DATACALL_AUTH_PAP - GECKO_DATACALL_AUTH_CHAP, // DATACALL_AUTH_CHAP - GECKO_DATACALL_AUTH_PAP_OR_CHAP // DATACALL_AUTH_PAP_OR_CHAP -]; - -this.GECKO_DATACALL_PDP_TYPE_IP = "IP"; -this.GECKO_DATACALL_PDP_TYPE_IPV4V6 = "IPV4V6"; -this.GECKO_DATACALL_PDP_TYPE_IPV6 = "IPV6"; -this.GECKO_DATACALL_PDP_TYPE_DEFAULT = GECKO_DATACALL_PDP_TYPE_IP; -this.RIL_DATACALL_PDP_TYPES = [ - GECKO_DATACALL_PDP_TYPE_IP, - GECKO_DATACALL_PDP_TYPE_IPV4V6, - GECKO_DATACALL_PDP_TYPE_IPV6, -]; - -this.DATACALL_PROFILE_DEFAULT = 0; -this.DATACALL_PROFILE_TETHERED = 1; -this.DATACALL_PROFILE_OEM_BASE = 1000; - -this.DATACALL_DEACTIVATE_NO_REASON = 0; -this.DATACALL_DEACTIVATE_RADIO_SHUTDOWN = 1; - -this.DATACALL_ACTIVE_UNKNOWN = -1; -this.DATACALL_INACTIVE = 0; -this.DATACALL_ACTIVE_DOWN = 1; -this.DATACALL_ACTIVE_UP = 2; - -this.DATACALL_FAIL_NONE = 0; -this.DATACALL_FAIL_OPERATOR_BARRED = 0x08; -this.DATACALL_FAIL_INSUFFICIENT_RESOURCES = 0x1A; -this.DATACALL_FAIL_MISSING_UKNOWN_APN = 0x1B; -this.DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C; -this.DATACALL_FAIL_USER_AUTHENTICATION = 0x1D; -this.DATACALL_FAIL_ACTIVATION_REJECT_GGSN = 0x1E; -this.DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F; -this.DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20; -this.DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21; -this.DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22; -this.DATACALL_FAIL_NSAPI_IN_USE = 0x23; -this.DATACALL_FAIL_ONLY_IPV4_ALLOWED = 0x32; -this.DATACALL_FAIL_ONLY_IPV6_ALLOWED = 0x33; -this.DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED = 0x34; -this.DATACALL_FAIL_PROTOCOL_ERRORS = 0x6F; -this.DATACALL_FAIL_VOICE_REGISTRATION_FAIL = -1; -this.DATACALL_FAIL_DATA_REGISTRATION_FAIL = -2; -this.DATACALL_FAIL_SIGNAL_LOST = -3; -this.DATACALL_FAIL_PREF_RADIO_TECH_CHANGED = -4; -this.DATACALL_FAIL_RADIO_POWER_OFF = -5; -this.DATACALL_FAIL_TETHERED_CALL_ACTIVE = -6; -this.DATACALL_FAIL_ERROR_UNSPECIFIED = 0xffff; - -// Keep consistent with nsINetworkManager.NETWORK_STATE_*. -this.GECKO_NETWORK_STATE_UNKNOWN = -1; -this.GECKO_NETWORK_STATE_CONNECTING = 0; -this.GECKO_NETWORK_STATE_CONNECTED = 1; -this.GECKO_NETWORK_STATE_DISCONNECTING = 2; -this.GECKO_NETWORK_STATE_DISCONNECTED = 3; - -// 3GPP 24.008 Annex H. -this.CALL_FAIL_UNOBTAINABLE_NUMBER = 1; -this.CALL_FAIL_NO_ROUTE_TO_DESTINATION = 3; -this.CALL_FAIL_CHANNEL_UNACCEPTABLE = 6; -this.CALL_FAIL_OPERATOR_DETERMINED_BARRING = 8; -this.CALL_FAIL_NORMAL = 16; -this.CALL_FAIL_BUSY = 17; -this.CALL_FAIL_NO_USER_RESPONDING = 18; -this.CALL_FAIL_USER_ALERTING = 19; -this.CALL_FAIL_CALL_REJECTED = 21; -this.CALL_FAIL_NUMBER_CHANGED = 22; -this.CALL_FAIL_CALL_REJECTED_DESTINATION_FEATURE = 24; -this.CALL_FAIL_CALL_PRE_EMPTION = 25; -this.CALL_FAIL_DEST_OUT_OF_ORDER = 27; -this.CALL_FAIL_INVALID_FORMAT = 28; -this.CALL_FAIL_FACILITY_REJECTED = 29; -this.CALL_FAIL_RESPONSE_TO_STATUS_ENQUIRY = 30; -this.CALL_FAIL_NORMAL_UNSPECIFIED = 31; -this.CALL_FAIL_CONGESTION = 34; -this.CALL_FAIL_NETWORK_OUT_OF_ORDER = 38; -this.CALL_FAIL_NETWORK_TEMP_FAILURE = 41; -this.CALL_FAIL_SWITCHING_EQUIP_CONGESTION = 42; -this.CALL_FAIL_ACCESS_INFO_DISCARDED = 43; -this.CALL_FAIL_REQUESTED_CHANNEL_NOT_AVAILABLE = 44; -this.CALL_FAIL_RESOURCE_UNAVAILABLE = 47; -this.CALL_FAIL_QOS_UNAVAILABLE = 49; -this.CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED = 50; -this.CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG = 55; -this.CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED = 57; -this.CALL_FAIL_BEARER_CAPABILITY_NOT_AVAILABLE = 58; -this.CALL_FAIL_SERVICE_NOT_AVAILABLE = 63; -this.CALL_FAIL_BEARER_NOT_IMPLEMENTED = 65; -this.CALL_FAIL_ACM_LIMIT_EXCEEDED = 68; -this.CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED = 69; -this.CALL_FAIL_UNRESTRICTED_BEARER_NOT_AVAILABLE = 70; -this.CALL_FAIL_SERVICE_NOT_IMPLEMENTED = 79; -this.CALL_FAIL_INVALID_TRANSACTION_ID = 81; -this.CALL_FAIL_USER_NOT_CUG_MEMBER = 87; -this.CALL_FAIL_INCOMPATIBLE_DESTINATION = 88; -this.CALL_FAIL_INVALID_TRANSIT_NETWORK_SELECTION = 91; -this.CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE = 95; -this.CALL_FAIL_INVALID_MANDATORY_INFO = 96; -this.CALL_FAIL_MESSAGE_TYPE_NOT_IMPLEMENTED = 97; -this.CALL_FAIL_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE = 98; -this.CALL_FAIL_INFO_ELEMENT_NOT_IMPLEMENTED = 99; -this.CALL_FAIL_CONDITIONAL_IE_ERROR = 100; -this.CALL_FAIL_MESSAGE_INCOMPABITLE_PROTOCOL_STATE = 101; -this.CALL_FAIL_RECOVERY_ON_TIMER_EXPIRY = 102; -this.CALL_FAIL_PROTOCOL_ERROR = 111; -this.CALL_FAIL_INTERWORKING = 127; -// AOSP ril.h -this.CALL_FAIL_CALL_BARRED = 240; -this.CALL_FAIL_FDN_BLOCKED = 241; -this.CALL_FAIL_IMSI_UNKNOWN_IN_VLR = 242; -this.CALL_FAIL_IMEI_NOT_ACCEPTED = 243; -this.CALL_FAIL_DIAL_MODIFIED_TO_USSD = 244; // STK Call Control -this.CALL_FAIL_DIAL_MODIFIED_TO_SS = 245; -this.CALL_FAIL_DIAL_MODIFIED_TO_DIAL = 246; -this.CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE = 1000; -this.CALL_FAIL_CDMA_DROP = 1001; -this.CALL_FAIL_CDMA_INTERCEPT = 1002; -this.CALL_FAIL_CDMA_REORDER = 1003; -this.CALL_FAIL_CDMA_SO_REJECT = 1004; -this.CALL_FAIL_CDMA_RETRY_ORDER = 1005; -this.CALL_FAIL_CDMA_ACCESS_FAILURE = 1006; -this.CALL_FAIL_CDMA_PREEMPTED = 1007; -this.CALL_FAIL_CDMA_NOT_EMERGENCY = 1008; // For non-emergency number dialed - // during emergency callback mode -this.CALL_FAIL_CDMA_ACCESS_BLOCKED = 1009; -this.CALL_FAIL_ERROR_UNSPECIFIED = 0xffff; - -// See nsIMobileConnection::MOBILE_RADIO_STATE_* -this.GECKO_RADIOSTATE_UNKNOWN = -1; -this.GECKO_RADIOSTATE_ENABLED = 0; -this.GECKO_RADIOSTATE_DISABLED = 1; - -// Only used in ril_worker.js -this.GECKO_CARDSTATE_UNINITIALIZED = 4294967294; // UINT32_MAX - 1 -// See nsIIcc::CARD_STATE_* -this.GECKO_CARDSTATE_UNDETECTED = 4294967295; // UINT32_MAX -this.GECKO_CARDSTATE_UNKNOWN = 0; -this.GECKO_CARDSTATE_READY = 1; -this.GECKO_CARDSTATE_PIN_REQUIRED = 2; -this.GECKO_CARDSTATE_PUK_REQUIRED = 3; -this.GECKO_CARDSTATE_PERMANENT_BLOCKED = 4; -this.GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS = 5; -this.GECKO_CARDSTATE_PERSONALIZATION_READY = 6; -this.GECKO_CARDSTATE_NETWORK_LOCKED = 7; -this.GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED = 8; -this.GECKO_CARDSTATE_CORPORATE_LOCKED = 9; -this.GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED = 10; -this.GECKO_CARDSTATE_SIM_LOCKED = 11; -this.GECKO_CARDSTATE_NETWORK_PUK_REQUIRED = 12; -this.GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED = 13; -this.GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED = 14; -this.GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED = 15; -this.GECKO_CARDSTATE_SIM_PUK_REQUIRED = 16; -this.GECKO_CARDSTATE_NETWORK1_LOCKED = 17; -this.GECKO_CARDSTATE_NETWORK2_LOCKED = 18; -this.GECKO_CARDSTATE_HRPD_NETWORK_LOCKED = 19; -this.GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED = 20; -this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED = 21; -this.GECKO_CARDSTATE_RUIM_LOCKED = 22; -this.GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED = 23; -this.GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED = 24; -this.GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED = 25; -this.GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED = 26; -this.GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED = 27; -this.GECKO_CARDSTATE_RUIM_PUK_REQUIRED = 28; -this.GECKO_CARDSTATE_ILLEGAL = 29; - -// See nsIIcc::CARD_LOCK_TYPE_* -this.GECKO_CARDLOCK_PIN = 0; -this.GECKO_CARDLOCK_PIN2 = 1; -this.GECKO_CARDLOCK_PUK = 2; -this.GECKO_CARDLOCK_PUK2 = 3; -this.GECKO_CARDLOCK_NCK = 4; -this.GECKO_CARDLOCK_NSCK = 5; -this.GECKO_CARDLOCK_NCK1 = 6; -this.GECKO_CARDLOCK_NCK2 = 7; -this.GECKO_CARDLOCK_HNCK = 8; -this.GECKO_CARDLOCK_CCK = 9; -this.GECKO_CARDLOCK_SPCK = 10; -this.GECKO_CARDLOCK_PCK = 11; -this.GECKO_CARDLOCK_RCCK = 12; -this.GECKO_CARDLOCK_RSPCK = 13; -this.GECKO_CARDLOCK_NCK_PUK = 14; -this.GECKO_CARDLOCK_NSCK_PUK = 15; -this.GECKO_CARDLOCK_NCK1_PUK = 16; -this.GECKO_CARDLOCK_NCK2_PUK = 17; -this.GECKO_CARDLOCK_HNCK_PUK = 18; -this.GECKO_CARDLOCK_CCK_PUK = 19; -this.GECKO_CARDLOCK_SPCK_PUK = 20; -this.GECKO_CARDLOCK_PCK_PUK = 21; -this.GECKO_CARDLOCK_RCCK_PUK = 22; -this.GECKO_CARDLOCK_RSPCK_PUK = 23; -this.GECKO_CARDLOCK_FDN = 24; - -this.GECKO_CARDLOCK_TO_FACILITY = {}; -GECKO_CARDLOCK_TO_FACILITY[GECKO_CARDLOCK_PIN] = ICC_CB_FACILITY_SIM; -GECKO_CARDLOCK_TO_FACILITY[GECKO_CARDLOCK_FDN] = ICC_CB_FACILITY_FDN; - -this.GECKO_CARDLOCK_TO_SEL_CODE = {}; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PIN] = ICC_SEL_CODE_SIM_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PIN2] = ICC_SEL_CODE_SIM_PIN2; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PUK] = ICC_SEL_CODE_SIM_PUK; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_PUK2] = ICC_SEL_CODE_SIM_PUK2; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_NCK] = ICC_SEL_CODE_PH_NET_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_NSCK] = ICC_SEL_CODE_PH_NETSUB_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_CCK] = ICC_SEL_CODE_PH_CORP_PIN; -GECKO_CARDLOCK_TO_SEL_CODE[GECKO_CARDLOCK_SPCK] = ICC_SEL_CODE_PH_SP_PIN; -// TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM @ -// ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_PCK. - -// See nsIIcc::CARD_CONTACT_TYPE_* -this.GECKO_CARDCONTACT_TYPE_ADN = 0; -this.GECKO_CARDCONTACT_TYPE_FDN = 1; -this.GECKO_CARDCONTACT_TYPE_SDN = 2; - -// See nsIIcc::CARD_MVNO_TYPE_* -this.GECKO_CARDMVNO_TYPE_IMSI = 0; -this.GECKO_CARDMVNO_TYPE_SPN = 1; -this.GECKO_CARDMVNO_TYPE_GID = 2; - -// See nsIIcc::CARD_SERVICE_* -this.GECKO_CARDSERVICE_FDN = 0; - -// See ril.h RIL_PersoSubstate -this.PERSONSUBSTATE = {}; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_UNKNOWN] = GECKO_CARDSTATE_UNKNOWN; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_IN_PROGRESS] = GECKO_CARDSTATE_PERSONALIZATION_IN_PROGRESS; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_READY] = GECKO_CARDSTATE_PERSONALIZATION_READY; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK] = GECKO_CARDSTATE_NETWORK_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET] = GECKO_CARDSTATE_NETWORK_SUBSET_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_CORPORATE] = GECKO_CARDSTATE_CORPORATE_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER] = GECKO_CARDSTATE_SERVICE_PROVIDER_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SIM] = GECKO_CARDSTATE_SIM_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_PUK] = GECKO_CARDSTATE_NETWORK_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK] = GECKO_CARDSTATE_NETWORK_SUBSET_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK] = GECKO_CARDSTATE_CORPORATE_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK] = GECKO_CARDSTATE_SERVICE_PROVIDER_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_SIM_SIM_PUK] = GECKO_CARDSTATE_SIM_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK1] = GECKO_CARDSTATE_NETWORK1_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK2] = GECKO_CARDSTATE_NETWORK2_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_HRPD] = GECKO_CARDSTATE_HRPD_NETWORK_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_CORPORATE] = GECKO_CARDSTATE_RUIM_CORPORATE_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER] = GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_RUIM] = GECKO_CARDSTATE_RUIM_LOCKED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK] = GECKO_CARDSTATE_NETWORK1_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK] = GECKO_CARDSTATE_NETWORK2_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_HRPD_PUK] = GECKO_CARDSTATE_HRPD_NETWORK_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK] = GECKO_CARDSTATE_RUIM_CORPORATE_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK] = GECKO_CARDSTATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED; -PERSONSUBSTATE[CARD_PERSOSUBSTATE_RUIM_RUIM_PUK] = GECKO_CARDSTATE_RUIM_PUK_REQUIRED; - -// See nsIMobileConnection::NETWORK_SELECTION_MODE_* -this.GECKO_NETWORK_SELECTION_UNKNOWN = -1; -this.GECKO_NETWORK_SELECTION_AUTOMATIC = 0; -this.GECKO_NETWORK_SELECTION_MANUAL = 1; - -this.GECKO_MOBILE_CONNECTION_STATE_UNKNOWN = null; -this.GECKO_MOBILE_CONNECTION_STATE_NOTSEARCHING = "notSearching"; -this.GECKO_MOBILE_CONNECTION_STATE_SEARCHING = "searching"; -this.GECKO_MOBILE_CONNECTION_STATE_REGISTERED = "registered"; -this.GECKO_MOBILE_CONNECTION_STATE_DENIED = "denied"; - -this.NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE = {}; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_NOT_SEARCHING] = GECKO_MOBILE_CONNECTION_STATE_NOTSEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_REGISTERED_HOME] = GECKO_MOBILE_CONNECTION_STATE_REGISTERED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_SEARCHING] = GECKO_MOBILE_CONNECTION_STATE_SEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_DENIED] = GECKO_MOBILE_CONNECTION_STATE_DENIED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_UNKNOWN] = GECKO_MOBILE_CONNECTION_STATE_UNKNOWN; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_REGISTERED_ROAMING] = GECKO_MOBILE_CONNECTION_STATE_REGISTERED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_NOT_SEARCHING_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_NOTSEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_SEARCHING_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_SEARCHING; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_DENIED_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_DENIED; -NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[NETWORK_CREG_STATE_UNKNOWN_EMERGENCY_CALLS] = GECKO_MOBILE_CONNECTION_STATE_UNKNOWN; - - -// Should match enum TelephonyCallDisconnectedReason defined in TelephonyCall.webidl -this.GECKO_CALL_ERROR_BAD_NUMBER = "BadNumberError"; -this.GECKO_CALL_ERROR_NO_ROUTE_TO_DESTINATION = "NoRouteToDestinationError"; -this.GECKO_CALL_ERROR_CHANNEL_UNACCEPTABLE = "ChannelUnacceptableError"; -this.GECKO_CALL_ERROR_OPERATOR_DETERMINED_BARRING = "OperatorDeterminedBarringError"; -this.GECKO_CALL_ERROR_NORMAL_CALL_CLEARING = "NormalCallClearingError"; -this.GECKO_CALL_ERROR_BUSY = "BusyError"; -this.GECKO_CALL_ERROR_NO_USER_RESPONDING = "NoUserRespondingError"; -this.GECKO_CALL_ERROR_USER_ALERTING = "UserAlertingNoAnswerError"; -this.GECKO_CALL_ERROR_REJECTED = "CallRejectedError"; -this.GECKO_CALL_ERROR_NUMBER_CHANGED = "NumberChangedError"; -this.GECKO_CALL_ERROR_REJECTED_DETINATION_FEATURE = "CallRejectedDestinationFeatureError"; -this.GECKO_CALL_ERROR_PRE_EMPTION = "PreEmptionError"; -this.GECKO_CALL_ERROR_DEST_OUT_OF_ORDER = "DestinationOutOfOrderError"; -this.GECKO_CALL_ERROR_INVALID_NUMBER_FORMAT = "InvalidNumberFormatError"; -this.GECKO_CALL_ERROR_FACILITY_REJECTED = "FacilityRejectedError"; -this.GECKO_CALL_ERROR_RESPONSE_TO_STATUS_ENQUIRY = "ResponseToStatusEnquiryError"; -this.GECKO_CALL_ERROR_CONGESTION = "CongestionError"; -this.GECKO_CALL_ERROR_NETWORK_OUT_OF_ORDER = "NetworkOutOfOrderError"; -this.GECKO_CALL_ERROR_NETWORK_TEMP_FAILURE = "NetworkTempFailureError"; -this.GECKO_CALL_ERROR_SWITCHING_EQUIP_CONGESTION = "SwitchingEquipCongestionError"; -this.GECKO_CALL_ERROR_ACCESS_INFO_DISCARDED = "AccessInfoDiscardedError"; -this.GECKO_CALL_ERROR_REQUESTED_CHANNEL_NOT_AVAILABLE = "RequestedChannelNotAvailableError"; -this.GECKO_CALL_ERROR_RESOURCE_UNAVAILABLE = "ResourceUnavailableError"; -this.GECKO_CALL_ERROR_QOS_UNAVAILABLE = "QosUnavailableError"; -this.GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_SUBSCRIBED = "RequestedFacilityNotSubscribedError"; -this.GECKO_CALL_ERROR_INCOMING_CALLS_BARRED_WITHIN_CUG = "IncomingCallsBarredWithinCugError"; -this.GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AUTHORIZED = "BearerCapabilityNotAuthorizedError"; -this.GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AVAILABLE = "BearerCapabilityNotAvailableError"; -this.GECKO_CALL_ERROR_BEARER_NOT_IMPLEMENTED = "BearerNotImplementedError"; -this.GECKO_CALL_ERROR_SERVICE_NOT_AVAILABLE = "ServiceNotAvailableError"; -this.GECKO_CALL_ERROR_INCOMING_CALL_EXCEEDED = "IncomingCallExceededError"; -this.GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_IMPLEMENTED = "RequestedFacilityNotImplementedError"; -this.GECKO_CALL_ERROR_UNRESTRICTED_BEARER_NOT_AVAILABLE = "UnrestrictedBearerNotAvailableError"; -this.GECKO_CALL_ERROR_SERVICE_NOT_IMPLEMENTED = "ServiceNotImplementedError"; -this.GECKO_CALL_ERROR_INVALID_TRANSACTION_ID = "InvalidTransactionIdError"; -this.GECKO_CALL_ERROR_USER_NOT_CUG_MEMBER = "NotCugMemberError"; -this.GECKO_CALL_ERROR_INCOMPATIBLE_DESTINATION = "IncompatibleDestinationError"; -this.GECKO_CALL_ERROR_INVALID_TRANSIT_NETWORK_SELECTION = "InvalidTransitNetworkSelectionError"; -this.GECKO_CALL_ERROR_SEMANTICALLY_INCORRECT_MESSAGE = "SemanticallyIncorrectMessageError"; -this.GECKO_CALL_ERROR_INVALID_MANDATORY_INFO = "InvalidMandatoryInfoError"; -this.GECKO_CALL_ERROR_MESSAGE_TYPE_NOT_IMPLEMENTED = "MessageTypeNotImplementedError"; -this.GECKO_CALL_ERROR_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE = "MessageTypeIncompatibleProtocolStateError"; -this.GECKO_CALL_ERROR_INFO_ELEMENT_NOT_IMPLEMENTED = "InfoElementNotImplementedError"; -this.GECKO_CALL_ERROR_CONDITIONAL_IE = "ConditionalIeError"; -this.GECKO_CALL_ERROR_MESSAGE_INCOMPATIBLE_PROTOCOL_STATE = "MessageIncompatibleProtocolStateError"; -this.GECKO_CALL_ERROR_RECOVERY_ON_TIMER_EXPIRY = "RecoveryOnTimerExpiryError"; -this.GECKO_CALL_ERROR_PROTOCOL = "ProtocolError"; -this.GECKO_CALL_ERROR_INTERWORKING = "InterworkingError"; -this.GECKO_CALL_ERROR_BARRED = "BarredError"; -this.GECKO_CALL_ERROR_FDN_BLOCKED = "FDNBlockedError"; -this.GECKO_CALL_ERROR_SUBSCRIBER_UNKNOWN = "SubscriberUnknownError"; -this.GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED = "DeviceNotAcceptedError"; -this.GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED = "ModifiedDialError"; -this.GECKO_CALL_ERROR_CDMA_LOCKED_UNTIL_POWER_CYCLE = "CdmaLockedUntilPowerCycleError"; -this.GECKO_CALL_ERROR_CDMA_DROP = "CdmaDropError"; -this.GECKO_CALL_ERROR_CDMA_INTERCEPT = "CdmaInterceptError"; -this.GECKO_CALL_ERROR_CDMA_REORDER = "CdmaReorderError"; -this.GECKO_CALL_ERROR_CDMA_SO_REJECT = "CdmaSoRejectError"; -this.GECKO_CALL_ERROR_CDMA_RETRY_ORDER = "CdmaRetryOrderError"; -this.GECKO_CALL_ERROR_CDMA_ACCESS_FAILURE = "CdmaAcessError"; -this.GECKO_CALL_ERROR_CDMA_PREEMPTED = "CdmaPreemptedError"; -this.GECKO_CALL_ERROR_CDMA_NOT_EMERGENCY = "CdmaNotEmergencyError"; -this.GECKO_CALL_ERROR_CDMA_ACCESS_BLOCKED = "CdmaAccessBlockedError"; -this.GECKO_CALL_ERROR_UNSPECIFIED = "UnspecifiedError"; - -this.RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR = {}; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_UNOBTAINABLE_NUMBER] = GECKO_CALL_ERROR_BAD_NUMBER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NO_ROUTE_TO_DESTINATION] = GECKO_CALL_ERROR_NO_ROUTE_TO_DESTINATION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CHANNEL_UNACCEPTABLE] = GECKO_CALL_ERROR_CHANNEL_UNACCEPTABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_OPERATOR_DETERMINED_BARRING] = GECKO_CALL_ERROR_OPERATOR_DETERMINED_BARRING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NORMAL] = GECKO_CALL_ERROR_NORMAL_CALL_CLEARING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BUSY] = GECKO_CALL_ERROR_BUSY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NO_USER_RESPONDING] = GECKO_CALL_ERROR_NO_USER_RESPONDING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_USER_ALERTING] = GECKO_CALL_ERROR_USER_ALERTING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_REJECTED] = GECKO_CALL_ERROR_REJECTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NUMBER_CHANGED] = GECKO_CALL_ERROR_NUMBER_CHANGED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_REJECTED_DESTINATION_FEATURE] = GECKO_CALL_ERROR_REJECTED_DETINATION_FEATURE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_PRE_EMPTION] = GECKO_CALL_ERROR_PRE_EMPTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DEST_OUT_OF_ORDER] = GECKO_CALL_ERROR_DEST_OUT_OF_ORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_FORMAT] = GECKO_CALL_ERROR_INVALID_NUMBER_FORMAT; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_FACILITY_REJECTED] = GECKO_CALL_ERROR_FACILITY_REJECTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_RESPONSE_TO_STATUS_ENQUIRY] = GECKO_CALL_ERROR_RESPONSE_TO_STATUS_ENQUIRY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NORMAL_UNSPECIFIED] = GECKO_CALL_ERROR_NORMAL_CALL_CLEARING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CONGESTION] = GECKO_CALL_ERROR_CONGESTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NETWORK_OUT_OF_ORDER] = GECKO_CALL_ERROR_NETWORK_OUT_OF_ORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_NETWORK_TEMP_FAILURE] = GECKO_CALL_ERROR_NETWORK_TEMP_FAILURE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SWITCHING_EQUIP_CONGESTION] = GECKO_CALL_ERROR_SWITCHING_EQUIP_CONGESTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ACCESS_INFO_DISCARDED] = GECKO_CALL_ERROR_ACCESS_INFO_DISCARDED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_REQUESTED_CHANNEL_NOT_AVAILABLE] = GECKO_CALL_ERROR_REQUESTED_CHANNEL_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_RESOURCE_UNAVAILABLE] = GECKO_CALL_ERROR_RESOURCE_UNAVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_QOS_UNAVAILABLE] = GECKO_CALL_ERROR_QOS_UNAVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_REQUESTED_FACILITY_NOT_SUBSCRIBED] = GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_SUBSCRIBED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INCOMING_CALLS_BARRED_WITHIN_CUG] = GECKO_CALL_ERROR_INCOMING_CALLS_BARRED_WITHIN_CUG; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BEARER_CAPABILITY_NOT_AUTHORIZED] = GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AUTHORIZED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BEARER_CAPABILITY_NOT_AVAILABLE] = GECKO_CALL_ERROR_BEARER_CAPABILITY_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SERVICE_NOT_AVAILABLE] = GECKO_CALL_ERROR_SERVICE_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BEARER_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_BEARER_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ACM_LIMIT_EXCEEDED] = GECKO_CALL_ERROR_INCOMING_CALL_EXCEEDED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_REQUESTED_FACILITY_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_REQUESTED_FACILITY_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_UNRESTRICTED_BEARER_NOT_AVAILABLE] = GECKO_CALL_ERROR_UNRESTRICTED_BEARER_NOT_AVAILABLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SERVICE_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_SERVICE_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_TRANSACTION_ID] = GECKO_CALL_ERROR_INVALID_TRANSACTION_ID; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_USER_NOT_CUG_MEMBER] = GECKO_CALL_ERROR_USER_NOT_CUG_MEMBER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INCOMPATIBLE_DESTINATION] = GECKO_CALL_ERROR_INCOMPATIBLE_DESTINATION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_TRANSIT_NETWORK_SELECTION] = GECKO_CALL_ERROR_INVALID_TRANSIT_NETWORK_SELECTION; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_SEMANTICALLY_INCORRECT_MESSAGE] = GECKO_CALL_ERROR_SEMANTICALLY_INCORRECT_MESSAGE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INVALID_MANDATORY_INFO] = GECKO_CALL_ERROR_INVALID_MANDATORY_INFO; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_MESSAGE_TYPE_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_MESSAGE_TYPE_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE] = GECKO_CALL_ERROR_MESSAGE_TYPE_INCOMPATIBLE_PROTOCOL_STATE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INFO_ELEMENT_NOT_IMPLEMENTED] = GECKO_CALL_ERROR_INFO_ELEMENT_NOT_IMPLEMENTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CONDITIONAL_IE_ERROR] = GECKO_CALL_ERROR_CONDITIONAL_IE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_MESSAGE_INCOMPABITLE_PROTOCOL_STATE] = GECKO_CALL_ERROR_MESSAGE_INCOMPATIBLE_PROTOCOL_STATE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_RECOVERY_ON_TIMER_EXPIRY] = GECKO_CALL_ERROR_RECOVERY_ON_TIMER_EXPIRY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_PROTOCOL_ERROR] = GECKO_CALL_ERROR_PROTOCOL; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_INTERWORKING] = GECKO_CALL_ERROR_INTERWORKING; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CALL_BARRED] = GECKO_CALL_ERROR_BARRED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_FDN_BLOCKED] = GECKO_CALL_ERROR_FDN_BLOCKED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMSI_UNKNOWN_IN_VLR] = GECKO_CALL_ERROR_SUBSCRIBER_UNKNOWN; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_IMEI_NOT_ACCEPTED] = GECKO_CALL_ERROR_DEVICE_NOT_ACCEPTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DIAL_MODIFIED_TO_USSD] = GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DIAL_MODIFIED_TO_SS] = GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_DIAL_MODIFIED_TO_DIAL] = GECKO_CALL_ERROR_MODIFIED_TO_DIAL_FAILED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_LOCKED_UNTIL_POWER_CYCLE] = GECKO_CALL_ERROR_CDMA_LOCKED_UNTIL_POWER_CYCLE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_DROP] = GECKO_CALL_ERROR_CDMA_DROP; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_INTERCEPT] = GECKO_CALL_ERROR_CDMA_INTERCEPT; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_REORDER] = GECKO_CALL_ERROR_CDMA_REORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_SO_REJECT] = GECKO_CALL_ERROR_CDMA_SO_REJECT; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_RETRY_ORDER] = GECKO_CALL_ERROR_CDMA_RETRY_ORDER; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_ACCESS_FAILURE] = GECKO_CALL_ERROR_CDMA_ACCESS_FAILURE; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_PREEMPTED] = GECKO_CALL_ERROR_CDMA_PREEMPTED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_NOT_EMERGENCY] = GECKO_CALL_ERROR_CDMA_NOT_EMERGENCY; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_CDMA_ACCESS_BLOCKED] = GECKO_CALL_ERROR_CDMA_ACCESS_BLOCKED; -RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_ERROR_UNSPECIFIED] = GECKO_CALL_ERROR_UNSPECIFIED; - -this.GECKO_DATACALL_ERROR_OPERATOR_BARRED = "OperatorBarredError"; -this.GECKO_DATACALL_ERROR_INSUFFICIENT_RESOURCES = "InsufficientResourcesError"; -this.GECKO_DATACALL_ERROR_MISSING_UKNOWN_APN = "MissingUnknownAPNError"; -this.GECKO_DATACALL_ERROR_UNKNOWN_PDP_ADDRESS_TYPE = "UnknownPDPAddressTypeError"; -this.GECKO_DATACALL_ERROR_USER_AUTHENTICATION = "UserAuthenticationError"; -this.GECKO_DATACALL_ERROR_ACTIVATION_REJECT_GGSN = "ActivationRejectGGSNError"; -this.GECKO_DATACALL_ERROR_ACTIVATION_REJECT_UNSPECIFIED = "ActivationRejectUnspecifiedError"; -this.GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUPPORTED = "ServiceOptionNotSupportedError"; -this.GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED = "ServiceOptionNotSubscribedError"; -this.GECKO_DATACALL_ERROR_SERVICE_OPTION_OUT_OF_ORDER = "ServiceOptionOutOfOrderError"; -this.GECKO_DATACALL_ERROR_NSAPI_IN_USE = "NSAPIInUseError"; -this.GECKO_DATACALL_ERROR_ONLY_IPV4_ALLOWED = "OnlyIPv4Error"; -this.GECKO_DATACALL_ERROR_ONLY_IPV6_ALLOWED = "OnlyIPv6Error"; -this.GECKO_DATACALL_ERROR_ONLY_SINGLE_BEARER_ALLOWED = "OnlySingleBearerAllowedError"; -this.GECKO_DATACALL_ERROR_PROTOCOL_ERRORS = "ProtocolErrorsError"; -this.GECKO_DATACALL_ERROR_VOICE_REGISTRATION_FAIL = "VoiceRegistrationFailError"; -this.GECKO_DATACALL_ERROR_DATA_REGISTRATION_FAIL = "DataRegistrationFailError"; -this.GECKO_DATACALL_ERROR_SIGNAL_LOST = "SignalLostError"; -this.GECKO_DATACALL_ERROR_PREF_RADIO_TECH_CHANGED = "PrefRadioTechChangedError"; -this.GECKO_DATACALL_ERROR_RADIO_POWER_OFF = "RadioPowerOffError"; -this.GECKO_DATACALL_ERROR_TETHERED_CALL_ACTIVE = "TetheredCallActiveError"; -this.GECKO_DATACALL_ERROR_UNSPECIFIED = "UnspecifiedError"; - -this.RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR = {}; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_OPERATOR_BARRED] = GECKO_DATACALL_ERROR_OPERATOR_BARRED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_INSUFFICIENT_RESOURCES] = GECKO_DATACALL_ERROR_INSUFFICIENT_RESOURCES; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_MISSING_UKNOWN_APN] = GECKO_DATACALL_ERROR_MISSING_UKNOWN_APN; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_UNKNOWN_PDP_ADDRESS_TYPE] = GECKO_DATACALL_ERROR_UNKNOWN_PDP_ADDRESS_TYPE; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_USER_AUTHENTICATION] = GECKO_DATACALL_ERROR_USER_AUTHENTICATION; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ACTIVATION_REJECT_GGSN] = GECKO_DATACALL_ERROR_ACTIVATION_REJECT_GGSN; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ACTIVATION_REJECT_UNSPECIFIED] = GECKO_DATACALL_ERROR_ACTIVATION_REJECT_UNSPECIFIED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_NOT_SUPPORTED] = GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUPPORTED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED] = GECKO_DATACALL_ERROR_SERVICE_OPTION_NOT_SUBSCRIBED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SERVICE_OPTION_OUT_OF_ORDER] = GECKO_DATACALL_ERROR_SERVICE_OPTION_OUT_OF_ORDER; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_NSAPI_IN_USE] = GECKO_DATACALL_ERROR_NSAPI_IN_USE; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_IPV4_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_IPV4_ALLOWED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_IPV6_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_IPV6_ALLOWED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ONLY_SINGLE_BEARER_ALLOWED] = GECKO_DATACALL_ERROR_ONLY_SINGLE_BEARER_ALLOWED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_PROTOCOL_ERRORS] = GECKO_DATACALL_ERROR_PROTOCOL_ERRORS; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_VOICE_REGISTRATION_FAIL] = GECKO_DATACALL_ERROR_VOICE_REGISTRATION_FAIL; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_DATA_REGISTRATION_FAIL] = GECKO_DATACALL_ERROR_DATA_REGISTRATION_FAIL; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_SIGNAL_LOST] = GECKO_DATACALL_ERROR_SIGNAL_LOST; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_PREF_RADIO_TECH_CHANGED] = GECKO_DATACALL_ERROR_PREF_RADIO_TECH_CHANGED; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_RADIO_POWER_OFF] = GECKO_DATACALL_ERROR_RADIO_POWER_OFF; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_TETHERED_CALL_ACTIVE] = GECKO_DATACALL_ERROR_TETHERED_CALL_ACTIVE; -RIL_DATACALL_FAILCAUSE_TO_GECKO_DATACALL_ERROR[DATACALL_FAIL_ERROR_UNSPECIFIED] = GECKO_DATACALL_ERROR_UNSPECIFIED; - -this.GECKO_RADIO_TECH = [ - null, - "gprs", - "edge", - "umts", - "is95a", - "is95b", - "1xrtt", - "evdo0", - "evdoa", - "hsdpa", - "hsupa", - "hspa", - "evdob", - "ehrpd", - "lte", - "hspa+", - "gsm", - null, - "hspa+", // DC-HSPA+ - "hspa+" -]; - -this.GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN = -1; - -// Call forwarding action. Must be in sync with nsIMobileConnectionService interface -this.CALL_FORWARD_ACTION_DISABLE = 0; -this.CALL_FORWARD_ACTION_ENABLE = 1; -this.CALL_FORWARD_ACTION_QUERY_STATUS = 2; -this.CALL_FORWARD_ACTION_REGISTRATION = 3; -this.CALL_FORWARD_ACTION_ERASURE = 4; - -// Call forwarding reason. Must be in sync with nsIMobileConnectionService interface -this.CALL_FORWARD_REASON_UNCONDITIONAL = 0; -this.CALL_FORWARD_REASON_MOBILE_BUSY = 1; -this.CALL_FORWARD_REASON_NO_REPLY = 2; -this.CALL_FORWARD_REASON_NOT_REACHABLE = 3; -this.CALL_FORWARD_REASON_ALL_CALL_FORWARDING = 4; -this.CALL_FORWARD_REASON_ALL_CONDITIONAL_CALL_FORWARDING = 5; - -// Call barring program. Must be in sync with nsIMobileConnectionService interface -this.CALL_BARRING_PROGRAM_ALL_OUTGOING = 0; -this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL = 1; -this.CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME = 2; -this.CALL_BARRING_PROGRAM_ALL_INCOMING = 3; -this.CALL_BARRING_PROGRAM_INCOMING_ROAMING = 4; -this.CALL_BARRING_PROGRAM_ALL_SERVICE = 5; -this.CALL_BARRING_PROGRAM_OUTGOING_SERVICE = 6; -this.CALL_BARRING_PROGRAM_INCOMING_SERVICE = 7; - -this.CALL_BARRING_PROGRAM_TO_FACILITY = {}; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_OUTGOING] = ICC_CB_FACILITY_BAOC; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL] = ICC_CB_FACILITY_BAOIC; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_INTERNATIONAL_EXCEPT_HOME] = ICC_CB_FACILITY_BAOICxH; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_INCOMING] = ICC_CB_FACILITY_BAIC; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_ROAMING] = ICC_CB_FACILITY_BAICr; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_ALL_SERVICE] = ICC_CB_FACILITY_BA_ALL; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_OUTGOING_SERVICE] = ICC_CB_FACILITY_BA_MO; -CALL_BARRING_PROGRAM_TO_FACILITY[CALL_BARRING_PROGRAM_INCOMING_SERVICE] = ICC_CB_FACILITY_BA_MT; - -/** - * CDMA PDU constants - */ - -// SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 3.4-1 -this.PDU_CDMA_MSG_TYPE_P2P = 0x00; // Point-to-Point -this.PDU_CDMA_MSG_TYPE_BROADCAST = 0x01; // Broadcast -this.PDU_CDMA_MSG_TYPE_ACK = 0x02; // Acknowledge - -// SMS Teleservice Identitifier, as defined in 3GPP2 N.S0005, Table 175 -this.PDU_CDMA_MSG_TELESERIVCIE_ID_SMS = 0x1002; // SMS -this.PDU_CDMA_MSG_TELESERIVCIE_ID_WAP = 0x1004; // WAP -this.PDU_CDMA_MSG_TELESERIVCIE_ID_WEMT = 0x1005; // Wireless Enhanced Messaging Teleservice - // required for fragmented SMS - -// SMS Service Category, as defined in 3GPP2 C.R1001-D, Table 9.3.1-1 -this.PDU_CDMA_MSG_CATEGORY_UNSPEC = 0x00; // Unknown/Unspecified - -// Address Information, Digit Mode, as defined in 3GPP2 C.S0015-A v2.0, sec 3.4.3.3 -this.PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF = 0x00; // Digit Mode : DTMF -this.PDU_CDMA_MSG_ADDR_DIGIT_MODE_ASCII = 0x01; // Digit Mode : 8-bit ASCII with MSB = 0 - -// Address Information, Number Mode, as defined in 3GPP2 C.S0015-A v2.0, sec 3.4.3.3 -this.PDU_CDMA_MSG_ADDR_NUMBER_MODE_ANSI = 0x00; // Number Mode : ANSI T1.607-2000(R2004) -this.PDU_CDMA_MSG_ADDR_NUMBER_MODE_ASCII = 0x01; // Number Mode : Data network address format - -// Address Information, Number Type, as defined in 3GPP2 C.S0015-A v2.0, Table 3.4.3.3-1 -this.PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN = 0x00; // Number Type : Unknown -this.PDU_CDMA_MSG_ADDR_NUMBER_TYPE_INTERNATIONAL = 0x01; // Number Type : Internaltional number(+XXXXX) -this.PDU_CDMA_MSG_ADDR_NUMBER_TYPE_NATIONAL = 0x02; // Number Type : National number - -// Address Information, Number Plan, as defined in 3GPP2 C.S0005-D v2.0, Table 2.7.1.3.2.4-3 -this.PDU_CDMA_MSG_ADDR_NUMBER_PLAN_UNKNOWN = 0x00; // Number Plan : Unknown -this.PDU_CDMA_MSG_ADDR_NUMBER_PLAN_ISDN = 0x01; // Number Plan : ISDN/Telephony numbering plan - -// SMS Encoding, as defined in 3GPP2 C.R1001-D, Table 9.1-1 -this.PDU_CDMA_MSG_CODING_OCTET = 0x00; // octet(8-bit), Not tested -this.PDU_CDMA_MSG_CODING_IS_91 = 0x01; // IS-91 Extended Protocol Message(variable), Not tested -this.PDU_CDMA_MSG_CODING_7BITS_ASCII = 0x02; // 7-bit ASCII(7-bit) -this.PDU_CDMA_MSG_CODING_IA5 = 0x03; // IA5(7-bit), Not tested -this.PDU_CDMA_MSG_CODING_UNICODE = 0x04; // Unicode(16-bit) -this.PDU_CDMA_MSG_CODING_SHIFT_JIS = 0x05; // Shift-6 JIS(8/16-bit variable), Not supported -this.PDU_CDMA_MSG_CODING_KOREAN = 0x06; // Korean(8/16-bit variable), Not supported -this.PDU_CDMA_MSG_CODING_LATIN_HEBREW = 0x07; // Latin/ Hebrew(8-bit), ISO/IEC 8859-8, Not supported -this.PDU_CDMA_MSG_CODING_LATIN = 0x08; // Latin(8-bit), ISO/IEC 8859-1, Not tested -this.PDU_CDMA_MSG_CODING_7BITS_GSM = 0x09; // GSM 7-bit default alphabet(7-bit), Not tested -this.PDU_CDMA_MSG_CODING_GSM_DCS = 0x0A; // GSM Data-Coding-Scheme, Not supported - -// SMS Message Type, as defined in 3GPP2 C.S0015-A v2.0, Table 4.5.1-1 -this.PDU_CDMA_MSG_TYPE_DELIVER = 0x01; // Deliver -this.PDU_CDMA_MSG_TYPE_SUBMIT = 0x02; // Submit -this.PDU_CDMA_MSG_TYPE_DELIVER_ACK = 0x04; // Delivery Acknowledgment - -// SMS User Data Subparameters, as defined in 3GPP2 C.S0015-A v2.0, Table 4.5-1 -this.PDU_CDMA_MSG_USERDATA_MSG_ID = 0x00; // Message Identifier -this.PDU_CDMA_MSG_USERDATA_BODY = 0x01; // User Data Body -this.PDU_CDMA_MSG_USERDATA_TIMESTAMP = 0x03; // Message Center Time Stamp -this.PDU_CDMA_MSG_USERDATA_REPLY_OPTION = 0x0A; // Reply Option -this.PDU_CDMA_LANGUAGE_INDICATOR = 0x0D; // Language Indicator -this.PDU_CDMA_MSG_USERDATA_CALLBACK_NUMBER = 0x0E; // Callback Number -this.PDU_CDMA_MSG_USER_DATA_MSG_STATUS = 0x14; // Message Status - -// CDMA Language Indicator: Language groups -// see 3GPP2 C.R1001-F table 9.2-1 -this.CB_CDMA_LANG_GROUP = [ - null, "en", "fr", "es", "ja", "ko", "zh", "he" -]; - -// IS-91 Message Type, as defined in TIA/EIA/IS-91-A, Table 9 -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_VOICEMAIL_STATUS = 0x82; -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS_FULL = 0x83; -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_CLI = 0x84; -this.PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS = 0x85; - -// Information Record Type, reference from ril.h -this.PDU_CDMA_INFO_REC_TYPE_DISPLAY = 0; -this.PDU_CDMA_INFO_REC_TYPE_CALLED_PARTY_NUMBER = 1; -this.PDU_CDMA_INFO_REC_TYPE_CALLING_PARTY_NUMBER = 2; -this.PDU_CDMA_INFO_REC_TYPE_CONNECTED_NUMBER =3; -this.PDU_CDMA_INFO_REC_TYPE_SIGNAL = 4; -this.PDU_CDMA_INFO_REC_TYPE_REDIRECTING_NUMBER = 5; -this.PDU_CDMA_INFO_REC_TYPE_LINE_CONTROL = 6; -this.PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY = 7; -this.PDU_CDMA_INFO_REC_TYPE_T53_CLIR = 8; -this.PDU_CDMA_INFO_REC_TYPE_T53_RELEASE = 9; -this.PDU_CDMA_INFO_REC_TYPE_T53_AUDIO_CONTROL = 10; - -// Display type of extended display of information record, -// as defined in C.S0005-F v1.0, Table 3.7.5.16-2 -this.INFO_REC_EXTENDED_DISPLAY_BLANK = 0x80; -this.INFO_REC_EXTENDED_DISPLAY_SKIP = 0x81; -this.INFO_REC_EXTENDED_DISPLAY_CONTINATION = 0x82; -this.INFO_REC_EXTENDED_DISPLAY_CALLED_ADDRESS = 0x83; -this.INFO_REC_EXTENDED_DISPLAY_CAUSE = 0x84; -this.INFO_REC_EXTENDED_DISPLAY_PROGRESS_INDICATOR = 0x85; -this.INFO_REC_EXTENDED_DISPLAY_NOTIFICATION_INDICATOR = 0x86; -this.INFO_REC_EXTENDED_DISPLAY_PROMPT = 0x87; -this.INFO_REC_EXTENDED_DISPLAY_ACCUMULATED_DIGITS = 0x88; -this.INFO_REC_EXTENDED_DISPLAY_STATUS = 0x89; -this.INFO_REC_EXTENDED_DISPLAY_INBAND = 0x8A; -this.INFO_REC_EXTENDED_DISPLAY_CALLING_ADDRESS = 0x8B; -this.INFO_REC_EXTENDED_DISPLAY_REASON = 0x8C; -this.INFO_REC_EXTENDED_DISPLAY_CALLING_PARTY_NAME = 0x8D; -this.INFO_REC_EXTENDED_DISPLAY_CALLED_PARTY_NAME = 0x8E; -this.INFO_REC_EXTENDED_DISPLAY_ORIGINAL_CALLED_NAME = 0x8F; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECT_NAME = 0x90; -this.INFO_REC_EXTENDED_DISPLAY_CONNECTED_NAME = 0x91; -this.INFO_REC_EXTENDED_DISPLAY_ORIGINATING_RESTRICTIONS = 0x92; -this.INFO_REC_EXTENDED_DISPLAY_DATE_TIME_OF_DAY = 0x93; -this.INFO_REC_EXTENDED_DISPLAY_CALL_APPEARANCE_ID = 0x94; -this.INFO_REC_EXTENDED_DISPLAY_FEATURE_ADDRESS = 0x95; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECTION_NAME = 0x96; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECTION_NUMBER = 0x97; -this.INFO_REC_EXTENDED_DISPLAY_REDIRECTING_NUMBER = 0x98; -this.INFO_REC_EXTENDED_DISPLAY_ORIGINAL_CALLED_NUMBER = 0x99; -this.INFO_REC_EXTENDED_DISPLAY_CONNECTED_NUMBER = 0x9A; -this.INFO_REC_EXTENDED_DISPLAY_TEXT = 0x9B; - -/** - * The table for MCC/MNC which the length of MNC is 3. - * - * This table is built from below links. - * - http://www.itu.int/pub/T-SP-E.212B-2013 - * - http://en.wikipedia.org/wiki/Mobile_Network_Code - */ -this.PLMN_HAVING_3DIGITS_MNC = { - // Puerto Rico. - "330": - ["110", // América Móvil - "120" // PR Wireless - ], - // Trinidad and Tobago. - "374": - ["130", // Digicel Trinidad and Tobago Ltd. - "140" // LaqTel Ltd. - ], - // India. - "405": - ["000", // Shyam Telelink Ltd. - "005", // Reliance, Delhi - "006", // Reliance, Gujarat - "007", // Reliance, Haryana - "009", // Reliance, J&K - "010", // Reliance, Karnataka - "011", // Reliance, Kerala - "012", // Reliance, Andhra Pradesh - "013", // Reliance, Maharashtr - "014", // Reliance, Madhya Pradesh - "018", // Reliance, Punjab - "020", // Reliance, Tamilnadu - "021", // Reliance, UP (East) - "022", // Reliance, UP (West) - "025", // TATA DOCOMO, Andhra Pradesh - "026", // TATA DOCOMO, Assam - "027", // TATA DOCOMO, Bihar - "028", // TATA DOCOMO, Chennai - "029", // TATA DOCOMO, Delhi - "030", // TATA DOCOMO, Gujarat - "031", // TATA DOCOMO, Haryana - "032", // TATA DOCOMO, Himachal Pradesh - "033", // Reliance, Bihar - "034", // TATA DOCOMO, Kamataka - "035", // TATA DOCOMO, Kerala - "036", // TATA DOCOMO, Kolkata - "037", // TATA DOCOMO, Maharashtra - "038", // TATA DOCOMO, Madhya Pradesh - "039", // TATA DOCOMO, Mumbai - "040", // Reliance, Chennai - "041", // TATA DOCOMO, Orissa - "042", // TATA DOCOMO, Punjab - "043", // TATA DOCOMO, Rajasthan - "044", // TATA DOCOMO, Tamilnadu - "045", // TATA DOCOMO, UP (East) - "046", // TATA DOCOMO, UP (West) - "047", // TATA DOCOMO, West Bengal - "750", // Vodafone IN, J&K - "751", // Vodafone IN, Assam - "752", // Vodafone IN, Bihar - "753", // Vodafone IN, Orissa - "754", // Vodafone IN, Himachal Pradesh - "755", // Vodafone IN, North East - "756", // Vodafone IN, Madhya Pradesh & Chhattisgarh - "799", // Idea, MUMBAI - "800", // Aircell, Delhi - "801", // Aircell, Andhra Pradesh - "802", // Aircell, Gujarat - "803", // Aircell, Kamataka - "804", // Aircell, Maharashtra - "805", // Aircell, Mumbai - "806", // Aircell, Rajasthan - "807", // Aircell, Haryana - "808", // Aircell, Madhya Pradesh - "809", // Aircell, Kerala - "810", // Aircell, Uttar Pradesh (East) - "811", // Aircell, Uttar Pradesh (West) - "812", // Aircell, Punjab - "818", // Uninor, Uttar Pradesh (West) - "819", // Uninor, Andhra Pradesh - "820", // Uninor, Karnataka - "821", // Uninor, Kerala - "822", // Uninor, Kolkata - "824", // Videocon, Assam - "827", // Videocon, Gujarat - "834", // Videocon, Madhya Pradesh - "840", // Jio, West Bengal - "844", // Uninor, Delhi & NCR - "845", // IDEA, Assam - "846", // IDEA, Jammu & Kashmir - "847", // IDEA, Karnataka - "848", // IDEA, Kolkata - "849", // IDEA, North East - "850", // IDEA, Orissa - "851", // IDEA, Punjab - "852", // IDEA, Tamil Nadu - "853", // IDEA, West Bengal - "854", // Jio, Andra Pradesh - "855", // Jio, Assam - "856", // Jio, Bihar - "857", // Jio, Gujarat - "858", // Jio, Haryana - "859", // Jio, Himachal Pradesh - "860", // Jio, Jammu Kashmir - "861", // Jio, Karnataka - "862", // Jio, Kerala - "863", // Jio, Madhyya Pradesh - "864", // Jio, Maharashtra - "865", // Jio, North East - "866", // Jio, Orissa - "867", // Jio, Punjab - "868", // Jio, Rajasthan - "869", // Jio, Tamil Nadu Chennai - "870", // Jio, Uttar Pradesh West - "871", // Jio, Uttar Pradesh East - "872", // Jio, Delhi - "873", // Jio, Kolkatta - "874", // Jio, Mumbai - "875", // Uninor, Assam - "880", // Uninor, West Bengal - "881", // S Tel, Assam - "908", // IDEA, Andhra Pradesh - "909", // IDEA, Delhi - "910", // IDEA, Haryana - "911", // Etisalat, Maharashtra - "912", // Etisalat, Andhra Pradesh - "913", // Etisalat, Delhi & NCR - "914", // Etisalat, Gujarat - "917", // Etisalat, Kerala - "927", // Uninor, Gujarat - "929" // Uninor, Maharashtra - ], - // Malaysia. - "502": - ["150", // Tune Talk Sdn Bhd - "151", // Baraka Telecom Sdn Bhd (MVNE) - "152", // YTL Communications Sdn Bhd - "156" // Altel Communications Sdn Bhd - ], - // Brazil. - "724": - ["055" // Sercomtel - ] -}; - -/** - * The table for MCC which the length of MNC is 3 - * - * This table is built from below links. - * - http://www.itu.int/pub/T-SP-E.212B-2013 - * - http://en.wikipedia.org/wiki/Mobile_Network_Code - */ -this.MCC_TABLE_FOR_MNC_LENGTH_IS_3 = [ - "302", // Canada - "310", // United States of America - "311", // United States of America - "312", // United States of America - "313", // United States of America - "316", // United States of America - "330", // Puerto Rico - "334", // Mexico - "338", // Jamaica - "342", // Barbados - "344", // Antigua and Barbuda - "346", // Cayman Islands - "348", // British Virgin Islands - "350", // Bermuda - "352", // Grenada - "354", // Montserrat - "356", // Saint Kitts and Nevis - "358", // Saint Lucia - "360", // Saint Vincent and the Grenadines - "365", // Anguilla - "366", // Dominica - "376", // Turks and Caicos Islands - "708", // Honduras - "722", // Argentina - "732", // Colombia - "750" // Falkland Islands (Malvinas) -]; - -// Supplementary service notifications, code2, as defined in 3GPP 27.007 7.17 -this.SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD = 2; -this.SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED = 3; - -this.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD = "RemoteHeld"; -this.GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED = "RemoteResumed"; - -this.GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2 = {}; -GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD] = GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD; -GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED] = GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED; - -/** - * The status for an Over-the-Air Service Provisioning / Over-the-Air - * Parameter Administration (OTASP/OTAPA) session. - * - * @see 3GPP2 C.S0016 - */ -this.GECKO_OTA_STATUS_SPL_UNLOCKED = "spl_unlocked"; -this.GECKO_OTA_STATUS_SPC_RETRIES_EXCEEDED = "spc_retries_exceeded"; -this.GECKO_OTA_STATUS_A_KEY_EXCHANGED = "a_key_exchanged"; -this.GECKO_OTA_STATUS_SSD_UPDATED = "ssd_updated"; -this.GECKO_OTA_STATUS_NAM_DOWNLOADED = "nam_downloaded"; -this.GECKO_OTA_STATUS_MDN_DOWNLOADED = "mdn_downloaded"; -this.GECKO_OTA_STATUS_IMSI_DOWNLOADED = "imsi_downloaded"; -this.GECKO_OTA_STATUS_PRL_DOWNLOADED = "prl_downloaded"; -this.GECKO_OTA_STATUS_COMMITTED = "committed"; -this.GECKO_OTA_STATUS_OTAPA_STARTED = "otapa_started"; -this.GECKO_OTA_STATUS_OTAPA_STOPPED = "otapa_stopped"; -this.GECKO_OTA_STATUS_OTAPA_ABORTED = "otapa_aborted"; -this.CDMA_OTA_PROVISION_STATUS_TO_GECKO = [ - GECKO_OTA_STATUS_SPL_UNLOCKED, - GECKO_OTA_STATUS_SPC_RETRIES_EXCEEDED, - GECKO_OTA_STATUS_A_KEY_EXCHANGED, - GECKO_OTA_STATUS_SSD_UPDATED, - GECKO_OTA_STATUS_NAM_DOWNLOADED, - GECKO_OTA_STATUS_MDN_DOWNLOADED, - GECKO_OTA_STATUS_IMSI_DOWNLOADED, - GECKO_OTA_STATUS_PRL_DOWNLOADED, - GECKO_OTA_STATUS_COMMITTED, - GECKO_OTA_STATUS_OTAPA_STARTED, - GECKO_OTA_STATUS_OTAPA_STOPPED, - GECKO_OTA_STATUS_OTAPA_ABORTED -]; - -// Allow this file to be imported via Components.utils.import(). -this.EXPORTED_SYMBOLS = Object.keys(this); diff --git a/dom/system/gonk/ril_worker.js b/dom/system/gonk/ril_worker.js deleted file mode 100644 index 0608a5be3..000000000 --- a/dom/system/gonk/ril_worker.js +++ /dev/null @@ -1,15206 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -/** - * This file implements the RIL worker thread. It communicates with - * the main thread to provide a high-level API to the phone's RIL - * stack, and with the RIL IPC thread to communicate with the RIL - * device itself. These communication channels use message events as - * known from Web Workers: - * - * - postMessage()/"message" events for main thread communication - * - * - postRILMessage()/"RILMessageEvent" events for RIL IPC thread - * communication. - * - * The two main objects in this file represent individual parts of this - * communication chain: - * - * - RILMessageEvent -> Buf -> RIL -> postMessage() -> nsIRadioInterfaceLayer - * - nsIRadioInterfaceLayer -> postMessage() -> RIL -> Buf -> postRILMessage() - * - * Note: The code below is purposely lean on abstractions to be as lean in - * terms of object allocations. As a result, it may look more like C than - * JavaScript, and that's intended. - */ - -/* global BufObject */ -/* global TelephonyRequestQueue */ - -"use strict"; - -importScripts("ril_consts.js"); -importScripts("resource://gre/modules/workers/require.js"); -importScripts("ril_worker_buf_object.js"); -importScripts("ril_worker_telephony_request_queue.js"); - -// set to true in ril_consts.js to see debug messages -var DEBUG = DEBUG_WORKER; -var GLOBAL = this; - -if (!this.debug) { - // Debugging stub that goes nowhere. - this.debug = function debug(message) { - dump("RIL Worker: " + message + "\n"); - }; -} - -// Timeout value for emergency callback mode. -const EMERGENCY_CB_MODE_TIMEOUT_MS = 300000; // 5 mins = 300000 ms. - -const ICC_MAX_LINEAR_FIXED_RECORDS = 0xfe; - -const GET_CURRENT_CALLS_RETRY_MAX = 3; - -var RILQUIRKS_CALLSTATE_EXTRA_UINT32; -var RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL; -var RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS; -var RILQUIRKS_SIGNAL_EXTRA_INT32; -var RILQUIRKS_AVAILABLE_NETWORKS_EXTRA_STRING; -// Needed for call-waiting on Peak device -var RILQUIRKS_EXTRA_UINT32_2ND_CALL; -// On the emulator we support querying the number of lock retries -var RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT; -// Ril quirk to Send STK Profile Download -var RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD; -// Ril quirk to attach data registration on demand. -var RILQUIRKS_DATA_REGISTRATION_ON_DEMAND; -// Ril quirk to control the uicc/data subscription. -var RILQUIRKS_SUBSCRIPTION_CONTROL; -// Ril quirk to describe the SMSC address format. -var RILQUIRKS_SMSC_ADDRESS_FORMAT; - -/** - * The RIL state machine. - * - * This object communicates with rild via parcels and with the main thread - * via post messages. It maintains state about the radio, ICC, calls, etc. - * and acts upon state changes accordingly. - */ -function RilObject(aContext) { - this.context = aContext; - - this.telephonyRequestQueue = new TelephonyRequestQueue(this); - this.currentConferenceState = CALL_STATE_UNKNOWN; - this._pendingSentSmsMap = {}; - this.pendingNetworkType = {}; - this._receivedSmsCbPagesMap = {}; - this._getCurrentCallsRetryCount = 0; -} -RilObject.prototype = { - context: null, - - /** - * RIL version. - */ - version: null, - - /** - * Call state of current conference group. - */ - currentConferenceState: null, - - /** - * Outgoing messages waiting for SMS-STATUS-REPORT. - */ - _pendingSentSmsMap: null, - - /** - * Marker object. - */ - pendingNetworkType: null, - - /** - * Global Cell Broadcast switch. - */ - cellBroadcastDisabled: false, - - /** - * Parsed Cell Broadcast search lists. - * cellBroadcastConfigs.MMI should be preserved over rild reset. - */ - cellBroadcastConfigs: null, - mergedCellBroadcastConfig: null, - - _receivedSmsCbPagesMap: null, - - initRILState: function() { - /** - * One of the RADIO_STATE_* constants. - */ - this.radioState = GECKO_RADIOSTATE_UNKNOWN; - - /** - * True if we are on a CDMA phone. - */ - this._isCdma = false; - - /** - * True if we are in emergency callback mode. - */ - this._isInEmergencyCbMode = false; - - /** - * Set when radio is ready but radio tech is unknown. That is, we are - * waiting for REQUEST_VOICE_RADIO_TECH - */ - this._waitingRadioTech = false; - - /** - * Card state - */ - this.cardState = GECKO_CARDSTATE_UNINITIALIZED; - - /** - * Device Identities including IMEI, IMEISV, ESN and MEID. - */ - this.deviceIdentities = null; - - /** - * ICC information that is not exposed to Gaia. - */ - this.iccInfoPrivate = {}; - - /** - * ICC information, such as MSISDN, MCC, MNC, SPN...etc. - */ - this.iccInfo = {}; - - /** - * CDMA specific information. ex. CDMA Network ID, CDMA System ID... etc. - */ - this.cdmaHome = null; - - /** - * Application identification for apps in ICC. - */ - this.aid = null; - - /** - * Application type for apps in ICC. - */ - this.appType = null; - - this.networkSelectionMode = GECKO_NETWORK_SELECTION_UNKNOWN; - - this.voiceRegistrationState = {}; - this.dataRegistrationState = {}; - - /** - * List of strings identifying the network operator. - */ - this.operator = null; - - /** - * String containing the baseband version. - */ - this.basebandVersion = null; - - // Clean up currentCalls: rild might have restarted. - this.sendChromeMessage({ - rilMessageType: "currentCalls", - calls: {} - }); - - // Don't clean up this._pendingSentSmsMap - // because on rild restart: we may continue with the pending segments. - - /** - * Whether or not the multiple requests in requestNetworkInfo() are currently - * being processed - */ - this._processingNetworkInfo = false; - - /** - * Multiple requestNetworkInfo() in a row before finishing the first - * request, hence we need to fire requestNetworkInfo() again after - * gathering all necessary stuffs. This is to make sure that ril_worker - * gets precise network information. - */ - this._needRepollNetworkInfo = false; - - /** - * Pending messages to be send in batch from requestNetworkInfo() - */ - this._pendingNetworkInfo = {rilMessageType: "networkinfochanged"}; - - /** - * Cell Broadcast Search Lists. - */ - let cbmmi = this.cellBroadcastConfigs && this.cellBroadcastConfigs.MMI; - this.cellBroadcastConfigs = { - MMI: cbmmi || null - }; - this.mergedCellBroadcastConfig = null; - - /** - * True when the request to report SMS Memory Status is pending. - */ - this.pendingToReportSmsMemoryStatus = false; - this.smsStorageAvailable = true; - }, - - /** - * Parse an integer from a string, falling back to a default value - * if the the provided value is not a string or does not contain a valid - * number. - * - * @param string - * String to be parsed. - * @param defaultValue [optional] - * Default value to be used. - * @param radix [optional] - * A number that represents the numeral system to be used. Default 10. - */ - parseInt: function(string, defaultValue, radix) { - let number = parseInt(string, radix || 10); - if (!isNaN(number)) { - return number; - } - if (defaultValue === undefined) { - defaultValue = null; - } - return defaultValue; - }, - - - /** - * Outgoing requests to the RIL. These can be triggered from the - * main thread via messages that look like this: - * - * {rilMessageType: "methodName", - * extra: "parameters", - * go: "here"} - * - * So if one of the following methods takes arguments, it takes only one, - * an object, which then contains all of the parameters as attributes. - * The "@param" documentation is to be interpreted accordingly. - */ - - /** - * Retrieve the ICC's status. - */ - getICCStatus: function() { - this.context.Buf.simpleRequest(REQUEST_GET_SIM_STATUS); - }, - - /** - * Helper function for unlocking ICC locks. - */ - iccUnlockCardLock: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: - this.enterICCPIN(options); - break; - case GECKO_CARDLOCK_PIN2: - this.enterICCPIN2(options); - break; - case GECKO_CARDLOCK_PUK: - this.enterICCPUK(options); - break; - case GECKO_CARDLOCK_PUK2: - this.enterICCPUK2(options); - break; - case GECKO_CARDLOCK_NCK: - case GECKO_CARDLOCK_NSCK: - case GECKO_CARDLOCK_NCK1: - case GECKO_CARDLOCK_NCK2: - case GECKO_CARDLOCK_HNCK: - case GECKO_CARDLOCK_CCK: - case GECKO_CARDLOCK_SPCK: - case GECKO_CARDLOCK_PCK: - case GECKO_CARDLOCK_RCCK: - case GECKO_CARDLOCK_RSPCK: - case GECKO_CARDLOCK_NCK_PUK: - case GECKO_CARDLOCK_NSCK_PUK: - case GECKO_CARDLOCK_NCK1_PUK: - case GECKO_CARDLOCK_NCK2_PUK: - case GECKO_CARDLOCK_HNCK_PUK: - case GECKO_CARDLOCK_CCK_PUK: - case GECKO_CARDLOCK_SPCK_PUK: - case GECKO_CARDLOCK_PCK_PUK: - case GECKO_CARDLOCK_RCCK_PUK: // Fall through. - case GECKO_CARDLOCK_RSPCK_PUK: - this.enterDepersonalization(options); - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - } - }, - - /** - * Enter a PIN to unlock the ICC. - * - * @param password - * String containing the PIN. - * @param [optional] aid - * AID value. - */ - enterICCPIN: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PIN, options); - Buf.writeInt32(2); - Buf.writeString(options.password); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Enter a PIN2 to unlock the ICC. - * - * @param password - * String containing the PIN2. - * @param [optional] aid - * AID value. - */ - enterICCPIN2: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PIN2, options); - Buf.writeInt32(2); - Buf.writeString(options.password); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Requests a network personalization be deactivated. - * - * @param personlization - * One of CARD_PERSOSUBSTATE_* - * @param password - * String containing the password. - */ - enterDepersonalization: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE, options); - Buf.writeInt32(1); - Buf.writeString(options.password); - Buf.sendParcel(); - }, - - /** - * Change the current ICC PIN number. - * - * @param password - * String containing the old PIN value - * @param newPassword - * String containing the new PIN value - * @param [optional] aid - * AID value. - */ - changeICCPIN: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CHANGE_SIM_PIN, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPassword); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Change the current ICC PIN2 number. - * - * @param password - * String containing the old PIN2 value - * @param newPassword - * String containing the new PIN2 value - * @param [optional] aid - * AID value. - */ - changeICCPIN2: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CHANGE_SIM_PIN2, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPassword); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Supplies ICC PUK and a new PIN to unlock the ICC. - * - * @param password - * String containing the PUK value. - * @param newPassword - * String containing the new PIN value. - * @param [optional] aid - * AID value. - */ - enterICCPUK: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PUK, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPin); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Supplies ICC PUK2 and a new PIN2 to unlock the ICC. - * - * @param password - * String containing the PUK2 value. - * @param newPassword - * String containing the new PIN2 value. - * @param [optional] aid - * AID value. - */ - enterICCPUK2: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_ENTER_SIM_PUK2, options); - Buf.writeInt32(3); - Buf.writeString(options.password); - Buf.writeString(options.newPin); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Helper function for changing ICC locks. - */ - iccChangeCardLockPassword: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: - this.changeICCPIN(options); - break; - case GECKO_CARDLOCK_PIN2: - this.changeICCPIN2(options); - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - } - }, - - /** - * Helper function for setting the state of ICC locks. - */ - iccSetCardLockEnabled: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: // Fall through. - case GECKO_CARDLOCK_FDN: - options.facility = GECKO_CARDLOCK_TO_FACILITY[options.lockType]; - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - options.serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - this.setICCFacilityLock(options); - }, - - /** - * Helper function for fetching the state of ICC locks. - */ - iccGetCardLockEnabled: function(options) { - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: // Fall through. - case GECKO_CARDLOCK_FDN: - options.facility = GECKO_CARDLOCK_TO_FACILITY[options.lockType]; - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - options.password = ""; // For query no need to provide pin. - options.serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - this.queryICCFacilityLock(options); - }, - - /** - * Helper function for fetching the number of unlock retries of ICC locks. - * - * We only query the retry count when we're on the emulator. The phones do - * not support the request id and their rild doesn't return an error. - */ - iccGetCardLockRetryCount: function(options) { - if (!RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT) { - // Only the emulator supports this request. - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - switch (options.lockType) { - case GECKO_CARDLOCK_PIN: - case GECKO_CARDLOCK_PIN2: - case GECKO_CARDLOCK_PUK: - case GECKO_CARDLOCK_PUK2: - case GECKO_CARDLOCK_NCK: - case GECKO_CARDLOCK_NSCK: - case GECKO_CARDLOCK_CCK: // Fall through. - case GECKO_CARDLOCK_SPCK: - // TODO: Bug 1116072: identify the mapping between RIL_PERSOSUBSTATE_SIM_SIM - // @ ril.h and TS 27.007, clause 8.65 for GECKO_CARDLOCK_SPCK. - options.selCode = GECKO_CARDLOCK_TO_SEL_CODE[options.lockType]; - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - this.queryICCLockRetryCount(options); - }, - - /** - * Query ICC lock retry count. - * - * @param selCode - * One of ICC_SEL_CODE_*. - * @param serviceClass - * One of ICC_SERVICE_CLASS_*. - */ - queryICCLockRetryCount: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_GET_UNLOCK_RETRY_COUNT, options); - Buf.writeInt32(1); - Buf.writeString(options.selCode); - Buf.sendParcel(); - }, - - /** - * Query ICC facility lock. - * - * @param facility - * One of ICC_CB_FACILITY_*. - * @param password - * Password for the facility, or "" if not required. - * @param serviceClass - * One of ICC_SERVICE_CLASS_*. - * @param [optional] aid - * AID value. - */ - queryICCFacilityLock: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_QUERY_FACILITY_LOCK, options); - Buf.writeInt32(4); - Buf.writeString(options.facility); - Buf.writeString(options.password); - Buf.writeString(options.serviceClass.toString()); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Set ICC facility lock. - * - * @param facility - * One of ICC_CB_FACILITY_*. - * @param enabled - * true to enable, false to disable. - * @param password - * Password for the facility, or "" if not required. - * @param serviceClass - * One of ICC_SERVICE_CLASS_*. - * @param [optional] aid - * AID value. - */ - setICCFacilityLock: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_FACILITY_LOCK, options); - Buf.writeInt32(5); - Buf.writeString(options.facility); - Buf.writeString(options.enabled ? "1" : "0"); - Buf.writeString(options.password); - Buf.writeString(options.serviceClass.toString()); - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Request an ICC I/O operation. - * - * See TS 27.007 "restricted SIM" operation, "AT Command +CRSM". - * The sequence is in the same order as how libril reads this parcel, - * see the struct RIL_SIM_IO_v5 or RIL_SIM_IO_v6 defined in ril.h - * - * @param command - * The I/O command, one of the ICC_COMMAND_* constants. - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param pathId - * String type, check the 'pathid' parameter from TS 27.007 +CRSM. - * @param p1, p2, p3 - * Arbitrary integer parameters for the command. - * @param [optional] dataWriter - * The function for writing string parameter for the ICC_COMMAND_UPDATE_RECORD. - * @param [optional] pin2 - * String containing the PIN2. - * @param [optional] aid - * AID value. - */ - iccIO: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_IO, options); - Buf.writeInt32(options.command); - Buf.writeInt32(options.fileId); - Buf.writeString(options.pathId); - Buf.writeInt32(options.p1); - Buf.writeInt32(options.p2); - Buf.writeInt32(options.p3); - - // Write data. - if (options.command == ICC_COMMAND_UPDATE_RECORD && - options.dataWriter) { - options.dataWriter(options.p3); - } else { - Buf.writeString(null); - } - - // Write pin2. - if (options.command == ICC_COMMAND_UPDATE_RECORD && - options.pin2) { - Buf.writeString(options.pin2); - } else { - Buf.writeString(null); - } - - Buf.writeString(options.aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Get IMSI. - * - * @param [optional] aid - * AID value. - */ - getIMSI: function(aid) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_GET_IMSI); - Buf.writeInt32(1); - Buf.writeString(aid || this.aid); - Buf.sendParcel(); - }, - - /** - * Retrieve ICC's GID1 field. - */ - getGID1: function(options) { - options.gid1 = this.iccInfoPrivate.gid1; - this.sendChromeMessage(options); - }, - - /** - * Read UICC Phonebook contacts. - * - * @param contactType - * One of GECKO_CARDCONTACT_TYPE_*. - * @param requestId - * Request id from RadioInterfaceLayer. - */ - readICCContacts: function(options) { - if (!this.appType) { - options.errorMsg = CONTACT_ERR_REQUEST_NOT_SUPPORTED; - this.sendChromeMessage(options); - return; - } - - this.context.ICCContactHelper.readICCContacts( - this.appType, - options.contactType, - function onsuccess(contacts) { - for (let i = 0; i < contacts.length; i++) { - let contact = contacts[i]; - let pbrIndex = contact.pbrIndex || 0; - let recordIndex = pbrIndex * ICC_MAX_LINEAR_FIXED_RECORDS + contact.recordId; - contact.contactId = this.iccInfo.iccid + recordIndex; - } - // Reuse 'options' to get 'requestId' and 'contactType'. - options.contacts = contacts; - this.sendChromeMessage(options); - }.bind(this), - function onerror(errorMsg) { - options.errorMsg = errorMsg; - this.sendChromeMessage(options); - }.bind(this)); - }, - - /** - * Update UICC Phonebook. - * - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param contact The contact will be updated. - * @param pin2 PIN2 is required for updating FDN. - * @param requestId Request id from RadioInterfaceLayer. - */ - updateICCContact: function(options) { - let onsuccess = function onsuccess(updatedContact) { - let recordIndex = - updatedContact.pbrIndex * ICC_MAX_LINEAR_FIXED_RECORDS + updatedContact.recordId; - updatedContact.contactId = this.iccInfo.iccid + recordIndex; - options.contact = updatedContact; - // Reuse 'options' to get 'requestId' and 'contactType'. - this.sendChromeMessage(options); - }.bind(this); - - let onerror = function onerror(errorMsg) { - options.errorMsg = errorMsg; - this.sendChromeMessage(options); - }.bind(this); - - if (!this.appType || !options.contact) { - onerror(CONTACT_ERR_REQUEST_NOT_SUPPORTED ); - return; - } - - let contact = options.contact; - let iccid = this.iccInfo.iccid; - let isValidRecordId = false; - if (typeof contact.contactId === "string" && - contact.contactId.startsWith(iccid)) { - let recordIndex = contact.contactId.substring(iccid.length); - contact.pbrIndex = Math.floor(recordIndex / ICC_MAX_LINEAR_FIXED_RECORDS); - contact.recordId = recordIndex % ICC_MAX_LINEAR_FIXED_RECORDS; - isValidRecordId = contact.recordId > 0 && contact.recordId < 0xff; - } - - if (DEBUG) { - this.context.debug("Update ICC Contact " + JSON.stringify(contact)); - } - - let ICCContactHelper = this.context.ICCContactHelper; - // If contact has 'recordId' property, updates corresponding record. - // If not, inserts the contact into a free record. - if (isValidRecordId) { - ICCContactHelper.updateICCContact( - this.appType, options.contactType, contact, options.pin2, onsuccess, onerror); - } else { - ICCContactHelper.addICCContact( - this.appType, options.contactType, contact, options.pin2, onsuccess, onerror); - } - }, - - /** - * Check if operator name needs to be overriden by current voiceRegistrationState - * , EFOPL and EFPNN. See 3GPP TS 31.102 clause 4.2.58 EFPNN and 4.2.59 EFOPL - * for detail. - * - * @return true if operator name is overridden, false otherwise. - */ - overrideICCNetworkName: function() { - if (!this.operator) { - return false; - } - - // We won't get network name using PNN and OPL if voice registration isn't - // ready. - if (!this.voiceRegistrationState.cell || - this.voiceRegistrationState.cell.gsmLocationAreaCode == -1) { - return false; - } - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let networkName = ICCUtilsHelper.getNetworkNameFromICC( - this.operator.mcc, - this.operator.mnc, - this.voiceRegistrationState.cell.gsmLocationAreaCode); - - if (!networkName) { - return false; - } - - if (DEBUG) { - this.context.debug("Operator names will be overriden: " + - "longName = " + networkName.fullName + ", " + - "shortName = " + networkName.shortName); - } - - this.operator.longName = networkName.fullName; - this.operator.shortName = networkName.shortName; - - this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator); - return true; - }, - - /** - * Request the phone's radio to be enabled or disabled. - * - * @param enabled - * Boolean indicating the desired state. - */ - setRadioEnabled: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_RADIO_POWER, options); - Buf.writeInt32(1); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Query call waiting status. - * - */ - queryCallWaiting: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_QUERY_CALL_WAITING, options); - Buf.writeInt32(1); - // As per 3GPP TS 24.083, section 1.6 UE doesn't need to send service - // class parameter in call waiting interrogation to network. - Buf.writeInt32(ICC_SERVICE_CLASS_NONE); - Buf.sendParcel(); - }, - - /** - * Set call waiting status. - * - * @param enabled - * Boolean indicating the desired waiting status. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - */ - setCallWaiting: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_CALL_WAITING, options); - Buf.writeInt32(2); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.writeInt32(options.serviceClass); - Buf.sendParcel(); - }, - - /** - * Queries current CLIP status. - */ - queryCLIP: function(options) { - this.context.Buf.simpleRequest(REQUEST_QUERY_CLIP, options); - }, - - /** - * Queries current CLIR status. - * - */ - getCLIR: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_CLIR, options); - }, - - /** - * Enables or disables the presentation of the calling line identity (CLI) to - * the called party when originating a call. - * - * @param options.clirMode - * One of the CLIR_* constants. - */ - setCLIR: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_CLIR, options); - Buf.writeInt32(1); - Buf.writeInt32(options.clirMode); - Buf.sendParcel(); - }, - - /** - * Set screen state. - * - * @param on - * Boolean indicating whether the screen should be on or off. - */ - setScreenState: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SCREEN_STATE); - Buf.writeInt32(1); - Buf.writeInt32(options.on ? 1 : 0); - Buf.sendParcel(); - }, - - getVoiceRegistrationState: function() { - this.context.Buf.simpleRequest(REQUEST_VOICE_REGISTRATION_STATE); - }, - - getVoiceRadioTechnology: function() { - this.context.Buf.simpleRequest(REQUEST_VOICE_RADIO_TECH); - }, - - getDataRegistrationState: function() { - this.context.Buf.simpleRequest(REQUEST_DATA_REGISTRATION_STATE); - }, - - getOperator: function() { - this.context.Buf.simpleRequest(REQUEST_OPERATOR); - }, - - /** - * Set the preferred network type. - * - * @param options An object contains a valid value of - * RIL_PREFERRED_NETWORK_TYPE_TO_GECKO as its `type` attribute. - */ - setPreferredNetworkType: function(options) { - let networkType = options.type; - if (networkType < 0 || networkType >= RIL_PREFERRED_NETWORK_TYPE_TO_GECKO.length) { - options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_PREFERRED_NETWORK_TYPE, options); - Buf.writeInt32(1); - Buf.writeInt32(networkType); - Buf.sendParcel(); - }, - - /** - * Get the preferred network type. - */ - getPreferredNetworkType: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_PREFERRED_NETWORK_TYPE, options); - }, - - /** - * Request neighboring cell ids in GSM network. - */ - getNeighboringCellIds: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_NEIGHBORING_CELL_IDS, options); - }, - - /** - * Request all of the current cell information known to the radio. - */ - getCellInfoList: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_CELL_INFO_LIST, options); - }, - - /** - * Request various states about the network. - */ - requestNetworkInfo: function() { - if (this._processingNetworkInfo) { - if (DEBUG) { - this.context.debug("Network info requested, but we're already " + - "requesting network info."); - } - this._needRepollNetworkInfo = true; - return; - } - - if (DEBUG) this.context.debug("Requesting network info"); - - this._processingNetworkInfo = true; - this.getVoiceRegistrationState(); - this.getDataRegistrationState(); //TODO only GSM - this.getOperator(); - this.getNetworkSelectionMode(); - this.getSignalStrength(); - }, - - /** - * Get the available networks - */ - getAvailableNetworks: function(options) { - if (DEBUG) this.context.debug("Getting available networks"); - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_QUERY_AVAILABLE_NETWORKS, options); - Buf.sendParcel(); - }, - - /** - * Request the radio's network selection mode - */ - getNetworkSelectionMode: function() { - if (DEBUG) this.context.debug("Getting network selection mode"); - this.context.Buf.simpleRequest(REQUEST_QUERY_NETWORK_SELECTION_MODE); - }, - - /** - * Tell the radio to automatically choose a voice/data network - */ - selectNetworkAuto: function(options) { - if (DEBUG) this.context.debug("Setting automatic network selection"); - this.context.Buf.simpleRequest(REQUEST_SET_NETWORK_SELECTION_AUTOMATIC, options); - }, - - /** - * Set the roaming preference mode - */ - setRoamingPreference: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CDMA_SET_ROAMING_PREFERENCE, options); - Buf.writeInt32(1); - Buf.writeInt32(options.mode); - Buf.sendParcel(); - }, - - /** - * Get the roaming preference mode - */ - queryRoamingPreference: function(options) { - this.context.Buf.simpleRequest(REQUEST_CDMA_QUERY_ROAMING_PREFERENCE, options); - }, - - /** - * Set the voice privacy mode - */ - setVoicePrivacyMode: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE, options); - Buf.writeInt32(1); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Get the voice privacy mode - */ - queryVoicePrivacyMode: function(options) { - this.context.Buf.simpleRequest(REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE, options); - }, - - /** - * Open Logical UICC channel (aid) for Secure Element access - */ - iccOpenChannel: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_OPEN_CHANNEL, options); - Buf.writeString(options.aid); - Buf.sendParcel(); - }, - - /** - * Exchange APDU data on an open Logical UICC channel - */ - iccExchangeAPDU: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_TRANSMIT_APDU_CHANNEL, options); - Buf.writeInt32(options.channel); - Buf.writeInt32(options.apdu.cla); - Buf.writeInt32(options.apdu.command); - Buf.writeInt32(options.apdu.p1); - Buf.writeInt32(options.apdu.p2); - Buf.writeInt32(options.apdu.p3); - Buf.writeString(options.apdu.data); - Buf.sendParcel(); - }, - - /** - * Close Logical UICC channel - */ - iccCloseChannel: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SIM_CLOSE_CHANNEL, options); - Buf.writeInt32(1); - Buf.writeInt32(options.channel); - Buf.sendParcel(); - }, - - /** - * Get UICC service state - */ - getIccServiceState: function(options) { - switch (options.service) { - case GECKO_CARDSERVICE_FDN: - let ICCUtilsHelper = this.context.ICCUtilsHelper; - options.result = ICCUtilsHelper.isICCServiceAvailable("FDN"); - break; - default: - options.errorMsg = GECKO_ERROR_REQUEST_NOT_SUPPORTED; - break; - } - this.sendChromeMessage(options); - }, - - /** - * Enable/Disable UICC subscription - */ - setUiccSubscription: function(options) { - if (DEBUG) { - this.context.debug("setUiccSubscription: " + JSON.stringify(options)); - } - - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_UICC_SUBSCRIPTION, options); - Buf.writeInt32(this.context.clientId); - Buf.writeInt32(options.appIndex); - Buf.writeInt32(this.context.clientId); - Buf.writeInt32(options.enabled ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Tell the radio to choose a specific voice/data network - */ - selectNetwork: function(options) { - if (DEBUG) { - this.context.debug("Setting manual network selection: " + - options.mcc + ", " + options.mnc); - } - - let numeric = (options.mcc && options.mnc) ? options.mcc + options.mnc : null; - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_NETWORK_SELECTION_MANUAL, options); - Buf.writeString(numeric); - Buf.sendParcel(); - }, - - /** - * Get the signal strength. - */ - getSignalStrength: function() { - this.context.Buf.simpleRequest(REQUEST_SIGNAL_STRENGTH); - }, - - getDeviceIdentity: function() { - this.deviceIdentities || this.context.Buf.simpleRequest(REQUEST_DEVICE_IDENTITY); - }, - - getBasebandVersion: function() { - this.context.Buf.simpleRequest(REQUEST_BASEBAND_VERSION); - }, - - sendExitEmergencyCbModeRequest: function(options) { - this.context.Buf.simpleRequest(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE, options); - }, - - getCdmaSubscription: function() { - this.context.Buf.simpleRequest(REQUEST_CDMA_SUBSCRIPTION); - }, - - exitEmergencyCbMode: function(options) { - // The function could be called by an API from RadioInterfaceLayer or by - // ril_worker itself. From ril_worker, we won't pass the parameter - // 'options'. In this case, it is marked as internal. - if (!options) { - options = {internal: true}; - } - this._cancelEmergencyCbModeTimeout(); - this.sendExitEmergencyCbModeRequest(options); - }, - - /** - * Dial a non-emergency number. - * - * @param isEmergency - * Whether the number is an emergency number. - * @param number - * String containing the number to dial. - * @param clirMode - * Integer for showing/hidding the caller Id to the called party. - * @param uusInfo - * Integer doing something XXX TODO - */ - dial: function(options) { - if (options.isEmergency) { - options.request = RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL ? - REQUEST_DIAL_EMERGENCY_CALL : REQUEST_DIAL; - - } else { - options.request = REQUEST_DIAL; - - // Exit emergency callback mode when user dial a non-emergency call. - if (this._isInEmergencyCbMode) { - this.exitEmergencyCbMode(); - } - } - - this.telephonyRequestQueue.push(options.request, () => { - let Buf = this.context.Buf; - Buf.newParcel(options.request, options); - Buf.writeString(options.number); - Buf.writeInt32(options.clirMode || 0); - Buf.writeInt32(options.uusInfo || 0); - // TODO Why do we need this extra 0? It was put it in to make this - // match the format of the binary message. - Buf.writeInt32(0); - Buf.sendParcel(); - }); - }, - - /** - * CDMA flash. - * - * @param featureStr (optional) - * Dialing number when the command is used for three-way-calling - */ - cdmaFlash: function(options) { - let Buf = this.context.Buf; - options.request = REQUEST_CDMA_FLASH; - Buf.newParcel(options.request, options); - Buf.writeString(options.featureStr || ""); - Buf.sendParcel(); - }, - - /** - * Hang up the phone. - * - * @param callIndex - * Call index (1-based) as reported by REQUEST_GET_CURRENT_CALLS. - */ - hangUpCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_HANGUP, () => { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_HANGUP, options); - Buf.writeInt32(1); - Buf.writeInt32(options.callIndex); - Buf.sendParcel(); - }); - }, - - hangUpForeground: function(options) { - this.telephonyRequestQueue.push(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, () => { - this.context.Buf.simpleRequest(REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, - options); - }); - }, - - hangUpBackground: function(options) { - this.telephonyRequestQueue.push(REQUEST_HANGUP_WAITING_OR_BACKGROUND, () => { - this.context.Buf.simpleRequest(REQUEST_HANGUP_WAITING_OR_BACKGROUND, - options); - }); - }, - - switchActiveCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, () => { - this.context.Buf.simpleRequest(REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, - options); - }); - }, - - udub: function(options) { - this.telephonyRequestQueue.push(REQUEST_UDUB, () => { - this.context.Buf.simpleRequest(REQUEST_UDUB, options); - }); - }, - - answerCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_ANSWER, () => { - this.context.Buf.simpleRequest(REQUEST_ANSWER, options); - }); - }, - - conferenceCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_CONFERENCE, () => { - this.context.Buf.simpleRequest(REQUEST_CONFERENCE, options); - }); - }, - - separateCall: function(options) { - this.telephonyRequestQueue.push(REQUEST_SEPARATE_CONNECTION, () => { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SEPARATE_CONNECTION, options); - Buf.writeInt32(1); - Buf.writeInt32(options.callIndex); - Buf.sendParcel(); - }); - }, - - /** - * Get current calls. - */ - getCurrentCalls: function(options) { - this.telephonyRequestQueue.push(REQUEST_GET_CURRENT_CALLS, () => { - this.context.Buf.simpleRequest(REQUEST_GET_CURRENT_CALLS, options); - }); - }, - - /** - * Mute or unmute the radio. - * - * @param mute - * Boolean to indicate whether to mute or unmute the radio. - */ - setMute: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_MUTE); - Buf.writeInt32(1); - Buf.writeInt32(options.muted ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Send an SMS. - * - * The `options` parameter object should contain the following attributes: - * - * @param number - * String containing the recipient number. - * @param body - * String containing the message text. - * @param envelopeId - * Numeric value identifying the sms request. - */ - sendSMS: function(options) { - options.langIndex = options.langIndex || PDU_NL_IDENTIFIER_DEFAULT; - options.langShiftIndex = options.langShiftIndex || PDU_NL_IDENTIFIER_DEFAULT; - - if (!options.segmentSeq) { - // Fist segment to send - options.segmentSeq = 1; - options.body = options.segments[0].body; - options.encodedBodyLength = options.segments[0].encodedBodyLength; - } - - let Buf = this.context.Buf; - if (this._isCdma) { - Buf.newParcel(REQUEST_CDMA_SEND_SMS, options); - this.context.CdmaPDUHelper.writeMessage(options); - } else { - Buf.newParcel(REQUEST_SEND_SMS, options); - Buf.writeInt32(2); - Buf.writeString(options.SMSC); - this.context.GsmPDUHelper.writeMessage(options); - } - Buf.sendParcel(); - }, - - /** - * Acknowledge the receipt and handling of an SMS. - * - * @param success - * Boolean indicating whether the message was successfuly handled. - * @param cause - * SMS_* constant indicating the reason for unsuccessful handling. - */ - acknowledgeGsmSms: function(success, cause) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SMS_ACKNOWLEDGE); - Buf.writeInt32(2); - Buf.writeInt32(success ? 1 : 0); - Buf.writeInt32(cause); - Buf.sendParcel(); - }, - - /** - * Acknowledge the receipt and handling of an SMS. - * - * @param success - * Boolean indicating whether the message was successfuly handled. - */ - ackSMS: function(options) { - if (options.result == PDU_FCS_RESERVED) { - return; - } - if (this._isCdma) { - this.acknowledgeCdmaSms(options.result == PDU_FCS_OK, options.result); - } else { - this.acknowledgeGsmSms(options.result == PDU_FCS_OK, options.result); - } - }, - - /** - * Acknowledge the receipt and handling of a CDMA SMS. - * - * @param success - * Boolean indicating whether the message was successfuly handled. - * @param cause - * SMS_* constant indicating the reason for unsuccessful handling. - */ - acknowledgeCdmaSms: function(success, cause) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CDMA_SMS_ACKNOWLEDGE); - Buf.writeInt32(success ? 0 : 1); - Buf.writeInt32(cause); - Buf.sendParcel(); - }, - - /** - * Update received MWI into EF_MWIS. - */ - updateMwis: function(options) { - if (this.context.ICCUtilsHelper.isICCServiceAvailable("MWIS")) { - this.context.SimRecordHelper.updateMWIS(options.mwi); - } - }, - - /** - * Report SMS storage status to modem. - */ - _updateSmsMemoryStatus: function() { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_REPORT_SMS_MEMORY_STATUS); - Buf.writeInt32(1); - Buf.writeInt32(this.smsStorageAvailable ? 1 : 0); - Buf.sendParcel(); - }, - - reportSmsMemoryStatus: function(options) { - this.pendingToReportSmsMemoryStatus = true; - this.smsStorageAvailable = options.isAvailable; - this._updateSmsMemoryStatus(); - }, - - setCellBroadcastDisabled: function(options) { - this.cellBroadcastDisabled = options.disabled; - - // If |this.mergedCellBroadcastConfig| is null, either we haven't finished - // reading required SIM files, or no any channel is ever configured. In - // the former case, we'll call |this.updateCellBroadcastConfig()| later - // with correct configs; in the latter case, we don't bother resetting CB - // to disabled again. - if (this.mergedCellBroadcastConfig) { - this.updateCellBroadcastConfig(); - } - }, - - setCellBroadcastSearchList: function(options) { - let getSearchListStr = function(aSearchList) { - if (typeof aSearchList === "string" || aSearchList instanceof String) { - return aSearchList; - } - - // TODO: Set search list for CDMA/GSM individually. Bug 990926 - let prop = this._isCdma ? "cdma" : "gsm"; - - return aSearchList && aSearchList[prop]; - }.bind(this); - - try { - let str = getSearchListStr(options.searchList); - this.cellBroadcastConfigs.MMI = this._convertCellBroadcastSearchList(str); - } catch (e) { - if (DEBUG) { - this.context.debug("Invalid Cell Broadcast search list: " + e); - } - options.errorMsg = GECKO_ERROR_UNSPECIFIED_ERROR; - } - - this.sendChromeMessage(options); - if (options.errorMsg) { - return; - } - - this._mergeAllCellBroadcastConfigs(); - }, - - updateCellBroadcastConfig: function() { - let activate = !this.cellBroadcastDisabled && - (this.mergedCellBroadcastConfig != null) && - (this.mergedCellBroadcastConfig.length > 0); - if (activate) { - this.setSmsBroadcastConfig(this.mergedCellBroadcastConfig); - } else { - // It's unnecessary to set config first if we're deactivating. - this.setSmsBroadcastActivation(false); - } - }, - - setGsmSmsBroadcastConfig: function(config) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_GSM_SET_BROADCAST_SMS_CONFIG); - - let numConfigs = config ? config.length / 2 : 0; - Buf.writeInt32(numConfigs); - for (let i = 0; i < config.length;) { - // convert [from, to) to [from, to - 1] - Buf.writeInt32(config[i++]); - Buf.writeInt32(config[i++] - 1); - Buf.writeInt32(0x00); - Buf.writeInt32(0xFF); - Buf.writeInt32(1); - } - - Buf.sendParcel(); - }, - - /** - * Send CDMA SMS broadcast config. - * - * @see 3GPP2 C.R1001 Sec. 9.2 and 9.3 - */ - setCdmaSmsBroadcastConfig: function(config) { - let Buf = this.context.Buf; - // |config| is an array of half-closed range: [[from, to), [from, to), ...]. - // It will be further decomposed, ex: [1, 4) => 1, 2, 3. - Buf.newParcel(REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG); - - let numConfigs = 0; - for (let i = 0; i < config.length; i += 2) { - numConfigs += (config[i+1] - config[i]); - } - - Buf.writeInt32(numConfigs); - for (let i = 0; i < config.length;) { - let begin = config[i++]; - let end = config[i++]; - - for (let j = begin; j < end; ++j) { - Buf.writeInt32(j); - Buf.writeInt32(0); // Language Indicator: Unknown or unspecified. - Buf.writeInt32(1); - } - } - - Buf.sendParcel(); - }, - - setSmsBroadcastConfig: function(config) { - if (this._isCdma) { - this.setCdmaSmsBroadcastConfig(config); - } else { - this.setGsmSmsBroadcastConfig(config); - } - }, - - setSmsBroadcastActivation: function(activate) { - let parcelType = this._isCdma ? REQUEST_CDMA_SMS_BROADCAST_ACTIVATION : - REQUEST_GSM_SMS_BROADCAST_ACTIVATION; - let Buf = this.context.Buf; - Buf.newParcel(parcelType); - Buf.writeInt32(1); - // See hardware/ril/include/telephony/ril.h, 0 - Activate, 1 - Turn off. - Buf.writeInt32(activate ? 0 : 1); - Buf.sendParcel(); - }, - - /** - * Start a DTMF Tone. - * - * @param dtmfChar - * DTMF signal to send, 0-9, *, + - */ - startTone: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_DTMF_START, options); - Buf.writeString(options.dtmfChar); - Buf.sendParcel(); - }, - - stopTone: function() { - this.context.Buf.simpleRequest(REQUEST_DTMF_STOP); - }, - - /** - * Send a DTMF tone. - * - * @param dtmfChar - * DTMF signal to send, 0-9, *, + - */ - sendTone: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_DTMF); - Buf.writeString(options.dtmfChar); - Buf.sendParcel(); - }, - - /** - * Get the Short Message Service Center address. - */ - getSmscAddress: function(options) { - this.context.Buf.simpleRequest(REQUEST_GET_SMSC_ADDRESS, options); - }, - - /** - * Set the Short Message Service Center address. - * - * @param smscAddress - * Number part of the SMSC address. - * @param typeOfNumber - * Type of number in integer, as defined in - * |Table 10.5.118: Called party BCD number| of 3GPP TS 24.008. - * @param numberPlanIdentification - * The index of number plan identification value in - * CALLED_PARTY_BCD_NPI array. - */ - setSmscAddress: function(options) { - let ton = options.typeOfNumber; - let npi = CALLED_PARTY_BCD_NPI[options.numberPlanIdentification]; - - // If any of the mandatory arguments is not available, return an error - // immediately. - if (ton === undefined || npi === undefined || !options.smscAddress) { - options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; - this.sendChromeMessage(options); - return; - } - - // Remove all illegal characters in the number string for user-input fault - // tolerance. - let numStart = options.smscAddress[0] === "+" ? 1 : 0; - let number = options.smscAddress.substring(0, numStart) + - options.smscAddress.substring(numStart) - .replace(/[^0-9*#abc]/ig, ""); - - // If the filtered number is an empty string, return an error immediately. - if (number.length === 0) { - options.errorMsg = GECKO_ERROR_INVALID_PARAMETER; - this.sendChromeMessage(options); - return; - } - - // Init parcel. - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_SMSC_ADDRESS, options); - - // +---+-----------+---------------+ - // | 1 | TON | NPI | - // +---+-----------+---------------+ - let tosca = (0x1 << 7) + (ton << 4) + npi; - if (RILQUIRKS_SMSC_ADDRESS_FORMAT === "pdu") { - let pduHelper = this.context.GsmPDUHelper; - - // Remove the preceding '+', and covert the special BCD digits defined in - // |Called party BCD number| of 3GPP TS 24.008 to corresponding - // hexadecimal values (refer the following table). - // - // +=========+=======+=====+ - // | value | digit | hex | - // +======================== - // | 1 0 1 0 | * | 0xA | - // | 1 0 1 1 | # | 0xB | - // | 1 1 0 0 | a | 0xC | - // | 1 1 0 1 | b | 0xD | - // | 1 1 1 0 | c | 0xE | - // +=========+=======+=====+ - // - // The replace order is reversed intentionally, because if the digits are - // replaced in ascending order, "#" will be converted to "b" and then be - // converted again to "d", which generates incorrect result. - let pureNumber = number.substring(numStart) - .replace(/c/ig, "e") - .replace(/b/ig, "d") - .replace(/a/ig, "c") - .replace(/\#/g, "b") - .replace(/\*/g, "a"); - - // address length and string length - let length = Math.ceil(pureNumber.length / 2) + 1; // +1 octet for TOA - let strlen = length * 2 + 2; // +2 semi-octets for length octet - - Buf.writeInt32(strlen); - pduHelper.writeHexOctet(length); - pduHelper.writeHexOctet(tosca); - pduHelper.writeSwappedNibbleBCD(pureNumber); - Buf.writeStringDelimiter(strlen); - } else /* RILQUIRKS_SMSC_ADDRESS_FORMAT === "text" */ { - let sca; - sca = '"' + number + '"' + ',' + tosca; - Buf.writeString(sca); - } - - Buf.sendParcel(); - }, - - /** - * Setup a data call. - * - * @param radioTech - * Integer to indicate radio technology. - * DATACALL_RADIOTECHNOLOGY_CDMA => CDMA. - * DATACALL_RADIOTECHNOLOGY_GSM => GSM. - * @param apn - * String containing the name of the APN to connect to. - * @param user - * String containing the username for the APN. - * @param passwd - * String containing the password for the APN. - * @param chappap - * Integer containing CHAP/PAP auth type. - * DATACALL_AUTH_NONE => PAP and CHAP is never performed. - * DATACALL_AUTH_PAP => PAP may be performed. - * DATACALL_AUTH_CHAP => CHAP may be performed. - * DATACALL_AUTH_PAP_OR_CHAP => PAP / CHAP may be performed. - * @param pdptype - * String containing PDP type to request. ("IP", "IPV6", ...) - */ - setupDataCall: function(options) { - // From ./hardware/ril/include/telephony/ril.h: - // ((const char **)data)[0] Radio technology to use: 0-CDMA, 1-GSM/UMTS, 2... - // for values above 2 this is RIL_RadioTechnology + 2. - // - // From frameworks/base/telephony/java/com/android/internal/telephony/DataConnection.java: - // if the mRilVersion < 6, radio technology must be GSM/UMTS or CDMA. - // Otherwise, it must be + 2 - // - // See also bug 901232 and 867873 - let radioTech = options.radioTech + 2; - let Buf = this.context.Buf; - let token = Buf.newParcel(REQUEST_SETUP_DATA_CALL, options); - Buf.writeInt32(7); - Buf.writeString(radioTech.toString()); - Buf.writeString(DATACALL_PROFILE_DEFAULT.toString()); - Buf.writeString(options.apn); - Buf.writeString(options.user); - Buf.writeString(options.passwd); - Buf.writeString(options.chappap.toString()); - Buf.writeString(options.pdptype); - Buf.sendParcel(); - return token; - }, - - /** - * Deactivate a data call. - * - * @param cid - * String containing CID. - * @param reason - * One of DATACALL_DEACTIVATE_* constants. - */ - deactivateDataCall: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_DEACTIVATE_DATA_CALL, options); - Buf.writeInt32(2); - Buf.writeString(options.cid.toString()); - Buf.writeString(options.reason !== undefined ? - options.reason.toString() : - DATACALL_DEACTIVATE_NO_REASON.toString()); - Buf.sendParcel(); - }, - - /** - * Get a list of data calls. - */ - getDataCallList: function(options) { - this.context.Buf.simpleRequest(REQUEST_DATA_CALL_LIST, options); - }, - - _attachDataRegistration: false, - /** - * Manually attach/detach data registration. - * - * @param attach - * Boolean value indicating attach or detach. - */ - setDataRegistration: function(options) { - this._attachDataRegistration = options.attach; - - if (RILQUIRKS_DATA_REGISTRATION_ON_DEMAND) { - let request = options.attach ? RIL_REQUEST_GPRS_ATTACH : - RIL_REQUEST_GPRS_DETACH; - this.context.Buf.simpleRequest(request, options); - return; - } else if (RILQUIRKS_SUBSCRIPTION_CONTROL && options.attach) { - this.context.Buf.simpleRequest(REQUEST_SET_DATA_SUBSCRIPTION, options); - return; - } - - // We don't really send a request to rild, so instantly reply success to - // RadioInterfaceLayer. - this.sendChromeMessage(options); - }, - - /** - * Get failure casue code for the most recently failed PDP context. - */ - getFailCause: function(options) { - this.context.Buf.simpleRequest(REQUEST_LAST_CALL_FAIL_CAUSE, options); - }, - - /** - * Send USSD. - * - * @param ussd - * String containing the USSD code. - */ - sendUSSD: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SEND_USSD, options); - Buf.writeString(options.ussd); - Buf.sendParcel(); - }, - - /** - * Cancel pending USSD. - */ - cancelUSSD: function(options) { - this.context.Buf.simpleRequest(REQUEST_CANCEL_USSD, options); - }, - - /** - * Queries current call forward rules. - * - * @param reason - * One of CALL_FORWARD_REASON_* constants. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - * @param number - * Phone number of forwarding address. - */ - queryCallForwardStatus: function(options) { - let Buf = this.context.Buf; - let number = options.number || ""; - Buf.newParcel(REQUEST_QUERY_CALL_FORWARD_STATUS, options); - Buf.writeInt32(CALL_FORWARD_ACTION_QUERY_STATUS); - Buf.writeInt32(options.reason); - Buf.writeInt32(options.serviceClass || ICC_SERVICE_CLASS_NONE); - Buf.writeInt32(this._toaFromString(number)); - Buf.writeString(number); - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Configures call forward rule. - * - * @param action - * One of CALL_FORWARD_ACTION_* constants. - * @param reason - * One of CALL_FORWARD_REASON_* constants. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - * @param number - * Phone number of forwarding address. - * @param timeSeconds - * Time in seconds to wait beforec all is forwarded. - */ - setCallForward: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_SET_CALL_FORWARD, options); - Buf.writeInt32(options.action); - Buf.writeInt32(options.reason); - Buf.writeInt32(options.serviceClass); - Buf.writeInt32(this._toaFromString(options.number)); - Buf.writeString(options.number); - Buf.writeInt32(options.timeSeconds); - Buf.sendParcel(); - }, - - /** - * Queries current call barring rules. - * - * @param program - * One of CALL_BARRING_PROGRAM_* constants. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - */ - queryCallBarringStatus: function(options) { - options.facility = CALL_BARRING_PROGRAM_TO_FACILITY[options.program]; - options.password = ""; // For query no need to provide it. - - // For some operators, querying specific serviceClass doesn't work. We use - // serviceClass 0 instead, and then process the response to extract the - // answer for queryServiceClass. - options.queryServiceClass = options.serviceClass; - options.serviceClass = 0; - - this.queryICCFacilityLock(options); - }, - - /** - * Configures call barring rule. - * - * @param program - * One of CALL_BARRING_PROGRAM_* constants. - * @param enabled - * Enable or disable the call barring. - * @param password - * Barring password. - * @param serviceClass - * One of ICC_SERVICE_CLASS_* constants. - */ - setCallBarring: function(options) { - options.facility = CALL_BARRING_PROGRAM_TO_FACILITY[options.program]; - this.setICCFacilityLock(options); - }, - - /** - * Change call barring facility password. - * - * @param pin - * Old password. - * @param newPin - * New password. - */ - changeCallBarringPassword: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_CHANGE_BARRING_PASSWORD, options); - Buf.writeInt32(3); - // Set facility to ICC_CB_FACILITY_BA_ALL by following TS.22.030 clause - // 6.5.4 and Table B.1. - Buf.writeString(ICC_CB_FACILITY_BA_ALL); - Buf.writeString(options.pin); - Buf.writeString(options.newPin); - Buf.sendParcel(); - }, - - /** - * Handle STK CALL_SET_UP request. - * - * @param hasConfirmed - * Does use have confirmed the call requested from ICC? - */ - stkHandleCallSetup: function(options) { - let Buf = this.context.Buf; - Buf.newParcel(REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM); - Buf.writeInt32(1); - Buf.writeInt32(options.hasConfirmed ? 1 : 0); - Buf.sendParcel(); - }, - - /** - * Send STK Profile Download. - * - * @param profile Profile supported by ME. - */ - sendStkTerminalProfile: function(profile) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_STK_SET_PROFILE); - Buf.writeInt32(profile.length * 2); - for (let i = 0; i < profile.length; i++) { - GsmPDUHelper.writeHexOctet(profile[i]); - } - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Send STK terminal response. - * - * @param command - * @param deviceIdentities - * @param resultCode - * @param [optional] additionalInformation - * @param [optional] itemIdentifier - * @param [optional] input - * @param [optional] isYesNo - * @param [optional] hasConfirmed - * @param [optional] localInfo - * @param [optional] timer - */ - sendStkTerminalResponse: function(response) { - if (response.hasConfirmed !== undefined) { - this.stkHandleCallSetup(response); - return; - } - - let Buf = this.context.Buf; - let ComprehensionTlvHelper = this.context.ComprehensionTlvHelper; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let command = response.command; - Buf.newParcel(REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // 1st mark for Parcel size - Buf.startCalOutgoingSize(function(size) { - // Parcel size is in string length, which costs 2 uint8 per char. - Buf.writeInt32(size / 2); - }); - - // Command Details - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(3); - if (command) { - GsmPDUHelper.writeHexOctet(command.commandNumber); - GsmPDUHelper.writeHexOctet(command.typeOfCommand); - GsmPDUHelper.writeHexOctet(command.commandQualifier); - } else { - GsmPDUHelper.writeHexOctet(0x00); - GsmPDUHelper.writeHexOctet(0x00); - GsmPDUHelper.writeHexOctet(0x00); - } - - // Device Identifier - // According to TS102.223/TS31.111 section 6.8 Structure of - // TERMINAL RESPONSE, "For all SIMPLE-TLV objects with Min=N, - // the ME should set the CR(comprehension required) flag to - // comprehension not required.(CR=0)" - // Since DEVICE_IDENTITIES and DURATION TLVs have Min=N, - // the CR flag is not set. - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DEVICE_ID); - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_ME); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_SIM); - - // Result - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - if ("additionalInformation" in response) { - // In |12.12 Result| TS 11.14, the length of additional information is - // varied and all possible values are addressed in 12.12.1-11 of TS 11.14 - // and 8.12.1-13 in TS 31.111. - // However, - // 1. Only SEND SS requires info with more than 1 octet. - // 2. In rild design, SEND SS is expected to be handled by modem and - // UNSOLICITED_STK_EVENT_NOTIFY will be sent to application layer to - // indicate appropriate messages to users. TR is not required in this - // case. - // Hence, we simplify the structure of |additionalInformation| to a - // numeric value instead of a octet array. - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(response.resultCode); - GsmPDUHelper.writeHexOctet(response.additionalInformation); - } else { - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(response.resultCode); - } - - // Item Identifier - if (response.itemIdentifier != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ITEM_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(response.itemIdentifier); - } - - // No need to process Text data if user requests help information. - if (response.resultCode != STK_RESULT_HELP_INFO_REQUIRED) { - let text; - let coding = command.options.isUCS2 ? - STK_TEXT_CODING_UCS2 : - (command.options.isPacked ? - STK_TEXT_CODING_GSM_7BIT_PACKED : - STK_TEXT_CODING_GSM_8BIT); - if (response.isYesNo !== undefined) { - // Tag: GET_INKEY - // When the ME issues a successful TERMINAL RESPONSE for a GET INKEY - // ("Yes/No") command with command qualifier set to "Yes/No", it shall - // supply the value '01' when the answer is "positive" and the value - // '00' when the answer is "negative" in the Text string data object. - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - // Length: 2 - GsmPDUHelper.writeHexOctet(2); - // Value: Coding, Yes/No. - GsmPDUHelper.writeHexOctet(coding); - GsmPDUHelper.writeHexOctet(response.isYesNo ? 0x01 : 0x00); - } else { - if (response.input !== undefined) { - ComprehensionTlvHelper.writeTextStringTlv(response.input, coding); - } - } - } - - // Duration - if (response.resultCode === STK_RESULT_NO_RESPONSE_FROM_USER) { - // In TS102 223, 6.4.2 GET INKEY, "if the UICC requests a variable timeout, - // the terminal shall wait until either the user enters a single character - // or the timeout expires. The timer starts when the text is displayed on - // the screen and stops when the TERMINAL RESPONSE is sent. The terminal - // shall pass the total display text duration (command execution duration) - // to the UICC using the TERMINAL RESPONSE. The time unit of the response - // is identical to the time unit of the requested variable timeout." - let duration = command && command.options && command.options.duration; - if (duration) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DURATION); - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(duration.timeUnit); - GsmPDUHelper.writeHexOctet(duration.timeInterval); - } - } - - // Local Information - if (response.localInfo) { - let localInfo = response.localInfo; - - // Location Infomation - if (localInfo.locationInfo) { - ComprehensionTlvHelper.writeLocationInfoTlv(localInfo.locationInfo); - } - - // IMEI - if (localInfo.imei != null) { - let imei = localInfo.imei; - if (imei.length == 15) { - imei = imei + "0"; - } - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_IMEI); - GsmPDUHelper.writeHexOctet(8); - for (let i = 0; i < imei.length / 2; i++) { - GsmPDUHelper.writeHexOctet(parseInt(imei.substr(i * 2, 2), 16)); - } - } - - // Date and Time Zone - if (localInfo.date != null) { - ComprehensionTlvHelper.writeDateTimeZoneTlv(localInfo.date); - } - - // Language - if (localInfo.language) { - ComprehensionTlvHelper.writeLanguageTlv(localInfo.language); - } - } - - // Timer - if (response.timer) { - let timer = response.timer; - - if (timer.timerId) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(timer.timerId); - } - - if (timer.timerValue) { - ComprehensionTlvHelper.writeTimerValueTlv(timer.timerValue, false); - } - } - - // Calculate and write Parcel size to 1st mark - Buf.stopCalOutgoingSize(); - - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Send STK Envelope(Menu Selection) command. - * - * @param itemIdentifier - * @param helpRequested - */ - sendStkMenuSelection: function(command) { - command.tag = BER_MENU_SELECTION_TAG; - command.deviceId = { - sourceId :STK_DEVICE_ID_KEYPAD, - destinationId: STK_DEVICE_ID_SIM - }; - this.sendICCEnvelopeCommand(command); - }, - - /** - * Send STK Envelope(Timer Expiration) command. - * - * @param timer - */ - sendStkTimerExpiration: function(command) { - command.tag = BER_TIMER_EXPIRATION_TAG; - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.timerId = command.timer.timerId; - command.timerValue = command.timer.timerValue; - this.sendICCEnvelopeCommand(command); - }, - - /** - * Send STK Envelope(Event Download) command. - * @param event - */ - sendStkEventDownload: function(command) { - command.tag = BER_EVENT_DOWNLOAD_TAG; - command.eventList = command.event.eventType; - switch (command.eventList) { - case STK_EVENT_TYPE_LOCATION_STATUS: - command.deviceId = { - sourceId :STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.locationStatus = command.event.locationStatus; - // Location info should only be provided when locationStatus is normal. - if (command.locationStatus == STK_SERVICE_STATE_NORMAL) { - command.locationInfo = command.event.locationInfo; - } - break; - case STK_EVENT_TYPE_MT_CALL: - command.deviceId = { - sourceId: STK_DEVICE_ID_NETWORK, - destinationId: STK_DEVICE_ID_SIM - }; - command.transactionId = 0; - command.address = command.event.number; - break; - case STK_EVENT_TYPE_CALL_DISCONNECTED: - command.cause = command.event.error; - // Fall through. - case STK_EVENT_TYPE_CALL_CONNECTED: - command.deviceId = { - sourceId: (command.event.isIssuedByRemote ? - STK_DEVICE_ID_NETWORK : STK_DEVICE_ID_ME), - destinationId: STK_DEVICE_ID_SIM - }; - command.transactionId = 0; - break; - case STK_EVENT_TYPE_USER_ACTIVITY: - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - break; - case STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE: - command.deviceId = { - sourceId: STK_DEVICE_ID_DISPLAY, - destinationId: STK_DEVICE_ID_SIM - }; - break; - case STK_EVENT_TYPE_LANGUAGE_SELECTION: - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.language = command.event.language; - break; - case STK_EVENT_TYPE_BROWSER_TERMINATION: - command.deviceId = { - sourceId: STK_DEVICE_ID_ME, - destinationId: STK_DEVICE_ID_SIM - }; - command.terminationCause = command.event.terminationCause; - break; - } - this.sendICCEnvelopeCommand(command); - }, - - /** - * Send REQUEST_STK_SEND_ENVELOPE_COMMAND to ICC. - * - * @param tag - * @patam deviceId - * @param [optioanl] itemIdentifier - * @param [optional] helpRequested - * @param [optional] eventList - * @param [optional] locationStatus - * @param [optional] locationInfo - * @param [optional] address - * @param [optional] transactionId - * @param [optional] cause - * @param [optional] timerId - * @param [optional] timerValue - * @param [optional] terminationCause - */ - sendICCEnvelopeCommand: function(options) { - if (DEBUG) { - this.context.debug("Stk Envelope " + JSON.stringify(options)); - } - - let Buf = this.context.Buf; - let ComprehensionTlvHelper = this.context.ComprehensionTlvHelper; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // 1st mark for Parcel size - Buf.startCalOutgoingSize(function(size) { - // Parcel size is in string length, which costs 2 uint8 per char. - Buf.writeInt32(size / 2); - }); - - // Write a BER-TLV - GsmPDUHelper.writeHexOctet(options.tag); - // 2nd mark for BER length - Buf.startCalOutgoingSize(function(size) { - // BER length is in number of hexOctets, which costs 4 uint8 per hexOctet. - GsmPDUHelper.writeHexOctet(size / 4); - }); - - // Event List - if (options.eventList != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.eventList); - } - - // Device Identifies - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(2); - GsmPDUHelper.writeHexOctet(options.deviceId.sourceId); - GsmPDUHelper.writeHexOctet(options.deviceId.destinationId); - - // Item Identifier - if (options.itemIdentifier != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ITEM_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.itemIdentifier); - } - - // Help Request - if (options.helpRequested) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_HELP_REQUEST | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(0); - // Help Request doesn't have value - } - - // Location Status - if (options.locationStatus != null) { - let len = options.locationStatus.length; - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_STATUS | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.locationStatus); - } - - // Location Info - if (options.locationInfo) { - ComprehensionTlvHelper.writeLocationInfoTlv(options.locationInfo); - } - - // Transaction Id - if (options.transactionId != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TRANSACTION_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.transactionId); - } - - // Address - if (options.address) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ADDRESS | - COMPREHENSIONTLV_FLAG_CR); - let addressLength = options.address[0] == '+' ? options.address.length - 1 - : options.address.length; - ComprehensionTlvHelper.writeLength( - Math.ceil(addressLength / 2) + 1 // address BCD + TON - ); - this.context.ICCPDUHelper.writeDiallingNumber(options.address); - } - - // Cause of disconnection. - if (options.cause != null) { - ComprehensionTlvHelper.writeCauseTlv(options.cause); - } - - // Timer Identifier - if (options.timerId != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.timerId); - } - - // Timer Value - if (options.timerValue != null) { - ComprehensionTlvHelper.writeTimerValueTlv(options.timerValue, true); - } - - // Language - if (options.language) { - ComprehensionTlvHelper.writeLanguageTlv(options.language); - } - - // Browser Termination - if (options.terminationCause != null) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(1); - GsmPDUHelper.writeHexOctet(options.terminationCause); - } - - // Calculate and write BER length to 2nd mark - Buf.stopCalOutgoingSize(); - - // Calculate and write Parcel size to 1st mark - Buf.stopCalOutgoingSize(); - - Buf.writeInt32(0); - Buf.sendParcel(); - }, - - /** - * Report STK Service is running. - */ - reportStkServiceIsRunning: function() { - this.context.Buf.simpleRequest(REQUEST_REPORT_STK_SERVICE_IS_RUNNING); - }, - - /** - * Process ICC status. - */ - _processICCStatus: function(iccStatus) { - // If |_waitingRadioTech| is true, we should not get app information because - // the |_isCdma| flag is not ready yet. Otherwise we may use wrong index to - // get app information, especially for the case that icc card has both cdma - // and gsm subscription. - if (this._waitingRadioTech) { - return; - } - - // When |iccStatus.cardState| is not CARD_STATE_PRESENT, set cardState to - // undetected. - if (iccStatus.cardState !== CARD_STATE_PRESENT) { - if (this.cardState !== GECKO_CARDSTATE_UNDETECTED) { - this.operator = null; - // We should send |cardstatechange| before |iccinfochange|, otherwise we - // may lost cardstatechange event when icc card becomes undetected. - this.cardState = GECKO_CARDSTATE_UNDETECTED; - this.sendChromeMessage({rilMessageType: "cardstatechange", - cardState: this.cardState}); - - this.iccInfo = {iccType: null}; - this.context.ICCUtilsHelper.handleICCInfoChange(); - } - return; - } - - if (RILQUIRKS_SUBSCRIPTION_CONTROL) { - // All appIndex is -1 means the subscription is not activated yet. - // Note that we don't support "ims" for now, so we don't take it into - // account. - let neetToActivate = iccStatus.cdmaSubscriptionAppIndex === -1 && - iccStatus.gsmUmtsSubscriptionAppIndex === -1; - if (neetToActivate && - // Note: setUiccSubscription works abnormally when RADIO is OFF, - // which causes SMS function broken in Flame. - // See bug 1008557 for detailed info. - this.radioState === GECKO_RADIOSTATE_ENABLED) { - for (let i = 0; i < iccStatus.apps.length; i++) { - this.setUiccSubscription({appIndex: i, enabled: true}); - } - } - } - - let newCardState; - let index = this._isCdma ? iccStatus.cdmaSubscriptionAppIndex - : iccStatus.gsmUmtsSubscriptionAppIndex; - let app = iccStatus.apps[index]; - if (app) { - // fetchICCRecords will need to read aid, so read aid here. - this.aid = app.aid; - this.appType = app.app_type; - this.iccInfo.iccType = GECKO_CARD_TYPE[this.appType]; - - switch (app.app_state) { - case CARD_APPSTATE_ILLEGAL: - newCardState = GECKO_CARDSTATE_ILLEGAL; - break; - case CARD_APPSTATE_PIN: - newCardState = GECKO_CARDSTATE_PIN_REQUIRED; - break; - case CARD_APPSTATE_PUK: - newCardState = GECKO_CARDSTATE_PUK_REQUIRED; - break; - case CARD_APPSTATE_SUBSCRIPTION_PERSO: - newCardState = PERSONSUBSTATE[app.perso_substate]; - break; - case CARD_APPSTATE_READY: - newCardState = GECKO_CARDSTATE_READY; - break; - case CARD_APPSTATE_UNKNOWN: - case CARD_APPSTATE_DETECTED: - // Fall through. - default: - newCardState = GECKO_CARDSTATE_UNKNOWN; - } - - let pin1State = app.pin1_replaced ? iccStatus.universalPINState : - app.pin1; - if (pin1State === CARD_PINSTATE_ENABLED_PERM_BLOCKED) { - newCardState = GECKO_CARDSTATE_PERMANENT_BLOCKED; - } - } else { - // Having incorrect app information, set card state to unknown. - newCardState = GECKO_CARDSTATE_UNKNOWN; - } - - let ICCRecordHelper = this.context.ICCRecordHelper; - // Try to get iccId only when cardState left GECKO_CARDSTATE_UNDETECTED. - if (iccStatus.cardState === CARD_STATE_PRESENT && - (this.cardState === GECKO_CARDSTATE_UNINITIALIZED || - this.cardState === GECKO_CARDSTATE_UNDETECTED)) { - ICCRecordHelper.readICCID(); - } - - if (this.cardState == newCardState) { - return; - } - - // This was moved down from CARD_APPSTATE_READY - this.requestNetworkInfo(); - if (newCardState == GECKO_CARDSTATE_READY) { - // For type SIM, we need to check EF_phase first. - // Other types of ICC we can send Terminal_Profile immediately. - if (this.appType == CARD_APPTYPE_SIM) { - this.context.SimRecordHelper.readSimPhase(); - } else if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD) { - this.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE); - } - - ICCRecordHelper.fetchICCRecords(); - } - - this.cardState = newCardState; - this.sendChromeMessage({rilMessageType: "cardstatechange", - cardState: this.cardState}); - }, - - /** - * Helper for processing responses of functions such as enterICC* and changeICC*. - */ - _processEnterAndChangeICCResponses: function(length, options) { - options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1; - this.sendChromeMessage(options); - }, - - // We combine all of the NETWORK_INFO_MESSAGE_TYPES into one "networkinfochange" - // message to the RadioInterfaceLayer, so we can avoid sending multiple - // VoiceInfoChanged events for both operator / voice_data_registration - // - // State management here is a little tricky. We need to know both: - // 1. Whether or not a response was received for each of the - // NETWORK_INFO_MESSAGE_TYPES - // 2. The outbound message that corresponds with that response -- but this - // only happens when internal state changes (i.e. it isn't guaranteed) - // - // To collect this state, each message response function first calls - // _receivedNetworkInfo, to mark the response as received. When the - // final response is received, a call to _sendPendingNetworkInfo is placed - // on the next tick of the worker thread. - // - // Since the original call to _receivedNetworkInfo happens at the top - // of the response handler, this gives the final handler a chance to - // queue up it's "changed" message by calling _sendNetworkInfoMessage if/when - // the internal state has actually changed. - _sendNetworkInfoMessage: function(type, message) { - if (!this._processingNetworkInfo) { - // We only combine these messages in the case of the combined request - // in requestNetworkInfo() - this.sendChromeMessage(message); - return; - } - - if (DEBUG) { - this.context.debug("Queuing " + type + " network info message: " + - JSON.stringify(message)); - } - this._pendingNetworkInfo[type] = message; - }, - - _receivedNetworkInfo: function(type) { - if (DEBUG) this.context.debug("Received " + type + " network info."); - if (!this._processingNetworkInfo) { - return; - } - - let pending = this._pendingNetworkInfo; - - // We still need to track states for events that aren't fired. - if (!(type in pending)) { - pending[type] = this.pendingNetworkType; - } - - // Pending network info is ready to be sent when no more messages - // are waiting for responses, but the combined payload hasn't been sent. - for (let i = 0; i < NETWORK_INFO_MESSAGE_TYPES.length; i++) { - let msgType = NETWORK_INFO_MESSAGE_TYPES[i]; - if (!(msgType in pending)) { - if (DEBUG) { - this.context.debug("Still missing some more network info, not " + - "notifying main thread."); - } - return; - } - } - - // Do a pass to clean up the processed messages that didn't create - // a response message, so we don't have unused keys in the outbound - // networkinfochanged message. - for (let key in pending) { - if (pending[key] == this.pendingNetworkType) { - delete pending[key]; - } - } - - if (DEBUG) { - this.context.debug("All pending network info has been received: " + - JSON.stringify(pending)); - } - - // Send the message on the next tick of the worker's loop, so we give the - // last message a chance to call _sendNetworkInfoMessage first. - setTimeout(this._sendPendingNetworkInfo.bind(this), 0); - }, - - _sendPendingNetworkInfo: function() { - this.sendChromeMessage(this._pendingNetworkInfo); - - this._processingNetworkInfo = false; - for (let i = 0; i < NETWORK_INFO_MESSAGE_TYPES.length; i++) { - delete this._pendingNetworkInfo[NETWORK_INFO_MESSAGE_TYPES[i]]; - } - - if (this._needRepollNetworkInfo) { - this._needRepollNetworkInfo = false; - this.requestNetworkInfo(); - } - }, - - /** - * Normalize the signal strength in dBm to the signal level from 0 to 100. - * - * @param signal - * The signal strength in dBm to normalize. - * @param min - * The signal strength in dBm maps to level 0. - * @param max - * The signal strength in dBm maps to level 100. - * - * @return level - * The signal level from 0 to 100. - */ - _processSignalLevel: function(signal, min, max) { - if (signal <= min) { - return 0; - } - - if (signal >= max) { - return 100; - } - - return Math.floor((signal - min) * 100 / (max - min)); - }, - - /** - * Process LTE signal strength to the signal info object. - * - * @param signal - * The signal object reported from RIL/modem. - * - * @return The object of signal strength info. - * Or null if invalid signal input. - * - * TODO: Bug 982013: reconsider the format of signal strength APIs for - * GSM/CDMA/LTE to expose details, such as rsrp and rsnnr, - * individually. - */ - _processLteSignal: function(signal) { - let info = { - voice: { - signalStrength: null, - relSignalStrength: null - }, - data: { - signalStrength: null, - relSignalStrength: null - } - }; - - // Referring to AOSP, use lteRSRP for signalStrength in dBm. - let signalStrength = (signal.lteRSRP === undefined || signal.lteRSRP === 0x7FFFFFFF) ? - null : signal.lteRSRP; - info.voice.signalStrength = info.data.signalStrength = signalStrength; - - // Referring to AOSP, first determine signalLevel based on RSRP and RSSNR, - // then on lteSignalStrength if RSRP and RSSNR are invalid. - let rsrpLevel = -1; - let rssnrLevel = -1; - if (signal.lteRSRP !== undefined && - signal.lteRSRP !== 0x7FFFFFFF && - signal.lteRSRP >= 44 && - signal.lteRSRP <= 140) { - rsrpLevel = this._processSignalLevel(signal.lteRSRP * -1, -115, -85); - } - - if (signal.lteRSSNR !== undefined && - signal.lteRSSNR !== 0x7FFFFFFF && - signal.lteRSSNR >= -200 && - signal.lteRSSNR <= 300) { - rssnrLevel = this._processSignalLevel(signal.lteRSSNR, -30, 130); - } - - if (rsrpLevel !== -1 && rssnrLevel !== -1) { - info.voice.relSignalStrength = info.data.relSignalStrength = - Math.min(rsrpLevel, rssnrLevel); - return info; - } - - let level = Math.max(rsrpLevel, rssnrLevel); - if (level !== -1) { - info.voice.relSignalStrength = info.data.relSignalStrength = level; - return info; - } - - // Valid values are 0-63 as defined in TS 27.007 clause 8.69. - if (signal.lteSignalStrength !== undefined && - signal.lteSignalStrength >= 0 && - signal.lteSignalStrength <= 63) { - level = this._processSignalLevel(signal.lteSignalStrength, 0, 12); - info.voice.relSignalStrength = info.data.relSignalStrength = level; - return info; - } - - return null; - }, - - _processSignalStrength: function(signal) { - let info = { - voice: { - signalStrength: null, - relSignalStrength: null - }, - data: { - signalStrength: null, - relSignalStrength: null - } - }; - - // During startup, |radioTech| is not yet defined, so we need to - // check it separately. - if (("radioTech" in this.voiceRegistrationState) && - !this._isGsmTechGroup(this.voiceRegistrationState.radioTech)) { - // CDMA RSSI. - // Valid values are positive integers. This value is the actual RSSI value - // multiplied by -1. Example: If the actual RSSI is -75, then this - // response value will be 75. - if (signal.cdmaDBM && signal.cdmaDBM > 0) { - let signalStrength = -1 * signal.cdmaDBM; - info.voice.signalStrength = signalStrength; - - // -105 and -70 are referred to AOSP's implementation. These values are - // not constants and can be customized based on different requirement. - let signalLevel = this._processSignalLevel(signalStrength, -105, -70); - info.voice.relSignalStrength = signalLevel; - } - - // EVDO RSSI. - // Valid values are positive integers. This value is the actual RSSI value - // multiplied by -1. Example: If the actual RSSI is -75, then this - // response value will be 75. - if (signal.evdoDBM && signal.evdoDBM > 0) { - let signalStrength = -1 * signal.evdoDBM; - info.data.signalStrength = signalStrength; - - // -105 and -70 are referred to AOSP's implementation. These values are - // not constants and can be customized based on different requirement. - let signalLevel = this._processSignalLevel(signalStrength, -105, -70); - info.data.relSignalStrength = signalLevel; - } - } else { - // Check LTE level first, and check GSM/UMTS level next if LTE one is not - // valid. - let lteInfo = this._processLteSignal(signal); - if (lteInfo) { - info = lteInfo; - } else { - // GSM signal strength. - // Valid values are 0-31 as defined in TS 27.007 8.5. - // 0 : -113 dBm or less - // 1 : -111 dBm - // 2...30: -109...-53 dBm - // 31 : -51 dBm - if (signal.gsmSignalStrength && - signal.gsmSignalStrength >= 0 && - signal.gsmSignalStrength <= 31) { - let signalStrength = -113 + 2 * signal.gsmSignalStrength; - info.voice.signalStrength = info.data.signalStrength = signalStrength; - - // -115 and -85 are referred to AOSP's implementation. These values are - // not constants and can be customized based on different requirement. - let signalLevel = this._processSignalLevel(signalStrength, -110, -85); - info.voice.relSignalStrength = info.data.relSignalStrength = signalLevel; - } - } - } - - info.rilMessageType = "signalstrengthchange"; - this._sendNetworkInfoMessage(NETWORK_INFO_SIGNAL, info); - }, - - /** - * Process the network registration flags. - * - * @return true if the state changed, false otherwise. - */ - _processCREG: function(curState, newState) { - let changed = false; - - let regState = this.parseInt(newState[0], NETWORK_CREG_STATE_UNKNOWN); - if (curState.regState === undefined || curState.regState !== regState) { - changed = true; - curState.regState = regState; - - curState.state = NETWORK_CREG_TO_GECKO_MOBILE_CONNECTION_STATE[regState]; - curState.connected = regState == NETWORK_CREG_STATE_REGISTERED_HOME || - regState == NETWORK_CREG_STATE_REGISTERED_ROAMING; - curState.roaming = regState == NETWORK_CREG_STATE_REGISTERED_ROAMING; - curState.emergencyCallsOnly = !curState.connected; - } - - if (!curState.cell) { - curState.cell = {}; - } - - // From TS 23.003, 0000 and 0xfffe are indicated that no valid LAI exists - // in MS. So we still need to report the '0000' as well. - let lac = this.parseInt(newState[1], -1, 16); - if (curState.cell.gsmLocationAreaCode === undefined || - curState.cell.gsmLocationAreaCode !== lac) { - curState.cell.gsmLocationAreaCode = lac; - changed = true; - } - - let cid = this.parseInt(newState[2], -1, 16); - if (curState.cell.gsmCellId === undefined || - curState.cell.gsmCellId !== cid) { - curState.cell.gsmCellId = cid; - changed = true; - } - - let radioTech = (newState[3] === undefined ? - NETWORK_CREG_TECH_UNKNOWN : - this.parseInt(newState[3], NETWORK_CREG_TECH_UNKNOWN)); - if (curState.radioTech === undefined || curState.radioTech !== radioTech) { - changed = true; - curState.radioTech = radioTech; - curState.type = GECKO_RADIO_TECH[radioTech] || null; - } - return changed; - }, - - _processVoiceRegistrationState: function(state) { - let rs = this.voiceRegistrationState; - let stateChanged = this._processCREG(rs, state); - if (stateChanged && rs.connected) { - this.getSmscAddress(); - } - - let cell = rs.cell; - if (this._isCdma) { - // Some variables below are not used. Comment them instead of removing to - // keep the information about state[x]. - let cdmaBaseStationId = this.parseInt(state[4], -1); - let cdmaBaseStationLatitude = this.parseInt(state[5], -2147483648); - let cdmaBaseStationLongitude = this.parseInt(state[6], -2147483648); - // let cssIndicator = this.parseInt(state[7]); - let cdmaSystemId = this.parseInt(state[8], -1); - let cdmaNetworkId = this.parseInt(state[9], -1); - // let roamingIndicator = this.parseInt(state[10]); - // let systemIsInPRL = this.parseInt(state[11]); - // let defaultRoamingIndicator = this.parseInt(state[12]); - // let reasonForDenial = this.parseInt(state[13]); - - if (cell.cdmaBaseStationId !== cdmaBaseStationId || - cell.cdmaBaseStationLatitude !== cdmaBaseStationLatitude || - cell.cdmaBaseStationLongitude !== cdmaBaseStationLongitude || - cell.cdmaSystemId !== cdmaSystemId || - cell.cdmaNetworkId !== cdmaNetworkId) { - stateChanged = true; - cell.cdmaBaseStationId = cdmaBaseStationId; - cell.cdmaBaseStationLatitude = cdmaBaseStationLatitude; - cell.cdmaBaseStationLongitude = cdmaBaseStationLongitude; - cell.cdmaSystemId = cdmaSystemId; - cell.cdmaNetworkId = cdmaNetworkId; - } - } - - if (stateChanged) { - rs.rilMessageType = "voiceregistrationstatechange"; - this._sendNetworkInfoMessage(NETWORK_INFO_VOICE_REGISTRATION_STATE, rs); - } - }, - - _processDataRegistrationState: function(state) { - let rs = this.dataRegistrationState; - let stateChanged = this._processCREG(rs, state); - if (stateChanged) { - rs.rilMessageType = "dataregistrationstatechange"; - this._sendNetworkInfoMessage(NETWORK_INFO_DATA_REGISTRATION_STATE, rs); - } - }, - - _processOperator: function(operatorData) { - if (operatorData.length < 3) { - if (DEBUG) { - this.context.debug("Expected at least 3 strings for operator."); - } - } - - if (!this.operator) { - this.operator = { - rilMessageType: "operatorchange", - longName: null, - shortName: null - }; - } - - let [longName, shortName, networkTuple] = operatorData; - let thisTuple = (this.operator.mcc || "") + (this.operator.mnc || ""); - - if (this.operator.longName !== longName || - this.operator.shortName !== shortName || - thisTuple !== networkTuple) { - - this.operator.mcc = null; - this.operator.mnc = null; - - if (networkTuple) { - try { - this._processNetworkTuple(networkTuple, this.operator); - } catch (e) { - if (DEBUG) this.context.debug("Error processing operator tuple: " + e); - } - } else { - // According to ril.h, the operator fields will be NULL when the operator - // is not currently registered. We can avoid trying to parse the numeric - // tuple in that case. - if (DEBUG) { - this.context.debug("Operator is currently unregistered"); - } - } - - this.operator.longName = longName; - this.operator.shortName = shortName; - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.updateDisplayCondition()) { - ICCUtilsHelper.handleICCInfoChange(); - } - - // NETWORK_INFO_OPERATOR message will be sent out by overrideICCNetworkName - // itself if operator name is overridden after checking, or we have to - // do it by ourself. - if (!this.overrideICCNetworkName()) { - this._sendNetworkInfoMessage(NETWORK_INFO_OPERATOR, this.operator); - } - } - }, - - _processSuppSvcNotification: function(info) { - if (DEBUG) { - this.context.debug("handle supp svc notification: " + JSON.stringify(info)); - } - - if (info.notificationType !== 1) { - // We haven't supported MO intermediate result code, i.e. - // info.notificationType === 0, which refers to code1 defined in 3GPP - // 27.007 7.17. We only support partial MT unsolicited result code, - // referring to code2, for now. - return; - } - - let notification = null; - - switch (info.code) { - case SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD: - case SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED: - notification = GECKO_SUPP_SVC_NOTIFICATION_FROM_CODE2[info.code]; - break; - default: - // Notification type not supported. - return; - } - - let message = {rilMessageType: "suppSvcNotification", - number: info.number, // could be empty. - notification: notification}; - this.sendChromeMessage(message); - }, - - _cancelEmergencyCbModeTimeout: function() { - if (this._exitEmergencyCbModeTimeoutID) { - clearTimeout(this._exitEmergencyCbModeTimeoutID); - this._exitEmergencyCbModeTimeoutID = null; - } - }, - - _handleChangedEmergencyCbMode: function(active) { - this._isInEmergencyCbMode = active; - - // Clear the existed timeout event. - this._cancelEmergencyCbModeTimeout(); - - // Start a new timeout event when entering the mode. - if (active) { - this._exitEmergencyCbModeTimeoutID = setTimeout( - this.exitEmergencyCbMode.bind(this), EMERGENCY_CB_MODE_TIMEOUT_MS); - } - - let message = {rilMessageType: "emergencyCbModeChange", - active: active, - timeoutMs: EMERGENCY_CB_MODE_TIMEOUT_MS}; - this.sendChromeMessage(message); - }, - - _updateNetworkSelectionMode: function(mode) { - if (this.networkSelectionMode === mode) { - return; - } - - let options = { - rilMessageType: "networkselectionmodechange", - mode: mode - }; - this.networkSelectionMode = mode; - this._sendNetworkInfoMessage(NETWORK_INFO_NETWORK_SELECTION_MODE, options); - }, - - _processNetworks: function() { - let strings = this.context.Buf.readStringList(); - let networks = []; - - for (let i = 0; i < strings.length; - i += RILQUIRKS_AVAILABLE_NETWORKS_EXTRA_STRING ? 5 : 4) { - let network = { - longName: strings[i], - shortName: strings[i + 1], - mcc: null, - mnc: null, - state: null - }; - - let networkTuple = strings[i + 2]; - try { - this._processNetworkTuple(networkTuple, network); - } catch (e) { - if (DEBUG) this.context.debug("Error processing operator tuple: " + e); - } - - let state = strings[i + 3]; - network.state = RIL_QAN_STATE_TO_GECKO_STATE[state]; - - networks.push(network); - } - return networks; - }, - - /** - * The "numeric" portion of the operator info is a tuple - * containing MCC (country code) and MNC (network code). - * AFAICT, MCC should always be 3 digits, making the remaining - * portion the MNC. - */ - _processNetworkTuple: function(networkTuple, network) { - let tupleLen = networkTuple.length; - - if (tupleLen == 5 || tupleLen == 6) { - network.mcc = networkTuple.substr(0, 3); - network.mnc = networkTuple.substr(3); - } else { - network.mcc = null; - network.mnc = null; - - throw new Error("Invalid network tuple (should be 5 or 6 digits): " + networkTuple); - } - }, - - /** - * Check if GSM radio access technology group. - */ - _isGsmTechGroup: function(radioTech) { - if (!radioTech) { - return true; - } - - switch(radioTech) { - case NETWORK_CREG_TECH_GPRS: - case NETWORK_CREG_TECH_EDGE: - case NETWORK_CREG_TECH_UMTS: - case NETWORK_CREG_TECH_HSDPA: - case NETWORK_CREG_TECH_HSUPA: - case NETWORK_CREG_TECH_HSPA: - case NETWORK_CREG_TECH_LTE: - case NETWORK_CREG_TECH_HSPAP: - case NETWORK_CREG_TECH_GSM: - case NETWORK_CREG_TECH_DCHSPAP_1: - case NETWORK_CREG_TECH_DCHSPAP_2: - return true; - } - - return false; - }, - - /** - * Process radio technology change. - */ - _processRadioTech: function(radioTech) { - let isCdma = !this._isGsmTechGroup(radioTech); - this.radioTech = radioTech; - - if (DEBUG) { - this.context.debug("Radio tech is set to: " + GECKO_RADIO_TECH[radioTech] + - ", it is a " + (isCdma?"cdma":"gsm") + " technology"); - } - - // We should request SIM information when - // 1. Radio state has been changed, so we are waiting for radioTech or - // 2. isCdma is different from this._isCdma. - if (this._waitingRadioTech || isCdma != this._isCdma) { - this._isCdma = isCdma; - this._waitingRadioTech = false; - this.getICCStatus(); - } - }, - - /** - * Helper for returning the TOA for the given dial string. - */ - _toaFromString: function(number) { - let toa = TOA_UNKNOWN; - if (number && number.length > 0 && number[0] == '+') { - toa = TOA_INTERNATIONAL; - } - return toa; - }, - - /** - * @param message A decoded SMS-DELIVER message. - * - * @see 3GPP TS 31.111 section 7.1.1 - */ - dataDownloadViaSMSPP: function(message) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let options = { - pid: message.pid, - dcs: message.dcs, - encoding: message.encoding, - }; - Buf.newParcel(REQUEST_STK_SEND_ENVELOPE_WITH_STATUS, options); - - Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable() - - 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type. - let messageStringLength = Buf.readInt32(); // In semi-octets - let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA - let tpduLength = (messageStringLength / 2) - (smscLength + 1); // In octets - - // Device identities: 4 bytes - // Address: 0 or (2 + smscLength) - // SMS TPDU: (2 or 3) + tpduLength - let berLen = 4 + - (smscLength ? (2 + smscLength) : 0) + - (tpduLength <= 127 ? 2 : 3) + tpduLength; // In octets - - let parcelLength = (berLen <= 127 ? 2 : 3) + berLen; // In octets - Buf.writeInt32(parcelLength * 2); // In semi-octets - - // Write a BER-TLV - GsmPDUHelper.writeHexOctet(BER_SMS_PP_DOWNLOAD_TAG); - if (berLen > 127) { - GsmPDUHelper.writeHexOctet(0x81); - } - GsmPDUHelper.writeHexOctet(berLen); - - // Device Identifies-TLV - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(0x02); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_NETWORK); - GsmPDUHelper.writeHexOctet(STK_DEVICE_ID_SIM); - - // Address-TLV - if (smscLength) { - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_ADDRESS); - GsmPDUHelper.writeHexOctet(smscLength); - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength); - } - - // SMS TPDU-TLV - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_SMS_TPDU | - COMPREHENSIONTLV_FLAG_CR); - if (tpduLength > 127) { - GsmPDUHelper.writeHexOctet(0x81); - } - GsmPDUHelper.writeHexOctet(tpduLength); - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * tpduLength); - - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - Buf.sendParcel(); - }, - - /** - * @param success A boolean value indicating the result of previous - * SMS-DELIVER message handling. - * @param responsePduLen ICC IO response PDU length in octets. - * @param options An object that contains four attributes: `pid`, `dcs`, - * `encoding` and `responsePduLen`. - * - * @see 3GPP TS 23.040 section 9.2.2.1a - */ - acknowledgeIncomingGsmSmsWithPDU: function(success, responsePduLen, options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU); - - // Two strings. - Buf.writeInt32(2); - - // String 1: Success - Buf.writeString(success ? "1" : "0"); - - // String 2: RP-ACK/RP-ERROR PDU - Buf.writeInt32(2 * (responsePduLen + (success ? 5 : 6))); // In semi-octet - // 1. TP-MTI & TP-UDHI - GsmPDUHelper.writeHexOctet(PDU_MTI_SMS_DELIVER); - if (!success) { - // 2. TP-FCS - GsmPDUHelper.writeHexOctet(PDU_FCS_USIM_DATA_DOWNLOAD_ERROR); - } - // 3. TP-PI - GsmPDUHelper.writeHexOctet(PDU_PI_USER_DATA_LENGTH | - PDU_PI_DATA_CODING_SCHEME | - PDU_PI_PROTOCOL_IDENTIFIER); - // 4. TP-PID - GsmPDUHelper.writeHexOctet(options.pid); - // 5. TP-DCS - GsmPDUHelper.writeHexOctet(options.dcs); - // 6. TP-UDL - if (options.encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - GsmPDUHelper.writeHexOctet(Math.floor(responsePduLen * 8 / 7)); - } else { - GsmPDUHelper.writeHexOctet(responsePduLen); - } - // TP-UD - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * responsePduLen); - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - Buf.sendParcel(); - }, - - /** - * @param message A decoded SMS-DELIVER message. - */ - writeSmsToSIM: function(message) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - Buf.newParcel(REQUEST_WRITE_SMS_TO_SIM); - - // Write EFsms Status - Buf.writeInt32(EFSMS_STATUS_FREE); - - Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable() - - 2 * Buf.UINT32_SIZE)); // Skip response_type & request_type. - let messageStringLength = Buf.readInt32(); // In semi-octets - let smscLength = GsmPDUHelper.readHexOctet(); // In octets, inclusive of TOA - let pduLength = (messageStringLength / 2) - (smscLength + 1); // In octets - - // 1. Write PDU first. - if (smscLength > 0) { - Buf.seekIncoming(smscLength * Buf.PDU_HEX_OCTET_SIZE); - } - // Write EFsms PDU string length - Buf.writeInt32(2 * pduLength); // In semi-octets - if (pduLength) { - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * pduLength); - } - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - // 2. Write SMSC - // Write EFsms SMSC string length - Buf.writeInt32(2 * (smscLength + 1)); // Plus smscLength itself, in semi-octets - // Write smscLength - GsmPDUHelper.writeHexOctet(smscLength); - // Write TOA & SMSC Address - if (smscLength) { - Buf.seekIncoming(-1 * (Buf.getCurrentParcelSize() - Buf.getReadAvailable() - - 2 * Buf.UINT32_SIZE // Skip response_type, request_type. - - 2 * Buf.PDU_HEX_OCTET_SIZE)); // Skip messageStringLength & smscLength. - Buf.copyIncomingToOutgoing(Buf.PDU_HEX_OCTET_SIZE * smscLength); - } - // Write 2 string delimitors for the total string length must be even. - Buf.writeStringDelimiter(0); - - Buf.sendParcel(); - }, - - /** - * Helper to delegate the received sms segment to RadioInterface to process. - * - * @param message - * Received sms message. - * - * @return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK - */ - _processSmsMultipart: function(message) { - message.rilMessageType = "sms-received"; - - this.sendChromeMessage(message); - - return MOZ_FCS_WAIT_FOR_EXPLICIT_ACK; - }, - - /** - * Helper for processing SMS-STATUS-REPORT PDUs. - * - * @param length - * Length of SMS string in the incoming parcel. - * - * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. - */ - _processSmsStatusReport: function(length) { - let [message, result] = this.context.GsmPDUHelper.processReceivedSms(length); - if (!message) { - if (DEBUG) this.context.debug("invalid SMS-STATUS-REPORT"); - return PDU_FCS_UNSPECIFIED; - } - - let options = this._pendingSentSmsMap[message.messageRef]; - if (!options) { - if (DEBUG) this.context.debug("no pending SMS-SUBMIT message"); - return PDU_FCS_OK; - } - - let status = message.status; - - // 3GPP TS 23.040 9.2.3.15 `The MS shall interpret any reserved values as - // "Service Rejected"(01100011) but shall store them exactly as received.` - if ((status >= 0x80) - || ((status >= PDU_ST_0_RESERVED_BEGIN) - && (status < PDU_ST_0_SC_SPECIFIC_BEGIN)) - || ((status >= PDU_ST_1_RESERVED_BEGIN) - && (status < PDU_ST_1_SC_SPECIFIC_BEGIN)) - || ((status >= PDU_ST_2_RESERVED_BEGIN) - && (status < PDU_ST_2_SC_SPECIFIC_BEGIN)) - || ((status >= PDU_ST_3_RESERVED_BEGIN) - && (status < PDU_ST_3_SC_SPECIFIC_BEGIN)) - ) { - status = PDU_ST_3_SERVICE_REJECTED; - } - - // Pending. Waiting for next status report. - if ((status >>> 5) == 0x01) { - if (DEBUG) this.context.debug("SMS-STATUS-REPORT: delivery still pending"); - return PDU_FCS_OK; - } - - delete this._pendingSentSmsMap[message.messageRef]; - - let deliveryStatus = ((status >>> 5) === 0x00) - ? GECKO_SMS_DELIVERY_STATUS_SUCCESS - : GECKO_SMS_DELIVERY_STATUS_ERROR; - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - deliveryStatus: deliveryStatus - }); - - return PDU_FCS_OK; - }, - - /** - * Helper for processing CDMA SMS Delivery Acknowledgment Message - * - * @param message - * decoded SMS Delivery ACK message from CdmaPDUHelper. - * - * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. - */ - _processCdmaSmsStatusReport: function(message) { - let options = this._pendingSentSmsMap[message.msgId]; - if (!options) { - if (DEBUG) this.context.debug("no pending SMS-SUBMIT message"); - return PDU_FCS_OK; - } - - if (message.errorClass === 2) { - if (DEBUG) { - this.context.debug("SMS-STATUS-REPORT: delivery still pending, " + - "msgStatus: " + message.msgStatus); - } - return PDU_FCS_OK; - } - - delete this._pendingSentSmsMap[message.msgId]; - - if (message.errorClass === -1 && message.body) { - // Process as normal incoming SMS, if errorClass is invalid - // but message body is available. - return this._processSmsMultipart(message); - } - - let deliveryStatus = (message.errorClass === 0) - ? GECKO_SMS_DELIVERY_STATUS_SUCCESS - : GECKO_SMS_DELIVERY_STATUS_ERROR; - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - deliveryStatus: deliveryStatus - }); - - return PDU_FCS_OK; - }, - - /** - * Helper for processing CDMA SMS WAP Push Message - * - * @param message - * decoded WAP message from CdmaPDUHelper. - * - * @return A failure cause defined in 3GPP 23.040 clause 9.2.3.22. - */ - _processCdmaSmsWapPush: function(message) { - if (!message.data) { - if (DEBUG) this.context.debug("no data inside WAP Push message."); - return PDU_FCS_OK; - } - - // See 6.5. MAPPING OF WDP TO CDMA SMS in WAP-295-WDP. - // - // Field | Length (bits) - // ----------------------------------------- - // MSG_TYPE | 8 - // TOTAL_SEGMENTS | 8 - // SEGMENT_NUMBER | 8 - // DATAGRAM | (NUM_FIELDS - 3) * 8 - let index = 0; - if (message.data[index++] !== 0) { - if (DEBUG) this.context.debug("Ignore a WAP Message which is not WDP."); - return PDU_FCS_OK; - } - - // 1. Originator Address in SMS-TL + Message_Id in SMS-TS are used to identify a unique WDP datagram. - // 2. TOTAL_SEGMENTS, SEGMENT_NUMBER are used to verify that a complete - // datagram has been received and is ready to be passed to a higher layer. - message.header = { - segmentRef: message.msgId, - segmentMaxSeq: message.data[index++], - segmentSeq: message.data[index++] + 1 // It's zero-based in CDMA WAP Push. - }; - - if (message.header.segmentSeq > message.header.segmentMaxSeq) { - if (DEBUG) this.context.debug("Wrong WDP segment info."); - return PDU_FCS_OK; - } - - // Ports are only specified in 1st segment. - if (message.header.segmentSeq == 1) { - message.header.originatorPort = message.data[index++] << 8; - message.header.originatorPort |= message.data[index++]; - message.header.destinationPort = message.data[index++] << 8; - message.header.destinationPort |= message.data[index++]; - } - - message.data = message.data.subarray(index); - - return this._processSmsMultipart(message); - }, - - /** - * Helper for processing sent multipart SMS. - */ - _processSentSmsSegment: function(options) { - // Setup attributes for sending next segment - let next = options.segmentSeq; - options.body = options.segments[next].body; - options.encodedBodyLength = options.segments[next].encodedBodyLength; - options.segmentSeq = next + 1; - - this.sendSMS(options); - }, - - /** - * Helper for processing result of send SMS. - * - * @param length - * Length of SMS string in the incoming parcel. - * @param options - * Sms information. - */ - _processSmsSendResult: function(length, options) { - if (options.errorMsg) { - if (DEBUG) { - this.context.debug("_processSmsSendResult: errorMsg = " + - options.errorMsg); - } - - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - errorMsg: options.errorMsg, - }); - return; - } - - let Buf = this.context.Buf; - options.messageRef = Buf.readInt32(); - options.ackPDU = Buf.readString(); - options.errorCode = Buf.readInt32(); - - if ((options.segmentMaxSeq > 1) - && (options.segmentSeq < options.segmentMaxSeq)) { - // Not last segment - this._processSentSmsSegment(options); - } else { - // Last segment sent with success. - if (options.requestStatusReport) { - if (DEBUG) { - this.context.debug("waiting SMS-STATUS-REPORT for messageRef " + - options.messageRef); - } - this._pendingSentSmsMap[options.messageRef] = options; - } - - this.sendChromeMessage({ - rilMessageType: options.rilMessageType, - rilMessageToken: options.rilMessageToken, - }); - } - }, - - _processReceivedSmsCbPage: function(original) { - if (original.numPages <= 1) { - if (original.body) { - original.fullBody = original.body; - delete original.body; - } else if (original.data) { - original.fullData = original.data; - delete original.data; - } - return original; - } - - // Hash = :::: - let hash = original.serial + ":" + this.iccInfo.mcc + ":" - + this.iccInfo.mnc + ":"; - switch (original.geographicalScope) { - case CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE_IMMEDIATE: - case CB_GSM_GEOGRAPHICAL_SCOPE_CELL_WIDE: - hash += this.voiceRegistrationState.cell.gsmLocationAreaCode + ":" - + this.voiceRegistrationState.cell.gsmCellId; - break; - case CB_GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA_WIDE: - hash += this.voiceRegistrationState.cell.gsmLocationAreaCode + ":"; - break; - default: - hash += ":"; - break; - } - - let index = original.pageIndex; - - let options = this._receivedSmsCbPagesMap[hash]; - if (!options) { - options = original; - this._receivedSmsCbPagesMap[hash] = options; - - options.receivedPages = 0; - options.pages = []; - } else if (options.pages[index]) { - // Duplicated page? - if (DEBUG) { - this.context.debug("Got duplicated page no." + index + - " of a multipage SMSCB: " + JSON.stringify(original)); - } - return null; - } - - if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - options.pages[index] = original.data; - delete original.data; - } else { - options.pages[index] = original.body; - delete original.body; - } - options.receivedPages++; - if (options.receivedPages < options.numPages) { - if (DEBUG) { - this.context.debug("Got page no." + index + " of a multipage SMSCB: " + - JSON.stringify(options)); - } - return null; - } - - // Remove from map - delete this._receivedSmsCbPagesMap[hash]; - - // Rebuild full body - if (options.encoding == PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - // Uint8Array doesn't have `concat`, so we have to merge all pages by hand. - let fullDataLen = 0; - for (let i = 1; i <= options.numPages; i++) { - fullDataLen += options.pages[i].length; - } - - options.fullData = new Uint8Array(fullDataLen); - for (let d= 0, i = 1; i <= options.numPages; i++) { - let data = options.pages[i]; - for (let j = 0; j < data.length; j++) { - options.fullData[d++] = data[j]; - } - } - } else { - options.fullBody = options.pages.join(""); - } - - if (DEBUG) { - this.context.debug("Got full multipage SMSCB: " + JSON.stringify(options)); - } - - return options; - }, - - _mergeCellBroadcastConfigs: function(list, from, to) { - if (!list) { - return [from, to]; - } - - for (let i = 0, f1, t1; i < list.length;) { - f1 = list[i++]; - t1 = list[i++]; - if (to == f1) { - // ...[from]...[to|f1]...(t1) - list[i - 2] = from; - return list; - } - - if (to < f1) { - // ...[from]...(to)...[f1] or ...[from]...(to)[f1] - if (i > 2) { - // Not the first range pair, merge three arrays. - return list.slice(0, i - 2).concat([from, to]).concat(list.slice(i - 2)); - } else { - return [from, to].concat(list); - } - } - - if (from > t1) { - // ...[f1]...(t1)[from] or ...[f1]...(t1)...[from] - continue; - } - - // Have overlap or merge-able adjacency with [f1]...(t1). Replace it - // with [min(from, f1)]...(max(to, t1)). - - let changed = false; - if (from < f1) { - // [from]...[f1]...(t1) or [from][f1]...(t1) - // Save minimum from value. - list[i - 2] = from; - changed = true; - } - - if (to <= t1) { - // [from]...[to](t1) or [from]...(to|t1) - // Can't have further merge-able adjacency. Return. - return list; - } - - // Try merging possible next adjacent range. - let j = i; - for (let f2, t2; j < list.length;) { - f2 = list[j++]; - t2 = list[j++]; - if (to > t2) { - // [from]...[f2]...[t2]...(to) or [from]...[f2]...[t2](to) - // Merge next adjacent range again. - continue; - } - - if (to < t2) { - if (to < f2) { - // [from]...(to)[f2] or [from]...(to)...[f2] - // Roll back and give up. - j -= 2; - } else if (to < t2) { - // [from]...[to|f2]...(t2), or [from]...[f2]...[to](t2) - // Merge to [from]...(t2) and give up. - to = t2; - } - } - - break; - } - - // Save maximum to value. - list[i - 1] = to; - - if (j != i) { - // Remove merged adjacent ranges. - let ret = list.slice(0, i); - if (j < list.length) { - ret = ret.concat(list.slice(j)); - } - return ret; - } - - return list; - } - - // Append to the end. - list.push(from); - list.push(to); - - return list; - }, - - _isCellBroadcastConfigReady: function() { - if (!("MMI" in this.cellBroadcastConfigs)) { - return false; - } - - // CBMI should be ready in GSM. - if (!this._isCdma && - (!("CBMI" in this.cellBroadcastConfigs) || - !("CBMID" in this.cellBroadcastConfigs) || - !("CBMIR" in this.cellBroadcastConfigs))) { - return false; - } - - return true; - }, - - /** - * Merge all members of cellBroadcastConfigs into mergedCellBroadcastConfig. - */ - _mergeAllCellBroadcastConfigs: function() { - if (!this._isCellBroadcastConfigReady()) { - if (DEBUG) { - this.context.debug("cell broadcast configs not ready, waiting ..."); - } - return; - } - - // Prepare cell broadcast config. CBMI* are only used in GSM. - let usedCellBroadcastConfigs = {MMI: this.cellBroadcastConfigs.MMI}; - if (!this._isCdma) { - usedCellBroadcastConfigs.CBMI = this.cellBroadcastConfigs.CBMI; - usedCellBroadcastConfigs.CBMID = this.cellBroadcastConfigs.CBMID; - usedCellBroadcastConfigs.CBMIR = this.cellBroadcastConfigs.CBMIR; - } - - if (DEBUG) { - this.context.debug("Cell Broadcast search lists: " + - JSON.stringify(usedCellBroadcastConfigs)); - } - - let list = null; - for (let key in usedCellBroadcastConfigs) { - let ll = usedCellBroadcastConfigs[key]; - if (ll == null) { - continue; - } - - for (let i = 0; i < ll.length; i += 2) { - list = this._mergeCellBroadcastConfigs(list, ll[i], ll[i + 1]); - } - } - - if (DEBUG) { - this.context.debug("Cell Broadcast search lists(merged): " + - JSON.stringify(list)); - } - this.mergedCellBroadcastConfig = list; - this.updateCellBroadcastConfig(); - }, - - /** - * Check whether search list from settings is settable by MMI, that is, - * whether the range is bounded in any entries of CB_NON_MMI_SETTABLE_RANGES. - */ - _checkCellBroadcastMMISettable: function(from, to) { - if ((to <= from) || (from >= 65536) || (from < 0)) { - return false; - } - - if (!this._isCdma) { - // GSM not settable ranges. - for (let i = 0, f, t; i < CB_NON_MMI_SETTABLE_RANGES.length;) { - f = CB_NON_MMI_SETTABLE_RANGES[i++]; - t = CB_NON_MMI_SETTABLE_RANGES[i++]; - if ((from < t) && (to > f)) { - // Have overlap. - return false; - } - } - } - - return true; - }, - - /** - * Convert Cell Broadcast settings string into search list. - */ - _convertCellBroadcastSearchList: function(searchListStr) { - let parts = searchListStr && searchListStr.split(","); - if (!parts) { - return null; - } - - let list = null; - let result, from, to; - for (let range of parts) { - // Match "12" or "12-34". The result will be ["12", "12", null] or - // ["12-34", "12", "34"]. - result = range.match(/^(\d+)(?:-(\d+))?$/); - if (!result) { - throw "Invalid format"; - } - - from = parseInt(result[1], 10); - to = (result[2]) ? parseInt(result[2], 10) + 1 : from + 1; - if (!this._checkCellBroadcastMMISettable(from, to)) { - throw "Invalid range"; - } - - if (list == null) { - list = []; - } - list.push(from); - list.push(to); - } - - return list; - }, - - /** - * Handle incoming messages from the main UI thread. - * - * @param message - * Object containing the message. Messages are supposed - */ - handleChromeMessage: function(message) { - if (DEBUG) { - this.context.debug("Received chrome message " + JSON.stringify(message)); - } - let method = this[message.rilMessageType]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Don't know what to do with message " + - JSON.stringify(message)); - } - return; - } - method.call(this, message); - }, - - /** - * Process STK Proactive Command. - */ - processStkProactiveCommand: function() { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - let berTlv; - try { - berTlv = this.context.BerTlvHelper.decode(length / 2); - } catch (e) { - if (DEBUG) this.context.debug("processStkProactiveCommand : " + e); - this.sendStkTerminalResponse({ - resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD}); - return; - } - - Buf.readStringDelimiter(length); - - let ctlvs = berTlv.value; - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs); - if (!ctlv) { - this.sendStkTerminalResponse({ - resultCode: STK_RESULT_CMD_DATA_NOT_UNDERSTOOD}); - throw new Error("Can't find COMMAND_DETAILS ComprehensionTlv"); - } - - let cmdDetails = ctlv.value; - if (DEBUG) { - this.context.debug("commandNumber = " + cmdDetails.commandNumber + - " typeOfCommand = " + cmdDetails.typeOfCommand.toString(16) + - " commandQualifier = " + cmdDetails.commandQualifier); - } - - // STK_CMD_MORE_TIME need not to propagate event to chrome. - if (cmdDetails.typeOfCommand == STK_CMD_MORE_TIME) { - this.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_OK}); - return; - } - - this.context.StkCommandParamsFactory.createParam(cmdDetails, - ctlvs, - (aResult) => { - cmdDetails.options = aResult; - cmdDetails.rilMessageType = "stkcommand"; - this.sendChromeMessage(cmdDetails); - }); - }, - - sendDefaultResponse: function(options) { - if (!options.rilMessageType) { - return; - } - - this.sendChromeMessage(options); - }, - - /** - * Send messages to the main thread. - */ - sendChromeMessage: function(message) { - message.rilMessageClientId = this.context.clientId; - postMessage(message); - }, - - /** - * Handle incoming requests from the RIL. We find the method that - * corresponds to the request type. Incidentally, the request type - * _is_ the method name, so that's easy. - */ - - handleParcel: function(request_type, length, options) { - let method = this[request_type]; - if (typeof method == "function") { - if (DEBUG) this.context.debug("Handling parcel as " + method.name); - method.call(this, length, options); - } - - if (this.telephonyRequestQueue.isValidRequest(request_type)) { - this.telephonyRequestQueue.pop(request_type); - } - } -}; - -RilObject.prototype[REQUEST_GET_SIM_STATUS] = function REQUEST_GET_SIM_STATUS(length, options) { - if (options.errorMsg) { - return; - } - - let iccStatus = {}; - let Buf = this.context.Buf; - iccStatus.cardState = Buf.readInt32(); // CARD_STATE_* - iccStatus.universalPINState = Buf.readInt32(); // CARD_PINSTATE_* - iccStatus.gsmUmtsSubscriptionAppIndex = Buf.readInt32(); - iccStatus.cdmaSubscriptionAppIndex = Buf.readInt32(); - iccStatus.imsSubscriptionAppIndex = Buf.readInt32(); - - let apps_length = Buf.readInt32(); - if (apps_length > CARD_MAX_APPS) { - apps_length = CARD_MAX_APPS; - } - - iccStatus.apps = []; - for (let i = 0 ; i < apps_length ; i++) { - iccStatus.apps.push({ - app_type: Buf.readInt32(), // CARD_APPTYPE_* - app_state: Buf.readInt32(), // CARD_APPSTATE_* - perso_substate: Buf.readInt32(), // CARD_PERSOSUBSTATE_* - aid: Buf.readString(), - app_label: Buf.readString(), - pin1_replaced: Buf.readInt32(), - pin1: Buf.readInt32(), - pin2: Buf.readInt32() - }); - if (RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS) { - Buf.readInt32(); - Buf.readInt32(); - Buf.readInt32(); - Buf.readInt32(); - } - } - - if (DEBUG) this.context.debug("iccStatus: " + JSON.stringify(iccStatus)); - this._processICCStatus(iccStatus); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PIN] = function REQUEST_ENTER_SIM_PIN(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PUK] = function REQUEST_ENTER_SIM_PUK(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PIN2] = function REQUEST_ENTER_SIM_PIN2(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_SIM_PUK2] = function REQUEST_ENTER_SIM_PUK(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_CHANGE_SIM_PIN] = function REQUEST_CHANGE_SIM_PIN(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_CHANGE_SIM_PIN2] = function REQUEST_CHANGE_SIM_PIN2(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE] = - function REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE(length, options) { - this._processEnterAndChangeICCResponses(length, options); -}; -RilObject.prototype[REQUEST_GET_CURRENT_CALLS] = function REQUEST_GET_CURRENT_CALLS(length, options) { - // Retry getCurrentCalls several times when error occurs. - if (options.errorMsg) { - if (this._getCurrentCallsRetryCount < GET_CURRENT_CALLS_RETRY_MAX) { - this._getCurrentCallsRetryCount++; - this.getCurrentCalls(options); - } else { - this.sendDefaultResponse(options); - } - return; - } - - this._getCurrentCallsRetryCount = 0; - - let Buf = this.context.Buf; - let calls_length = 0; - // The RIL won't even send us the length integer if there are no active calls. - // So only read this integer if the parcel actually has it. - if (length) { - calls_length = Buf.readInt32(); - } - - let calls = {}; - for (let i = 0; i < calls_length; i++) { - let call = {}; - - // Extra uint32 field to get correct callIndex and rest of call data for - // call waiting feature. - if (RILQUIRKS_EXTRA_UINT32_2ND_CALL && i > 0) { - Buf.readInt32(); - } - - call.state = Buf.readInt32(); // CALL_STATE_* - call.callIndex = Buf.readInt32(); // GSM index (1-based) - call.toa = Buf.readInt32(); - call.isMpty = Boolean(Buf.readInt32()); - call.isMT = Boolean(Buf.readInt32()); - call.als = Buf.readInt32(); - call.isVoice = Boolean(Buf.readInt32()); - call.isVoicePrivacy = Boolean(Buf.readInt32()); - if (RILQUIRKS_CALLSTATE_EXTRA_UINT32) { - Buf.readInt32(); - } - call.number = Buf.readString(); - call.numberPresentation = Buf.readInt32(); // CALL_PRESENTATION_* - call.name = Buf.readString(); - call.namePresentation = Buf.readInt32(); - - call.uusInfo = null; - let uusInfoPresent = Buf.readInt32(); - if (uusInfoPresent == 1) { - call.uusInfo = { - type: Buf.readInt32(), - dcs: Buf.readInt32(), - userData: null //XXX TODO byte array?!? - }; - } - - if (call.isVoice) { - calls[call.callIndex] = call; - } - } - - options.calls = calls; - options.rilMessageType = options.rilMessageType || "currentCalls"; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_DIAL] = function REQUEST_DIAL(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_DIAL_EMERGENCY_CALL] = function REQUEST_DIAL_EMERGENCY_CALL(length, options) { - RilObject.prototype[REQUEST_DIAL].call(this, length, options); -}; -RilObject.prototype[REQUEST_GET_IMSI] = function REQUEST_GET_IMSI(length, options) { - if (options.errorMsg) { - return; - } - - this.iccInfoPrivate.imsi = this.context.Buf.readString(); - if (DEBUG) { - this.context.debug("IMSI: " + this.iccInfoPrivate.imsi); - } - - options.rilMessageType = "iccimsi"; - options.imsi = this.iccInfoPrivate.imsi; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_HANGUP] = function REQUEST_HANGUP(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_HANGUP_WAITING_OR_BACKGROUND] = function REQUEST_HANGUP_WAITING_OR_BACKGROUND(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = function REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = function REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_CONFERENCE] = function REQUEST_CONFERENCE(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_UDUB] = function REQUEST_UDUB(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_LAST_CALL_FAIL_CAUSE] = function REQUEST_LAST_CALL_FAIL_CAUSE(length, options) { - // Treat it as CALL_FAIL_ERROR_UNSPECIFIED if the request failed. - let failCause = CALL_FAIL_ERROR_UNSPECIFIED; - - if (!options.errorMsg) { - let Buf = this.context.Buf; - let num = length ? Buf.readInt32() : 0; - - if (num) { - let causeNum = Buf.readInt32(); - failCause = RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[causeNum] || failCause; - } - if (DEBUG) this.context.debug("Last call fail cause: " + failCause); - } - - options.failCause = failCause; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SIGNAL_STRENGTH] = function REQUEST_SIGNAL_STRENGTH(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_SIGNAL); - - if (options.errorMsg) { - return; - } - - let Buf = this.context.Buf; - let signal = {}; - - signal.gsmSignalStrength = Buf.readInt32(); - signal.gsmBitErrorRate = Buf.readInt32(); - if (RILQUIRKS_SIGNAL_EXTRA_INT32) { - Buf.readInt32(); - } - signal.cdmaDBM = Buf.readInt32(); - signal.cdmaECIO = Buf.readInt32(); - signal.evdoDBM = Buf.readInt32(); - signal.evdoECIO = Buf.readInt32(); - signal.evdoSNR = Buf.readInt32(); - - signal.lteSignalStrength = Buf.readInt32(); - signal.lteRSRP = Buf.readInt32(); - signal.lteRSRQ = Buf.readInt32(); - signal.lteRSSNR = Buf.readInt32(); - signal.lteCQI = Buf.readInt32(); - - if (DEBUG) this.context.debug("signal strength: " + JSON.stringify(signal)); - - this._processSignalStrength(signal); -}; -RilObject.prototype[REQUEST_VOICE_REGISTRATION_STATE] = function REQUEST_VOICE_REGISTRATION_STATE(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_VOICE_REGISTRATION_STATE); - - if (options.errorMsg) { - return; - } - - let state = this.context.Buf.readStringList(); - if (DEBUG) this.context.debug("voice registration state: " + state); - - this._processVoiceRegistrationState(state); -}; -RilObject.prototype[REQUEST_DATA_REGISTRATION_STATE] = function REQUEST_DATA_REGISTRATION_STATE(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_DATA_REGISTRATION_STATE); - - if (options.errorMsg) { - return; - } - - let state = this.context.Buf.readStringList(); - this._processDataRegistrationState(state); -}; -RilObject.prototype[REQUEST_OPERATOR] = function REQUEST_OPERATOR(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_OPERATOR); - - if (options.errorMsg) { - return; - } - - let operatorData = this.context.Buf.readStringList(); - if (DEBUG) this.context.debug("Operator: " + operatorData); - this._processOperator(operatorData); -}; -RilObject.prototype[REQUEST_RADIO_POWER] = function REQUEST_RADIO_POWER(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_DTMF] = null; -RilObject.prototype[REQUEST_SEND_SMS] = function REQUEST_SEND_SMS(length, options) { - this._processSmsSendResult(length, options); -}; -RilObject.prototype[REQUEST_SEND_SMS_EXPECT_MORE] = null; - -RilObject.prototype[REQUEST_SETUP_DATA_CALL] = function REQUEST_SETUP_DATA_CALL(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let version = Buf.readInt32(); - // Skip number of data calls. - Buf.readInt32(); - - this.readDataCall(options, version); - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SIM_IO] = function REQUEST_SIM_IO(length, options) { - if (options.errorMsg) { - if (options.onerror) { - options.onerror(options.errorMsg); - } - return; - } - - let Buf = this.context.Buf; - options.sw1 = Buf.readInt32(); - options.sw2 = Buf.readInt32(); - - // See 3GPP TS 11.11, clause 9.4.1 for operation success results. - if (options.sw1 !== ICC_STATUS_NORMAL_ENDING && - options.sw1 !== ICC_STATUS_NORMAL_ENDING_WITH_EXTRA && - options.sw1 !== ICC_STATUS_WITH_SIM_DATA && - options.sw1 !== ICC_STATUS_WITH_RESPONSE_DATA) { - if (DEBUG) { - this.context.debug("ICC I/O Error EF id = 0x" + options.fileId.toString(16) + - ", command = 0x" + options.command.toString(16) + - ", sw1 = 0x" + options.sw1.toString(16) + - ", sw2 = 0x" + options.sw2.toString(16)); - } - if (options.onerror) { - // We can get fail cause from sw1/sw2 (See TS 11.11 clause 9.4.1 and - // ISO 7816-4 clause 6). But currently no one needs this information, - // so simply reports "GenericFailure" for now. - options.onerror(GECKO_ERROR_GENERIC_FAILURE); - } - return; - } - this.context.ICCIOHelper.processICCIO(options); -}; -RilObject.prototype[REQUEST_SEND_USSD] = function REQUEST_SEND_USSD(length, options) { - if (DEBUG) { - this.context.debug("REQUEST_SEND_USSD " + JSON.stringify(options)); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CANCEL_USSD] = function REQUEST_CANCEL_USSD(length, options) { - if (DEBUG) { - this.context.debug("REQUEST_CANCEL_USSD" + JSON.stringify(options)); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_CLIR] = function REQUEST_GET_CLIR(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let bufLength = Buf.readInt32(); - if (!bufLength || bufLength < 2) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - - options.n = Buf.readInt32(); // Will be TS 27.007 +CLIR parameter 'n'. - options.m = Buf.readInt32(); // Will be TS 27.007 +CLIR parameter 'm'. - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_CLIR] = function REQUEST_SET_CLIR(length, options) { - if (options.rilMessageType == null) { - // The request was made by ril_worker itself automatically. Don't report. - return; - } - - this.sendChromeMessage(options); -}; - -RilObject.prototype[REQUEST_QUERY_CALL_FORWARD_STATUS] = - function REQUEST_QUERY_CALL_FORWARD_STATUS(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let rulesLength = 0; - if (length) { - rulesLength = Buf.readInt32(); - } - if (!rulesLength) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - let rules = new Array(rulesLength); - for (let i = 0; i < rulesLength; i++) { - let rule = {}; - rule.active = Buf.readInt32() == 1; // CALL_FORWARD_STATUS_* - rule.reason = Buf.readInt32(); // CALL_FORWARD_REASON_* - rule.serviceClass = Buf.readInt32(); - rule.toa = Buf.readInt32(); - rule.number = Buf.readString(); - rule.timeSeconds = Buf.readInt32(); - rules[i] = rule; - } - options.rules = rules; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_CALL_FORWARD] = - function REQUEST_SET_CALL_FORWARD(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_CALL_WAITING] = - function REQUEST_QUERY_CALL_WAITING(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let results = Buf.readInt32List(); - let enabled = (results[0] === 1); - options.serviceClass = enabled ? results[1] : ICC_SERVICE_CLASS_NONE; - this.sendChromeMessage(options); -}; - -RilObject.prototype[REQUEST_SET_CALL_WAITING] = function REQUEST_SET_CALL_WAITING(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SMS_ACKNOWLEDGE] = null; -RilObject.prototype[REQUEST_GET_IMEI] = null; -RilObject.prototype[REQUEST_GET_IMEISV] = null; -RilObject.prototype[REQUEST_ANSWER] = function REQUEST_ANSWER(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_DEACTIVATE_DATA_CALL] = function REQUEST_DEACTIVATE_DATA_CALL(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_FACILITY_LOCK] = function REQUEST_QUERY_FACILITY_LOCK(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - if (!length) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - - // Buf.readInt32List()[0] for Call Barring is a bit vector of services. - options.serviceClass = this.context.Buf.readInt32List()[0]; - if (options.queryServiceClass) { - options.enabled = (options.serviceClass & options.queryServiceClass) ? true : false; - options.serviceClass = options.queryServiceClass; - } else { - options.enabled = options.serviceClass ? true : false; - } - - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_FACILITY_LOCK] = function REQUEST_SET_FACILITY_LOCK(length, options) { - options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CHANGE_BARRING_PASSWORD] = - function REQUEST_CHANGE_BARRING_PASSWORD(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_NETWORK_SELECTION_MODE] = function REQUEST_QUERY_NETWORK_SELECTION_MODE(length, options) { - this._receivedNetworkInfo(NETWORK_INFO_NETWORK_SELECTION_MODE); - - if (options.errorMsg) { - return; - } - - let mode = this.context.Buf.readInt32List(); - let selectionMode; - - switch (mode[0]) { - case NETWORK_SELECTION_MODE_AUTOMATIC: - selectionMode = GECKO_NETWORK_SELECTION_AUTOMATIC; - break; - case NETWORK_SELECTION_MODE_MANUAL: - selectionMode = GECKO_NETWORK_SELECTION_MANUAL; - break; - default: - selectionMode = GECKO_NETWORK_SELECTION_UNKNOWN; - break; - } - - this._updateNetworkSelectionMode(selectionMode); -}; -RilObject.prototype[REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = function REQUEST_SET_NETWORK_SELECTION_AUTOMATIC(length, options) { - if (!options.errorMsg) { - this._updateNetworkSelectionMode(GECKO_NETWORK_SELECTION_AUTOMATIC); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_NETWORK_SELECTION_MANUAL] = function REQUEST_SET_NETWORK_SELECTION_MANUAL(length, options) { - if (!options.errorMsg) { - this._updateNetworkSelectionMode(GECKO_NETWORK_SELECTION_MANUAL); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_QUERY_AVAILABLE_NETWORKS] = function REQUEST_QUERY_AVAILABLE_NETWORKS(length, options) { - if (!options.errorMsg) { - options.networks = this._processNetworks(); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_DTMF_START] = function REQUEST_DTMF_START(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_DTMF_STOP] = null; -RilObject.prototype[REQUEST_BASEBAND_VERSION] = function REQUEST_BASEBAND_VERSION(length, options) { - if (options.errorMsg) { - return; - } - - this.basebandVersion = this.context.Buf.readString(); - if (DEBUG) this.context.debug("Baseband version: " + this.basebandVersion); -}; -RilObject.prototype[REQUEST_SEPARATE_CONNECTION] = function REQUEST_SEPARATE_CONNECTION(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_SET_MUTE] = null; -RilObject.prototype[REQUEST_GET_MUTE] = null; -RilObject.prototype[REQUEST_QUERY_CLIP] = function REQUEST_QUERY_CLIP(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let bufLength = Buf.readInt32(); - if (!bufLength) { - options.errorMsg = GECKO_ERROR_GENERIC_FAILURE; - this.sendChromeMessage(options); - return; - } - - options.provisioned = Buf.readInt32(); - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_LAST_DATA_CALL_FAIL_CAUSE] = null; - -/** - * V6: - * # addresses - A space-delimited list of addresses with optional "/" prefix - * length. - * # dnses - A space-delimited list of DNS server addresses. - * # gateways - A space-delimited list of default gateway addresses. - * - * V10: - * # pcscf - A space-delimited list of Proxy Call State Control Function - * addresses. - */ - -RilObject.prototype.readDataCall = function(options, version) { - if (!options) { - options = {}; - } - let Buf = this.context.Buf; - options.failCause = Buf.readInt32(); // DATACALL_FAIL_* - options.suggestedRetryTime = Buf.readInt32(); - options.cid = Buf.readInt32().toString(); - options.active = Buf.readInt32(); // DATACALL_ACTIVE_* - options.type = Buf.readString(); - options.ifname = Buf.readString(); - options.addresses = Buf.readString(); - options.dnses = Buf.readString(); - options.gateways = Buf.readString(); - - if (version >= 10) { - options.pcscf = Buf.readString(); - } - - if (version >= 11) { - let mtu = Buf.readInt32(); - options.mtu = (mtu > 0) ? mtu : -1 ; - } - - return options; -}; - -RilObject.prototype[REQUEST_DATA_CALL_LIST] = function REQUEST_DATA_CALL_LIST(length, options) { - if (options.errorMsg) { - if (options.rilMessageType) { - this.sendChromeMessage(options); - } - return; - } - - if (!options.rilMessageType) { - // This is an unsolicited data call list changed. - options.rilMessageType = "datacalllistchanged"; - } - - if (!length) { - options.datacalls = []; - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let version = Buf.readInt32(); - let num = Buf.readInt32(); - let datacalls = []; - for (let i = 0; i < num; i++) { - let datacall; - datacall = this.readDataCall({}, version); - datacalls.push(datacall); - } - - options.datacalls = datacalls; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_RESET_RADIO] = null; -RilObject.prototype[REQUEST_OEM_HOOK_RAW] = null; -RilObject.prototype[REQUEST_OEM_HOOK_STRINGS] = null; -RilObject.prototype[REQUEST_SCREEN_STATE] = null; -RilObject.prototype[REQUEST_SET_SUPP_SVC_NOTIFICATION] = null; -RilObject.prototype[REQUEST_WRITE_SMS_TO_SIM] = function REQUEST_WRITE_SMS_TO_SIM(length, options) { - if (options.errorMsg) { - // `The MS shall return a "protocol error, unspecified" error message if - // the short message cannot be stored in the (U)SIM, and there is other - // message storage available at the MS` ~ 3GPP TS 23.038 section 4. Here - // we assume we always have indexed db as another storage. - this.acknowledgeGsmSms(false, PDU_FCS_PROTOCOL_ERROR); - } else { - this.acknowledgeGsmSms(true, PDU_FCS_OK); - } -}; -RilObject.prototype[REQUEST_DELETE_SMS_ON_SIM] = null; -RilObject.prototype[REQUEST_SET_BAND_MODE] = null; -RilObject.prototype[REQUEST_QUERY_AVAILABLE_BAND_MODE] = null; -RilObject.prototype[REQUEST_STK_GET_PROFILE] = null; -RilObject.prototype[REQUEST_STK_SET_PROFILE] = null; -RilObject.prototype[REQUEST_STK_SEND_ENVELOPE_COMMAND] = null; -RilObject.prototype[REQUEST_STK_SEND_TERMINAL_RESPONSE] = null; -RilObject.prototype[REQUEST_STK_HANDLE_CALL_SETUP_REQUESTED_FROM_SIM] = null; -RilObject.prototype[REQUEST_EXPLICIT_CALL_TRANSFER] = null; -RilObject.prototype[REQUEST_SET_PREFERRED_NETWORK_TYPE] = function REQUEST_SET_PREFERRED_NETWORK_TYPE(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_PREFERRED_NETWORK_TYPE] = function REQUEST_GET_PREFERRED_NETWORK_TYPE(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - options.type = this.context.Buf.readInt32List()[0]; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_NEIGHBORING_CELL_IDS] = function REQUEST_GET_NEIGHBORING_CELL_IDS(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let radioTech = this.voiceRegistrationState.radioTech; - if (radioTech == undefined || radioTech == NETWORK_CREG_TECH_UNKNOWN) { - options.errorMsg = "RadioTechUnavailable"; - this.sendChromeMessage(options); - return; - } - if (!this._isGsmTechGroup(radioTech) || radioTech == NETWORK_CREG_TECH_LTE) { - options.errorMsg = "UnsupportedRadioTech"; - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let neighboringCellIds = []; - let num = Buf.readInt32(); - - for (let i = 0; i < num; i++) { - let cellId = {}; - cellId.networkType = GECKO_RADIO_TECH[radioTech]; - cellId.signalStrength = Buf.readInt32(); - - let cid = Buf.readString(); - // pad cid string with leading "0" - let length = cid.length; - if (length > 8) { - continue; - } - if (length < 8) { - for (let j = 0; j < (8-length); j++) { - cid = "0" + cid; - } - } - - switch (radioTech) { - case NETWORK_CREG_TECH_GPRS: - case NETWORK_CREG_TECH_EDGE: - case NETWORK_CREG_TECH_GSM: - cellId.gsmCellId = this.parseInt(cid.substring(4), -1, 16); - cellId.gsmLocationAreaCode = this.parseInt(cid.substring(0, 4), -1, 16); - break; - case NETWORK_CREG_TECH_UMTS: - case NETWORK_CREG_TECH_HSDPA: - case NETWORK_CREG_TECH_HSUPA: - case NETWORK_CREG_TECH_HSPA: - case NETWORK_CREG_TECH_HSPAP: - case NETWORK_CREG_TECH_DCHSPAP_1: - case NETWORK_CREG_TECH_DCHSPAP_2: - cellId.wcdmaPsc = this.parseInt(cid, -1, 16); - break; - } - - neighboringCellIds.push(cellId); - } - - options.result = neighboringCellIds; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_CELL_INFO_LIST] = function REQUEST_GET_CELL_INFO_LIST(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - let cellInfoList = []; - let num = Buf.readInt32(); - for (let i = 0; i < num; i++) { - let cellInfo = {}; - cellInfo.type = Buf.readInt32(); - cellInfo.registered = Buf.readInt32() ? true : false; - cellInfo.timestampType = Buf.readInt32(); - cellInfo.timestamp = Buf.readInt64(); - - switch(cellInfo.type) { - case CELL_INFO_TYPE_GSM: - case CELL_INFO_TYPE_WCDMA: - cellInfo.mcc = Buf.readInt32(); - cellInfo.mnc = Buf.readInt32(); - cellInfo.lac = Buf.readInt32(); - cellInfo.cid = Buf.readInt32(); - if (cellInfo.type == CELL_INFO_TYPE_WCDMA) { - cellInfo.psc = Buf.readInt32(); - } - cellInfo.signalStrength = Buf.readInt32(); - cellInfo.bitErrorRate = Buf.readInt32(); - break; - case CELL_INFO_TYPE_CDMA: - cellInfo.networkId = Buf.readInt32(); - cellInfo.systemId = Buf.readInt32(); - cellInfo.basestationId = Buf.readInt32(); - cellInfo.longitude = Buf.readInt32(); - cellInfo.latitude = Buf.readInt32(); - cellInfo.cdmaDbm = Buf.readInt32(); - cellInfo.cdmaEcio = Buf.readInt32(); - cellInfo.evdoDbm = Buf.readInt32(); - cellInfo.evdoEcio = Buf.readInt32(); - cellInfo.evdoSnr = Buf.readInt32(); - break; - case CELL_INFO_TYPE_LTE: - cellInfo.mcc = Buf.readInt32(); - cellInfo.mnc = Buf.readInt32(); - cellInfo.cid = Buf.readInt32(); - cellInfo.pcid = Buf.readInt32(); - cellInfo.tac = Buf.readInt32(); - cellInfo.signalStrength = Buf.readInt32(); - cellInfo.rsrp = Buf.readInt32(); - cellInfo.rsrq = Buf.readInt32(); - cellInfo.rssnr = Buf.readInt32(); - cellInfo.cqi = Buf.readInt32(); - break; - } - cellInfoList.push(cellInfo); - } - options.result = cellInfoList; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_LOCATION_UPDATES] = null; -RilObject.prototype[REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE] = null; -RilObject.prototype[REQUEST_CDMA_SET_ROAMING_PREFERENCE] = function REQUEST_CDMA_SET_ROAMING_PREFERENCE(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CDMA_QUERY_ROAMING_PREFERENCE] = function REQUEST_CDMA_QUERY_ROAMING_PREFERENCE(length, options) { - if (!options.errorMsg) { - options.mode = this.context.Buf.readInt32List()[0]; - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_TTY_MODE] = null; -RilObject.prototype[REQUEST_QUERY_TTY_MODE] = null; -RilObject.prototype[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE] = function REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE] = function REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let enabled = this.context.Buf.readInt32List(); - options.enabled = enabled[0] ? true : false; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_CDMA_FLASH] = function REQUEST_CDMA_FLASH(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_CDMA_BURST_DTMF] = null; -RilObject.prototype[REQUEST_CDMA_VALIDATE_AND_WRITE_AKEY] = null; -RilObject.prototype[REQUEST_CDMA_SEND_SMS] = function REQUEST_CDMA_SEND_SMS(length, options) { - this._processSmsSendResult(length, options); -}; -RilObject.prototype[REQUEST_CDMA_SMS_ACKNOWLEDGE] = null; -RilObject.prototype[REQUEST_GSM_GET_BROADCAST_SMS_CONFIG] = null; -RilObject.prototype[REQUEST_GSM_SET_BROADCAST_SMS_CONFIG] = function REQUEST_GSM_SET_BROADCAST_SMS_CONFIG(length, options) { - if (options.errorMsg) { - return; - } - this.setSmsBroadcastActivation(true); -}; -RilObject.prototype[REQUEST_GSM_SMS_BROADCAST_ACTIVATION] = null; -RilObject.prototype[REQUEST_CDMA_GET_BROADCAST_SMS_CONFIG] = null; -RilObject.prototype[REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG] = function REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG(length, options) { - if (options.errorMsg) { - return; - } - this.setSmsBroadcastActivation(true); -}; -RilObject.prototype[REQUEST_CDMA_SMS_BROADCAST_ACTIVATION] = null; -RilObject.prototype[REQUEST_CDMA_SUBSCRIPTION] = function REQUEST_CDMA_SUBSCRIPTION(length, options) { - if (options.errorMsg) { - return; - } - - let result = this.context.Buf.readStringList(); - - this.iccInfo.mdn = result[0]; - // The result[1] is Home SID. (Already be handled in readCDMAHome()) - // The result[2] is Home NID. (Already be handled in readCDMAHome()) - // The result[3] is MIN. - this.iccInfo.prlVersion = parseInt(result[4], 10); - - this.context.ICCUtilsHelper.handleICCInfoChange(); -}; -RilObject.prototype[REQUEST_CDMA_WRITE_SMS_TO_RUIM] = null; -RilObject.prototype[REQUEST_CDMA_DELETE_SMS_ON_RUIM] = null; -RilObject.prototype[REQUEST_DEVICE_IDENTITY] = function REQUEST_DEVICE_IDENTITY(length, options) { - if (options.errorMsg) { - this.context.debug("Failed to get device identities:" + options.errorMsg); - return; - } - - let result = this.context.Buf.readStringList(); - this.deviceIdentities = { - imei: result[0] || null, - imeisv: result[1] || null, - esn: result[2] || null, - meid: result[3] || null, - }; - - this.sendChromeMessage({ - rilMessageType: "deviceidentitieschange", - deviceIdentities: this.deviceIdentities - }); -}; -RilObject.prototype[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE] = function REQUEST_EXIT_EMERGENCY_CALLBACK_MODE(length, options) { - if (options.internal) { - return; - } - - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_SMSC_ADDRESS] = function REQUEST_GET_SMSC_ADDRESS(length, options) { - if (!options.rilMessageType || options.rilMessageType !== "getSmscAddress") { - return; - } - - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let tosca = TOA_UNKNOWN; - let smsc = ""; - let Buf = this.context.Buf; - if (RILQUIRKS_SMSC_ADDRESS_FORMAT === "pdu") { - let pduHelper = this.context.GsmPDUHelper; - let strlen = Buf.readInt32(); - let length = pduHelper.readHexOctet(); - - // As defined in |8.2.5.2 Destination address element| of 3GPP TS 24.011, - // the value of length field can not exceed 11. Since the content might be - // filled with 12 'F' when SMSC is cleared, we don't parse the TOA and - // address fields if reported length exceeds 11 here. Instead, keep the - // default value (TOA_UNKNOWN with an empty address) in this case. - const MAX_LENGTH = 11 - if (length <= MAX_LENGTH) { - tosca = pduHelper.readHexOctet(); - - // Read and covert the decimal values back to special BCD digits defined in - // |Called party BCD number| of 3GPP TS 24.008 (refer the following table). - // - // +=========+=======+=====+ - // | value | digit | hex | - // +======================== - // | 1 0 1 0 | * | 0xA | - // | 1 0 1 1 | # | 0xB | - // | 1 1 0 0 | a | 0xC | - // | 1 1 0 1 | b | 0xD | - // | 1 1 1 0 | c | 0xE | - // +=========+=======+=====+ - smsc = pduHelper.readSwappedNibbleBcdString(length - 1, true) - .replace(/a/ig, "*") - .replace(/b/ig, "#") - .replace(/c/ig, "a") - .replace(/d/ig, "b") - .replace(/e/ig, "c"); - - Buf.readStringDelimiter(strlen); - } - } else /* RILQUIRKS_SMSC_ADDRESS_FORMAT === "text" */ { - let text = Buf.readString(); - let segments = text.split(",", 2); - // Parse TOA only if it presents since some devices might omit the TOA - // segment in the reported SMSC address. If TOA does not present, keep the - // default value TOA_UNKNOWN. - if (segments.length === 2) { - tosca = this.parseInt(segments[1], TOA_UNKNOWN, 10); - } - - smsc = segments[0].replace(/\"/g, ""); - } - - // Convert the NPI value to the corresponding index of CALLED_PARTY_BCD_NPI - // array. If the value does not present in the array, use - // CALLED_PARTY_BCD_NPI_ISDN. - let npi = CALLED_PARTY_BCD_NPI.indexOf(tosca & 0xf); - if (npi === -1) { - npi = CALLED_PARTY_BCD_NPI.indexOf(CALLED_PARTY_BCD_NPI_ISDN); - } - - // Extract TON. - let ton = (tosca & 0x70) >> 4; - - // Ensure + sign if TON is international, and vice versa. - const TON_INTERNATIONAL = (TOA_INTERNATIONAL & 0x70) >> 4; - if (ton === TON_INTERNATIONAL && smsc.charAt(0) !== "+") { - smsc = "+" + smsc; - } else if (smsc.charAt(0) === "+" && ton !== TON_INTERNATIONAL) { - if (DEBUG) { - this.context.debug("SMSC address number begins with '+' while the TON is not international. Change TON to international."); - } - ton = TON_INTERNATIONAL; - } - - options.smscAddress = smsc; - options.typeOfNumber = ton; - options.numberPlanIdentification = npi; - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SET_SMSC_ADDRESS] = function REQUEST_SET_SMSC_ADDRESS(length, options) { - if (!options.rilMessageType || options.rilMessageType !== "setSmscAddress") { - return; - } - - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_REPORT_SMS_MEMORY_STATUS] = function REQUEST_REPORT_SMS_MEMORY_STATUS(length, options) { - this.pendingToReportSmsMemoryStatus = !!options.errorMsg; -}; -RilObject.prototype[REQUEST_REPORT_STK_SERVICE_IS_RUNNING] = null; -RilObject.prototype[REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE] = null; -RilObject.prototype[REQUEST_ISIM_AUTHENTICATION] = null; -RilObject.prototype[REQUEST_ACKNOWLEDGE_INCOMING_GSM_SMS_WITH_PDU] = null; -RilObject.prototype[REQUEST_STK_SEND_ENVELOPE_WITH_STATUS] = function REQUEST_STK_SEND_ENVELOPE_WITH_STATUS(length, options) { - if (options.errorMsg) { - this.acknowledgeGsmSms(false, PDU_FCS_UNSPECIFIED); - return; - } - - let Buf = this.context.Buf; - let sw1 = Buf.readInt32(); - let sw2 = Buf.readInt32(); - if ((sw1 == ICC_STATUS_SAT_BUSY) && (sw2 === 0x00)) { - this.acknowledgeGsmSms(false, PDU_FCS_USAT_BUSY); - return; - } - - let success = ((sw1 == ICC_STATUS_NORMAL_ENDING) && (sw2 === 0x00)) - || (sw1 == ICC_STATUS_NORMAL_ENDING_WITH_EXTRA); - - let messageStringLength = Buf.readInt32(); // In semi-octets - let responsePduLen = messageStringLength / 2; // In octets - if (!responsePduLen) { - this.acknowledgeGsmSms(success, success ? PDU_FCS_OK - : PDU_FCS_USIM_DATA_DOWNLOAD_ERROR); - return; - } - - this.acknowledgeIncomingGsmSmsWithPDU(success, responsePduLen, options); -}; -RilObject.prototype[REQUEST_VOICE_RADIO_TECH] = function REQUEST_VOICE_RADIO_TECH(length, options) { - if (options.errorMsg) { - if (DEBUG) { - this.context.debug("Error when getting voice radio tech: " + - options.errorMsg); - } - return; - } - let radioTech = this.context.Buf.readInt32List(); - this._processRadioTech(radioTech[0]); -}; -RilObject.prototype[REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE] = null; -RilObject.prototype[REQUEST_SET_INITIAL_ATTACH_APN] = null; -RilObject.prototype[REQUEST_IMS_REGISTRATION_STATE] = null; -RilObject.prototype[REQUEST_IMS_SEND_SMS] = null; -RilObject.prototype[REQUEST_SIM_TRANSMIT_APDU_BASIC] = null; -RilObject.prototype[REQUEST_SIM_OPEN_CHANNEL] = function REQUEST_SIM_OPEN_CHANNEL(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - options.channel = this.context.Buf.readInt32List()[0]; - // onwards may optionally contain the select response for the open channel - // command with one byte per integer. - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_SIM_CLOSE_CHANNEL] = function REQUEST_SIM_CLOSE_CHANNEL(length, options) { - this.sendDefaultResponse(options); -}; -RilObject.prototype[REQUEST_SIM_TRANSMIT_APDU_CHANNEL] = function REQUEST_SIM_TRANSMIT_APDU_CHANNEL(length, options) { - if (options.errorMsg) { - this.sendChromeMessage(options); - return; - } - - let Buf = this.context.Buf; - options.sw1 = Buf.readInt32(); - options.sw2 = Buf.readInt32(); - options.simResponse = Buf.readString(); - if (DEBUG) { - this.context.debug("Setting return values for RIL[REQUEST_SIM_TRANSMIT_APDU_CHANNEL]: [" + - options.sw1 + "," + - options.sw2 + ", " + - options.simResponse + "]"); - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_NV_READ_ITEM] = null; -RilObject.prototype[REQUEST_NV_WRITE_ITEM] = null; -RilObject.prototype[REQUEST_NV_WRITE_CDMA_PRL] = null; -RilObject.prototype[REQUEST_NV_RESET_CONFIG] = null; -RilObject.prototype[REQUEST_SET_UICC_SUBSCRIPTION] = function REQUEST_SET_UICC_SUBSCRIPTION(length, options) { - // Resend data subscription after uicc subscription. - if (this._attachDataRegistration) { - this.setDataRegistration({attach: true}); - } -}; -RilObject.prototype[REQUEST_ALLOW_DATA] = null; -RilObject.prototype[REQUEST_GET_HARDWARE_CONFIG] = null; -RilObject.prototype[REQUEST_SIM_AUTHENTICATION] = null; -RilObject.prototype[REQUEST_GET_DC_RT_INFO] = null; -RilObject.prototype[REQUEST_SET_DC_RT_INFO_RATE] = null; -RilObject.prototype[REQUEST_SET_DATA_PROFILE] = null; -RilObject.prototype[REQUEST_SHUTDOWN] = null; -RilObject.prototype[REQUEST_SET_DATA_SUBSCRIPTION] = function REQUEST_SET_DATA_SUBSCRIPTION(length, options) { - if (!options.rilMessageType) { - // The request was made by ril_worker itself. Don't report. - return; - } - this.sendChromeMessage(options); -}; -RilObject.prototype[REQUEST_GET_UNLOCK_RETRY_COUNT] = function REQUEST_GET_UNLOCK_RETRY_COUNT(length, options) { - options.retryCount = length ? this.context.Buf.readInt32List()[0] : -1; - this.sendChromeMessage(options); -}; -RilObject.prototype[RIL_REQUEST_GPRS_ATTACH] = function RIL_REQUEST_GPRS_ATTACH(length, options) { - if (!options.rilMessageType) { - // The request was made by ril_worker itself. Don't report. - return; - } - this.sendChromeMessage(options); -}; -RilObject.prototype[RIL_REQUEST_GPRS_DETACH] = function RIL_REQUEST_GPRS_DETACH(length, options) { - this.sendChromeMessage(options); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED] = function UNSOLICITED_RESPONSE_RADIO_STATE_CHANGED() { - let radioState = this.context.Buf.readInt32(); - let newState; - switch (radioState) { - case RADIO_STATE_UNAVAILABLE: - newState = GECKO_RADIOSTATE_UNKNOWN; - break; - case RADIO_STATE_OFF: - newState = GECKO_RADIOSTATE_DISABLED; - break; - default: - newState = GECKO_RADIOSTATE_ENABLED; - } - - if (DEBUG) { - this.context.debug("Radio state changed from '" + this.radioState + - "' to '" + newState + "'"); - } - if (this.radioState == newState) { - return; - } - - if (radioState !== RADIO_STATE_UNAVAILABLE) { - // Retrieve device identities once radio is available. - this.getDeviceIdentity(); - } - - if (radioState == RADIO_STATE_ON) { - // This value is defined in RIL v7, we will retrieve radio tech by another - // request. We leave _isCdma untouched, and it will be set once we get the - // radio technology. - this._waitingRadioTech = true; - this.getVoiceRadioTechnology(); - } - - if ((this.radioState == GECKO_RADIOSTATE_UNKNOWN || - this.radioState == GECKO_RADIOSTATE_DISABLED) && - newState == GECKO_RADIOSTATE_ENABLED) { - // The radio became available, let's get its info. - this.getBasebandVersion(); - this.updateCellBroadcastConfig(); - if ((RILQUIRKS_DATA_REGISTRATION_ON_DEMAND || - RILQUIRKS_SUBSCRIPTION_CONTROL) && - this._attachDataRegistration) { - this.setDataRegistration({attach: true}); - } - - if (this.pendingToReportSmsMemoryStatus) { - this._updateSmsMemoryStatus(); - } - } - - this.radioState = newState; - this.sendChromeMessage({ - rilMessageType: "radiostatechange", - radioState: newState - }); - - // If the radio is up and on, so let's query the card state. - // On older RILs only if the card is actually ready, though. - // If _waitingRadioTech is set, we don't need to get icc status now. - if (radioState == RADIO_STATE_UNAVAILABLE || - radioState == RADIO_STATE_OFF || - this._waitingRadioTech) { - return; - } - this.getICCStatus(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_CALL_STATE_CHANGED] = function UNSOLICITED_RESPONSE_CALL_STATE_CHANGED() { - this.getCurrentCalls(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED] = function UNSOLICITED_RESPONSE_VOICE_NETWORK_STATE_CHANGED() { - if (DEBUG) { - this.context.debug("Network state changed, re-requesting phone state and " + - "ICC status"); - } - this.getICCStatus(); - this.requestNetworkInfo(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_SMS] = function UNSOLICITED_RESPONSE_NEW_SMS(length) { - let [message, result] = this.context.GsmPDUHelper.processReceivedSms(length); - - if (message) { - result = this._processSmsMultipart(message); - } - - if (result == PDU_FCS_RESERVED || result == MOZ_FCS_WAIT_FOR_EXPLICIT_ACK) { - return; - } - - // Not reserved FCS values, send ACK now. - this.acknowledgeGsmSms(result == PDU_FCS_OK, result); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT] = function UNSOLICITED_RESPONSE_NEW_SMS_STATUS_REPORT(length) { - let result = this._processSmsStatusReport(length); - this.acknowledgeGsmSms(result == PDU_FCS_OK, result); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM] = function UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM(length) { - let recordNumber = this.context.Buf.readInt32List()[0]; - - this.context.SimRecordHelper.readSMS( - recordNumber, - function onsuccess(message) { - if (message && message.simStatus === 3) { //New Unread SMS - this._processSmsMultipart(message); - } - }.bind(this), - function onerror(errorMsg) { - if (DEBUG) { - this.context.debug("Failed to Read NEW SMS on SIM #" + recordNumber + - ", errorMsg: " + errorMsg); - } - }); -}; -RilObject.prototype[UNSOLICITED_ON_USSD] = function UNSOLICITED_ON_USSD() { - let [typeCode, message] = this.context.Buf.readStringList(); - if (DEBUG) { - this.context.debug("On USSD. Type Code: " + typeCode + " Message: " + message); - } - - this.sendChromeMessage({rilMessageType: "ussdreceived", - message: message, - // Per ril.h the USSD session is assumed to persist if - // the type code is "1", otherwise the current session - // (if any) is assumed to have terminated. - sessionEnded: typeCode !== "1"}); -}; -RilObject.prototype[UNSOLICITED_ON_USSD_REQUEST] = null; -RilObject.prototype[UNSOLICITED_NITZ_TIME_RECEIVED] = function UNSOLICITED_NITZ_TIME_RECEIVED() { - let dateString = this.context.Buf.readString(); - - // The data contained in the NITZ message is - // in the form "yy/mm/dd,hh:mm:ss(+/-)tz,dt" - // for example: 12/02/16,03:36:08-20,00,310410 - // See also bug 714352 - Listen for NITZ updates from rild. - - if (DEBUG) this.context.debug("DateTimeZone string " + dateString); - - let now = Date.now(); - - let year = parseInt(dateString.substr(0, 2), 10); - let month = parseInt(dateString.substr(3, 2), 10); - let day = parseInt(dateString.substr(6, 2), 10); - let hours = parseInt(dateString.substr(9, 2), 10); - let minutes = parseInt(dateString.substr(12, 2), 10); - let seconds = parseInt(dateString.substr(15, 2), 10); - // Note that |tz| is in 15-min units. - let tz = parseInt(dateString.substr(17, 3), 10); - // Note that |dst| is in 1-hour units and is already applied in |tz|. - let dst = parseInt(dateString.substr(21, 2), 10); - - let timeInMS = Date.UTC(year + PDU_TIMESTAMP_YEAR_OFFSET, month - 1, day, - hours, minutes, seconds); - - if (isNaN(timeInMS)) { - if (DEBUG) this.context.debug("NITZ failed to convert date"); - return; - } - - this.sendChromeMessage({rilMessageType: "nitzTime", - networkTimeInMS: timeInMS, - networkTimeZoneInMinutes: -(tz * 15), - networkDSTInMinutes: -(dst * 60), - receiveTimeInMS: now}); -}; - -RilObject.prototype[UNSOLICITED_SIGNAL_STRENGTH] = function UNSOLICITED_SIGNAL_STRENGTH(length) { - this[REQUEST_SIGNAL_STRENGTH](length, {}); -}; -RilObject.prototype[UNSOLICITED_DATA_CALL_LIST_CHANGED] = function UNSOLICITED_DATA_CALL_LIST_CHANGED(length) { - this[REQUEST_DATA_CALL_LIST](length, {}); -}; -RilObject.prototype[UNSOLICITED_SUPP_SVC_NOTIFICATION] = function UNSOLICITED_SUPP_SVC_NOTIFICATION(length) { - let Buf = this.context.Buf; - let info = {}; - info.notificationType = Buf.readInt32(); - info.code = Buf.readInt32(); - info.index = Buf.readInt32(); - info.type = Buf.readInt32(); - info.number = Buf.readString(); - - this._processSuppSvcNotification(info); -}; - -RilObject.prototype[UNSOLICITED_STK_SESSION_END] = function UNSOLICITED_STK_SESSION_END() { - this.sendChromeMessage({rilMessageType: "stksessionend"}); -}; -RilObject.prototype[UNSOLICITED_STK_PROACTIVE_COMMAND] = function UNSOLICITED_STK_PROACTIVE_COMMAND() { - this.processStkProactiveCommand(); -}; -RilObject.prototype[UNSOLICITED_STK_EVENT_NOTIFY] = function UNSOLICITED_STK_EVENT_NOTIFY() { - this.processStkProactiveCommand(); -}; -RilObject.prototype[UNSOLICITED_STK_CALL_SETUP] = null; -RilObject.prototype[UNSOLICITED_SIM_SMS_STORAGE_FULL] = null; -RilObject.prototype[UNSOLICITED_SIM_REFRESH] = null; -RilObject.prototype[UNSOLICITED_CALL_RING] = function UNSOLICITED_CALL_RING() { - let Buf = this.context.Buf; - let info = {rilMessageType: "callRing"}; - let isCDMA = false; //XXX TODO hard-code this for now - if (isCDMA) { - info.isPresent = Buf.readInt32(); - info.signalType = Buf.readInt32(); - info.alertPitch = Buf.readInt32(); - info.signal = Buf.readInt32(); - } - // At this point we don't know much other than the fact there's an incoming - // call, but that's enough to bring up the Phone app already. We'll know - // details once we get a call state changed notification and can then - // dispatch DOM events etc. - this.sendChromeMessage(info); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_SIM_STATUS_CHANGED] = function UNSOLICITED_RESPONSE_SIM_STATUS_CHANGED() { - this.getICCStatus(); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_CDMA_NEW_SMS] = function UNSOLICITED_RESPONSE_CDMA_NEW_SMS(length) { - let [message, result] = this.context.CdmaPDUHelper.processReceivedSms(length); - - if (message) { - if (message.teleservice === PDU_CDMA_MSG_TELESERIVCIE_ID_WAP) { - result = this._processCdmaSmsWapPush(message); - } else if (message.subMsgType === PDU_CDMA_MSG_TYPE_DELIVER_ACK) { - result = this._processCdmaSmsStatusReport(message); - } else { - result = this._processSmsMultipart(message); - } - } - - if (result == PDU_FCS_RESERVED || result == MOZ_FCS_WAIT_FOR_EXPLICIT_ACK) { - return; - } - - // Not reserved FCS values, send ACK now. - this.acknowledgeCdmaSms(result == PDU_FCS_OK, result); -}; -RilObject.prototype[UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS] = function UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS(length) { - let message; - try { - message = - this.context.GsmPDUHelper.readCbMessage(this.context.Buf.readInt32()); - - // "Data-Download" message is expected to be handled by the modem. - // Ignore it here to prevent any garbage messages to be displayed. - // See 9.4.1.2.2 Message Identifier of TS 32.041 for the range of - // Message-identifier of the Data-Download CB messages. - if (message.messageId >= 0x1000 && message.messageId <= 0x10FF) { - if (DEBUG) { - this.context.debug("Ignore a Data-Download message, messageId: " + - message.messageId); - } - return; - } - } catch (e) { - if (DEBUG) { - this.context.debug("Failed to parse Cell Broadcast message: " + e); - } - return; - } - - message = this._processReceivedSmsCbPage(message); - if (!message) { - return; - } - - // Bug 1235697, failed to deactivate CBS in some modem. - // Workaround it according to the settings. - // Note: ETWS/CMAS/PWS can be received even disabled. - // It will be displayed according to the setting in application layer. - if (this.cellBroadcastDisabled && ( - !(message.messageId >= 0x1100 && message.messageId <= 0x1107) && // ETWS - !(message.messageId >= 0x1112 && message.messageId <= 0x112F) && // CMAS - !(message.messageId >= 0x1130 && message.messageId <= 0x18FF) // PWS - )) { - if (DEBUG) { - this.context.debug("Ignore a CB message when disabled, messageId: " + - message.messageId); - } - return; - } - - message.rilMessageType = "cellbroadcast-received"; - this.sendChromeMessage(message); -}; -RilObject.prototype[UNSOLICITED_CDMA_RUIM_SMS_STORAGE_FULL] = null; -RilObject.prototype[UNSOLICITED_RESTRICTED_STATE_CHANGED] = null; -RilObject.prototype[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE] = function UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE() { - this._handleChangedEmergencyCbMode(true); -}; -RilObject.prototype[UNSOLICITED_CDMA_CALL_WAITING] = function UNSOLICITED_CDMA_CALL_WAITING(length) { - let Buf = this.context.Buf; - let call = {}; - call.number = Buf.readString(); - call.numberPresentation = Buf.readInt32(); - call.name = Buf.readString(); - call.namePresentation = Buf.readInt32(); - call.isPresent = Buf.readInt32(); - call.signalType = Buf.readInt32(); - call.alertPitch = Buf.readInt32(); - call.signal = Buf.readInt32(); - this.sendChromeMessage({rilMessageType: "cdmaCallWaiting", - waitingCall: call}); -}; -RilObject.prototype[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = function UNSOLICITED_CDMA_OTA_PROVISION_STATUS() { - let status = - CDMA_OTA_PROVISION_STATUS_TO_GECKO[this.context.Buf.readInt32List()[0]]; - if (!status) { - return; - } - this.sendChromeMessage({rilMessageType: "otastatuschange", - status: status}); -}; -RilObject.prototype[UNSOLICITED_CDMA_INFO_REC] = function UNSOLICITED_CDMA_INFO_REC(length) { - this.sendChromeMessage({ - rilMessageType: "cdma-info-rec-received", - records: this.context.CdmaPDUHelper.decodeInformationRecord() - }); -}; -RilObject.prototype[UNSOLICITED_OEM_HOOK_RAW] = null; -RilObject.prototype[UNSOLICITED_RINGBACK_TONE] = null; -RilObject.prototype[UNSOLICITED_RESEND_INCALL_MUTE] = null; -RilObject.prototype[UNSOLICITED_CDMA_SUBSCRIPTION_SOURCE_CHANGED] = null; -RilObject.prototype[UNSOLICITED_CDMA_PRL_CHANGED] = function UNSOLICITED_CDMA_PRL_CHANGED(length) { - let version = this.context.Buf.readInt32List()[0]; - if (version !== this.iccInfo.prlVersion) { - this.iccInfo.prlVersion = version; - this.context.ICCUtilsHelper.handleICCInfoChange(); - } -}; -RilObject.prototype[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE] = function UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE() { - this._handleChangedEmergencyCbMode(false); -}; -RilObject.prototype[UNSOLICITED_RIL_CONNECTED] = function UNSOLICITED_RIL_CONNECTED(length) { - // Prevent response id collision between UNSOLICITED_RIL_CONNECTED and - // UNSOLICITED_VOICE_RADIO_TECH_CHANGED for Akami on gingerbread branch. - if (!length) { - return; - } - - this.version = this.context.Buf.readInt32List()[0]; - if (DEBUG) { - this.context.debug("Detected RIL version " + this.version); - } - - this.initRILState(); - // rild might have restarted, ensure data call list. - this.getDataCallList(); - // Always ensure that we are not in emergency callback mode when init. - this.exitEmergencyCbMode(); - // Reset radio in the case that b2g restart (or crash). - this.setRadioEnabled({enabled: false}); -}; -RilObject.prototype[UNSOLICITED_VOICE_RADIO_TECH_CHANGED] = function UNSOLICITED_VOICE_RADIO_TECH_CHANGED(length) { - // This unsolicited response will be sent when the technology of a multi-tech - // modem is changed, ex. switch between gsm and cdma. - // TODO: We may need to do more on updating data when switching between gsm - // and cdma mode, e.g. IMEI, ESN, iccInfo, iccType ... etc. - // See Bug 866038. - this._processRadioTech(this.context.Buf.readInt32List()[0]); -}; -RilObject.prototype[UNSOLICITED_CELL_INFO_LIST] = null; -RilObject.prototype[UNSOLICITED_RESPONSE_IMS_NETWORK_STATE_CHANGED] = null; -RilObject.prototype[UNSOLICITED_UICC_SUBSCRIPTION_STATUS_CHANGED] = null; -RilObject.prototype[UNSOLICITED_SRVCC_STATE_NOTIFY] = null; -RilObject.prototype[UNSOLICITED_HARDWARE_CONFIG_CHANGED] = null; -RilObject.prototype[UNSOLICITED_DC_RT_INFO_CHANGED] = null; - -/** - * This object exposes the functionality to parse and serialize PDU strings - * - * A PDU is a string containing a series of hexadecimally encoded octets - * or nibble-swapped binary-coded decimals (BCDs). It contains not only the - * message text but information about the sender, the SMS service center, - * timestamp, etc. - */ -function GsmPDUHelperObject(aContext) { - this.context = aContext; -} -GsmPDUHelperObject.prototype = { - context: null, - - /** - * Read one character (2 bytes) from a RIL string and decode as hex. - * - * @return the nibble as a number. - */ - readHexNibble: function() { - let nibble = this.context.Buf.readUint16(); - if (nibble >= 48 && nibble <= 57) { - nibble -= 48; // ASCII '0'..'9' - } else if (nibble >= 65 && nibble <= 70) { - nibble -= 55; // ASCII 'A'..'F' - } else if (nibble >= 97 && nibble <= 102) { - nibble -= 87; // ASCII 'a'..'f' - } else { - throw "Found invalid nibble during PDU parsing: " + - String.fromCharCode(nibble); - } - return nibble; - }, - - /** - * Encode a nibble as one hex character in a RIL string (2 bytes). - * - * @param nibble - * The nibble to encode (represented as a number) - */ - writeHexNibble: function(nibble) { - nibble &= 0x0f; - if (nibble < 10) { - nibble += 48; // ASCII '0' - } else { - nibble += 55; // ASCII 'A' - } - this.context.Buf.writeUint16(nibble); - }, - - /** - * Read a hex-encoded octet (two nibbles). - * - * @return the octet as a number. - */ - readHexOctet: function() { - return (this.readHexNibble() << 4) | this.readHexNibble(); - }, - - /** - * Write an octet as two hex-encoded nibbles. - * - * @param octet - * The octet (represented as a number) to encode. - */ - writeHexOctet: function(octet) { - this.writeHexNibble(octet >> 4); - this.writeHexNibble(octet); - }, - - /** - * Read an array of hex-encoded octets. - */ - readHexOctetArray: function(length) { - let array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = this.readHexOctet(); - } - return array; - }, - - /** - * Helper to write data into a temporary buffer for easier length encoding when - * the number of octets for the length encoding is varied. - * - * @param writeFunction - * Function of how the data to be written into temporary buffer. - * - * @return array of written octets. - **/ - writeWithBuffer: function(writeFunction) { - let buf = []; - let writeHexOctet = this.writeHexOctet; - this.writeHexOctet = function(octet) { - buf.push(octet); - } - - try { - writeFunction(); - } catch (e) { - if (DEBUG) { - debug("Error when writeWithBuffer: " + e); - } - buf = []; - } finally { - this.writeHexOctet = writeHexOctet; - } - - return buf; - }, - - /** - * Convert an octet (number) to a BCD number. - * - * Any nibbles that are not in the BCD range count as 0. - * - * @param octet - * The octet (a number, as returned by getOctet()) - * - * @return the corresponding BCD number. - */ - octetToBCD: function(octet) { - return ((octet & 0xf0) <= 0x90) * ((octet >> 4) & 0x0f) + - ((octet & 0x0f) <= 0x09) * (octet & 0x0f) * 10; - }, - - /** - * Convert a BCD number to an octet (number) - * - * Only take two digits with absolute value. - * - * @param bcd - * - * @return the corresponding octet. - */ - BCDToOctet: function(bcd) { - bcd = Math.abs(bcd); - return ((bcd % 10) << 4) + (Math.floor(bcd / 10) % 10); - }, - - /** - * Convert a semi-octet (number) to a GSM BCD char, or return empty - * string if invalid semiOctet and suppressException is set to true. - * - * @param semiOctet - * Nibble to be converted to. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return GSM BCD char, or empty string. - */ - bcdChars: "0123456789", - semiOctetToBcdChar: function(semiOctet, suppressException) { - if (semiOctet >= this.bcdChars.length) { - if (suppressException) { - return ""; - } else { - throw new RangeError(); - } - } - - return this.bcdChars.charAt(semiOctet); - }, - - /** - * Convert a semi-octet (number) to a GSM extended BCD char, or return empty - * string if invalid semiOctet and suppressException is set to true. - * - * @param semiOctet - * Nibble to be converted to. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return GSM extended BCD char, or empty string. - */ - extendedBcdChars: "0123456789*#,;", - semiOctetToExtendedBcdChar: function(semiOctet, suppressException) { - if (semiOctet >= this.extendedBcdChars.length) { - if (suppressException) { - return ""; - } else { - throw new RangeError(); - } - } - - return this.extendedBcdChars.charAt(semiOctet); - }, - - /** - * Convert string to a GSM extended BCD string - */ - stringToExtendedBcd: function(string) { - return string.replace(/[^0-9*#,]/g, "") - .replace(/\*/g, "a") - .replace(/\#/g, "b") - .replace(/\,/g, "c"); - }, - - /** - * Read a *swapped nibble* binary coded decimal (BCD) - * - * @param pairs - * Number of nibble *pairs* to read. - * - * @return the decimal as a number. - */ - readSwappedNibbleBcdNum: function(pairs) { - let number = 0; - for (let i = 0; i < pairs; i++) { - let octet = this.readHexOctet(); - // Ignore 'ff' octets as they're often used as filler. - if (octet == 0xff) { - continue; - } - // If the first nibble is an "F" , only the second nibble is to be taken - // into account. - if ((octet & 0xf0) == 0xf0) { - number *= 10; - number += octet & 0x0f; - continue; - } - number *= 100; - number += this.octetToBCD(octet); - } - return number; - }, - - /** - * Read a *swapped nibble* binary coded decimal (BCD) string - * - * @param pairs - * Number of nibble *pairs* to read. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return The BCD string. - */ - readSwappedNibbleBcdString: function(pairs, suppressException) { - let str = ""; - for (let i = 0; i < pairs; i++) { - let nibbleH = this.readHexNibble(); - let nibbleL = this.readHexNibble(); - if (nibbleL == 0x0F) { - break; - } - - str += this.semiOctetToBcdChar(nibbleL, suppressException); - if (nibbleH != 0x0F) { - str += this.semiOctetToBcdChar(nibbleH, suppressException); - } - } - - return str; - }, - - /** - * Read a *swapped nibble* extended binary coded decimal (BCD) string - * - * @param pairs - * Number of nibble *pairs* to read. - * @param suppressException [optional] - * Suppress exception if invalid semiOctet and suppressException is set - * to true. - * - * @return The BCD string. - */ - readSwappedNibbleExtendedBcdString: function(pairs, suppressException) { - let str = ""; - for (let i = 0; i < pairs; i++) { - let nibbleH = this.readHexNibble(); - let nibbleL = this.readHexNibble(); - if (nibbleL == 0x0F) { - break; - } - - str += this.semiOctetToExtendedBcdChar(nibbleL, suppressException); - if (nibbleH != 0x0F) { - str += this.semiOctetToExtendedBcdChar(nibbleH, suppressException); - } - } - - return str; - }, - - /** - * Write numerical data as swapped nibble BCD. - * - * @param data - * Data to write (as a string or a number) - */ - writeSwappedNibbleBCD: function(data) { - data = data.toString(); - if (data.length % 2) { - data += "F"; - } - let Buf = this.context.Buf; - for (let i = 0; i < data.length; i += 2) { - Buf.writeUint16(data.charCodeAt(i + 1)); - Buf.writeUint16(data.charCodeAt(i)); - } - }, - - /** - * Write numerical data as swapped nibble BCD. - * If the number of digit of data is even, add '0' at the beginning. - * - * @param data - * Data to write (as a string or a number) - */ - writeSwappedNibbleBCDNum: function(data) { - data = data.toString(); - if (data.length % 2) { - data = "0" + data; - } - let Buf = this.context.Buf; - for (let i = 0; i < data.length; i += 2) { - Buf.writeUint16(data.charCodeAt(i + 1)); - Buf.writeUint16(data.charCodeAt(i)); - } - }, - - /** - * Read user data, convert to septets, look up relevant characters in a - * 7-bit alphabet, and construct string. - * - * @param length - * Number of septets to read (*not* octets) - * @param paddingBits - * Number of padding bits in the first byte of user data. - * @param langIndex - * Table index used for normal 7-bit encoded character lookup. - * @param langShiftIndex - * Table index used for escaped 7-bit encoded character lookup. - * - * @return a string. - */ - readSeptetsToString: function(length, paddingBits, langIndex, langShiftIndex) { - let ret = ""; - let byteLength = Math.ceil((length * 7 + paddingBits) / 8); - - /** - * |<- last byte in header ->| - * |<- incompleteBits ->|<- last header septet->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * |<- 1st byte in user data ->| - * |<- data septet 1 ->|<-paddingBits->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * |<- 2nd byte in user data ->| - * |<- data spetet 2 ->|<-ds1->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - */ - let data = 0; - let dataBits = 0; - if (paddingBits) { - data = this.readHexOctet() >> paddingBits; - dataBits = 8 - paddingBits; - --byteLength; - } - - let escapeFound = false; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; - do { - // Read as much as fits in 32bit word - let bytesToRead = Math.min(byteLength, dataBits ? 3 : 4); - for (let i = 0; i < bytesToRead; i++) { - data |= this.readHexOctet() << dataBits; - dataBits += 8; - --byteLength; - } - - // Consume available full septets - for (; dataBits >= 7; dataBits -= 7) { - let septet = data & 0x7F; - data >>>= 7; - - if (escapeFound) { - escapeFound = false; - if (septet == PDU_NL_EXTENDED_ESCAPE) { - // According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On - // receipt of this code, a receiving entity shall display a space - // until another extensiion table is defined." - ret += " "; - } else if (septet == PDU_NL_RESERVED_CONTROL) { - // According to 3GPP TS 23.038 B.2, "This code represents a control - // character and therefore must not be used for language specific - // characters." - ret += " "; - } else { - ret += langShiftTable[septet]; - } - } else if (septet == PDU_NL_EXTENDED_ESCAPE) { - escapeFound = true; - - // is not an effective character - --length; - } else { - ret += langTable[septet]; - } - } - } while (byteLength); - - if (ret.length != length) { - /** - * If num of effective characters does not equal to the length of read - * string, cut the tail off. This happens when the last octet of user - * data has following layout: - * - * |<- penultimate octet in user data ->| - * |<- data septet N ->|<- dsN-1 ->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * |<- last octet in user data ->| - * |<- fill bits ->|<-dsN->| - * +===7===|===6===|===5===|===4===|===3===|===2===|===1===|===0===| - * - * The fill bits in the last octet may happen to form a full septet and - * be appended at the end of result string. - */ - ret = ret.slice(0, length); - } - return ret; - }, - - writeStringAsSeptets: function(message, paddingBits, langIndex, langShiftIndex) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[langIndex]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[langShiftIndex]; - - let dataBits = paddingBits; - let data = 0; - for (let i = 0; i < message.length; i++) { - let c = message.charAt(i); - let septet = langTable.indexOf(c); - if (septet == PDU_NL_EXTENDED_ESCAPE) { - continue; - } - - if (septet >= 0) { - data |= septet << dataBits; - dataBits += 7; - } else { - septet = langShiftTable.indexOf(c); - if (septet == -1) { - throw new Error("'" + c + "' is not in 7 bit alphabet " - + langIndex + ":" + langShiftIndex + "!"); - } - - if (septet == PDU_NL_RESERVED_CONTROL) { - continue; - } - - data |= PDU_NL_EXTENDED_ESCAPE << dataBits; - dataBits += 7; - data |= septet << dataBits; - dataBits += 7; - } - - for (; dataBits >= 8; dataBits -= 8) { - this.writeHexOctet(data & 0xFF); - data >>>= 8; - } - } - - if (dataBits !== 0) { - this.writeHexOctet(data & 0xFF); - } - }, - - writeStringAs8BitUnpacked: function(text) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - let len = text ? text.length : 0; - for (let i = 0; i < len; i++) { - let c = text.charAt(i); - let octet = langTable.indexOf(c); - - if (octet == -1) { - octet = langShiftTable.indexOf(c); - if (octet == -1) { - // Fallback to ASCII space. - octet = langTable.indexOf(' '); - } else { - this.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - } - } - this.writeHexOctet(octet); - } - }, - - /** - * Read user data and decode as a UCS2 string. - * - * @param numOctets - * Number of octets to be read as UCS2 string. - * - * @return a string. - */ - readUCS2String: function(numOctets) { - let str = ""; - let length = numOctets / 2; - for (let i = 0; i < length; ++i) { - let code = (this.readHexOctet() << 8) | this.readHexOctet(); - str += String.fromCharCode(code); - } - - if (DEBUG) this.context.debug("Read UCS2 string: " + str); - - return str; - }, - - /** - * Write user data as a UCS2 string. - * - * @param message - * Message string to encode as UCS2 in hex-encoded octets. - */ - writeUCS2String: function(message) { - for (let i = 0; i < message.length; ++i) { - let code = message.charCodeAt(i); - this.writeHexOctet((code >> 8) & 0xFF); - this.writeHexOctet(code & 0xFF); - } - }, - - /** - * Read 1 + UDHL octets and construct user data header. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.040 9.2.3.24 - */ - readUserDataHeader: function(msg) { - /** - * A header object with properties contained in received message. - * The properties set include: - * - * length: totoal length of the header, default 0. - * langIndex: used locking shift table index, default - * PDU_NL_IDENTIFIER_DEFAULT. - * langShiftIndex: used locking shift table index, default - * PDU_NL_IDENTIFIER_DEFAULT. - * - */ - let header = { - length: 0, - langIndex: PDU_NL_IDENTIFIER_DEFAULT, - langShiftIndex: PDU_NL_IDENTIFIER_DEFAULT - }; - - header.length = this.readHexOctet(); - if (DEBUG) this.context.debug("Read UDH length: " + header.length); - - let dataAvailable = header.length; - while (dataAvailable >= 2) { - let id = this.readHexOctet(); - let length = this.readHexOctet(); - if (DEBUG) this.context.debug("Read UDH id: " + id + ", length: " + length); - - dataAvailable -= 2; - - switch (id) { - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT: { - let ref = this.readHexOctet(); - let max = this.readHexOctet(); - let seq = this.readHexOctet(); - dataAvailable -= 3; - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT: { - let dstp = this.readHexOctet(); - let orip = this.readHexOctet(); - dataAvailable -= 2; - if ((dstp < PDU_APA_RESERVED_8BIT_PORTS) - || (orip < PDU_APA_RESERVED_8BIT_PORTS)) { - // 3GPP TS 23.040 clause 9.2.3.24.3: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - break; - } - header.destinationPort = dstp; - header.originatorPort = orip; - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT: { - let dstp = (this.readHexOctet() << 8) | this.readHexOctet(); - let orip = (this.readHexOctet() << 8) | this.readHexOctet(); - dataAvailable -= 4; - if ((dstp >= PDU_APA_VALID_16BIT_PORTS) || - (orip >= PDU_APA_VALID_16BIT_PORTS)) { - // 3GPP TS 23.040 clause 9.2.3.24.4: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - // Bug 1130292, some carriers set originatorPort to reserved port - // numbers for wap push. We rise this as a warning in debug message - // instead of ingoring this IEI to allow user to receive Wap Push - // under these carriers. - this.context.debug("Warning: Invalid port numbers [dstp, orip]: " + - JSON.stringify([dstp, orip])); - } - header.destinationPort = dstp; - header.originatorPort = orip; - break; - } - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT: { - let ref = (this.readHexOctet() << 8) | this.readHexOctet(); - let max = this.readHexOctet(); - let seq = this.readHexOctet(); - dataAvailable -= 4; - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT: - let langShiftIndex = this.readHexOctet(); - --dataAvailable; - if (langShiftIndex < PDU_NL_SINGLE_SHIFT_TABLES.length) { - header.langShiftIndex = langShiftIndex; - } - break; - case PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT: - let langIndex = this.readHexOctet(); - --dataAvailable; - if (langIndex < PDU_NL_LOCKING_SHIFT_TABLES.length) { - header.langIndex = langIndex; - } - break; - case PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION: - let msgInd = this.readHexOctet() & 0xFF; - let msgCount = this.readHexOctet(); - dataAvailable -= 2; - - - /* - * TS 23.040 V6.8.1 Sec 9.2.3.24.2 - * bits 1 0 : basic message indication type - * bits 4 3 2 : extended message indication type - * bits 6 5 : Profile id - * bit 7 : storage type - */ - let storeType = msgInd & PDU_MWI_STORE_TYPE_BIT; - let mwi = msg.mwi; - if (!mwi) { - mwi = msg.mwi = {}; - } - - if (storeType == PDU_MWI_STORE_TYPE_STORE) { - // Store message because TP_UDH indicates so, note this may override - // the setting in DCS, but that is expected - mwi.discard = false; - } else if (mwi.discard === undefined) { - // storeType == PDU_MWI_STORE_TYPE_DISCARD - // only override mwi.discard here if it hasn't already been set - mwi.discard = true; - } - - mwi.msgCount = msgCount & 0xFF; - mwi.active = mwi.msgCount > 0; - - if (DEBUG) { - this.context.debug("MWI in TP_UDH received: " + JSON.stringify(mwi)); - } - - break; - default: - if (DEBUG) { - this.context.debug("readUserDataHeader: unsupported IEI(" + id + - "), " + length + " bytes."); - } - - // Read out unsupported data - if (length) { - let octets; - if (DEBUG) octets = new Uint8Array(length); - - for (let i = 0; i < length; i++) { - let octet = this.readHexOctet(); - if (DEBUG) octets[i] = octet; - } - dataAvailable -= length; - - if (DEBUG) { - this.context.debug("readUserDataHeader: " + Array.slice(octets)); - } - } - break; - } - } - - if (dataAvailable !== 0) { - throw new Error("Illegal user data header found!"); - } - - msg.header = header; - }, - - /** - * Write out user data header. - * - * @param options - * Options containing information for user data header write-out. The - * `userDataHeaderLength` property must be correctly pre-calculated. - */ - writeUserDataHeader: function(options) { - this.writeHexOctet(options.userDataHeaderLength); - - if (options.segmentMaxSeq > 1) { - if (options.segmentRef16Bit) { - this.writeHexOctet(PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT); - this.writeHexOctet(4); - this.writeHexOctet((options.segmentRef >> 8) & 0xFF); - } else { - this.writeHexOctet(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT); - this.writeHexOctet(3); - } - this.writeHexOctet(options.segmentRef & 0xFF); - this.writeHexOctet(options.segmentMaxSeq & 0xFF); - this.writeHexOctet(options.segmentSeq & 0xFF); - } - - if (options.dcs == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - if (options.langIndex != PDU_NL_IDENTIFIER_DEFAULT) { - this.writeHexOctet(PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT); - this.writeHexOctet(1); - this.writeHexOctet(options.langIndex); - } - - if (options.langShiftIndex != PDU_NL_IDENTIFIER_DEFAULT) { - this.writeHexOctet(PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT); - this.writeHexOctet(1); - this.writeHexOctet(options.langShiftIndex); - } - } - }, - - /** - * Read SM-TL Address. - * - * @param len - * Length of useful semi-octets within the Address-Value field. For - * example, the lenth of "12345" should be 5, and 4 for "1234". - * - * @see 3GPP TS 23.040 9.1.2.5 - */ - readAddress: function(len) { - // Address Length - if (!len || (len < 0)) { - if (DEBUG) { - this.context.debug("PDU error: invalid sender address length: " + len); - } - return null; - } - if (len % 2 == 1) { - len += 1; - } - if (DEBUG) this.context.debug("PDU: Going to read address: " + len); - - // Type-of-Address - let toa = this.readHexOctet(); - let addr = ""; - - if ((toa & 0xF0) == PDU_TOA_ALPHANUMERIC) { - addr = this.readSeptetsToString(Math.floor(len * 4 / 7), 0, - PDU_NL_IDENTIFIER_DEFAULT , PDU_NL_IDENTIFIER_DEFAULT ); - return addr; - } - addr = this.readSwappedNibbleExtendedBcdString(len / 2); - if (addr.length <= 0) { - if (DEBUG) this.context.debug("PDU error: no number provided"); - return null; - } - if ((toa & 0xF0) == (PDU_TOA_INTERNATIONAL)) { - addr = '+' + addr; - } - - return addr; - }, - - /** - * Read TP-Protocol-Indicator(TP-PID). - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.040 9.2.3.9 - */ - readProtocolIndicator: function(msg) { - // `The MS shall interpret reserved, obsolete, or unsupported values as the - // value 00000000 but shall store them exactly as received.` - msg.pid = this.readHexOctet(); - - msg.epid = msg.pid; - switch (msg.epid & 0xC0) { - case 0x40: - // Bit 7..0 = 01xxxxxx - switch (msg.epid) { - case PDU_PID_SHORT_MESSAGE_TYPE_0: - case PDU_PID_ANSI_136_R_DATA: - case PDU_PID_USIM_DATA_DOWNLOAD: - return; - } - break; - } - - msg.epid = PDU_PID_DEFAULT; - }, - - /** - * Read TP-Data-Coding-Scheme(TP-DCS) - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.040 9.2.3.10, 3GPP TS 23.038 4. - */ - readDataCodingScheme: function(msg) { - let dcs = this.readHexOctet(); - if (DEBUG) this.context.debug("PDU: read SMS dcs: " + dcs); - - // No message class by default. - let messageClass = PDU_DCS_MSG_CLASS_NORMAL; - // 7 bit is the default fallback encoding. - let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - switch (dcs & PDU_DCS_CODING_GROUP_BITS) { - case 0x40: // bits 7..4 = 01xx - case 0x50: - case 0x60: - case 0x70: - // Bit 5..0 are coded exactly the same as Group 00xx - case 0x00: // bits 7..4 = 00xx - case 0x10: - case 0x20: - case 0x30: - if (dcs & 0x10) { - messageClass = dcs & PDU_DCS_MSG_CLASS_BITS; - } - switch (dcs & 0x0C) { - case 0x4: - encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET; - break; - case 0x8: - encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET; - break; - } - break; - - case 0xE0: // bits 7..4 = 1110 - encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET; - // Bit 3..0 are coded exactly the same as Message Waiting Indication - // Group 1101. - // Fall through. - case 0xC0: // bits 7..4 = 1100 - case 0xD0: // bits 7..4 = 1101 - // Indiciates voicemail indicator set or clear - let active = (dcs & PDU_DCS_MWI_ACTIVE_BITS) == PDU_DCS_MWI_ACTIVE_VALUE; - - // If TP-UDH is present, these values will be overwritten - switch (dcs & PDU_DCS_MWI_TYPE_BITS) { - case PDU_DCS_MWI_TYPE_VOICEMAIL: - let mwi = msg.mwi; - if (!mwi) { - mwi = msg.mwi = {}; - } - - mwi.active = active; - mwi.discard = (dcs & PDU_DCS_CODING_GROUP_BITS) == 0xC0; - mwi.msgCount = active ? GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN : 0; - - if (DEBUG) { - this.context.debug("MWI in DCS received for voicemail: " + - JSON.stringify(mwi)); - } - break; - case PDU_DCS_MWI_TYPE_FAX: - if (DEBUG) this.context.debug("MWI in DCS received for fax"); - break; - case PDU_DCS_MWI_TYPE_EMAIL: - if (DEBUG) this.context.debug("MWI in DCS received for email"); - break; - default: - if (DEBUG) this.context.debug("MWI in DCS received for \"other\""); - break; - } - break; - - case 0xF0: // bits 7..4 = 1111 - if (dcs & 0x04) { - encoding = PDU_DCS_MSG_CODING_8BITS_ALPHABET; - } - messageClass = dcs & PDU_DCS_MSG_CLASS_BITS; - break; - - default: - // Falling back to default encoding. - break; - } - - msg.dcs = dcs; - msg.encoding = encoding; - msg.messageClass = GECKO_SMS_MESSAGE_CLASSES[messageClass]; - - if (DEBUG) this.context.debug("PDU: message encoding is " + encoding + " bit."); - }, - - /** - * Read GSM TP-Service-Centre-Time-Stamp(TP-SCTS). - * - * @see 3GPP TS 23.040 9.2.3.11 - */ - readTimestamp: function() { - let year = this.readSwappedNibbleBcdNum(1) + PDU_TIMESTAMP_YEAR_OFFSET; - let month = this.readSwappedNibbleBcdNum(1) - 1; - let day = this.readSwappedNibbleBcdNum(1); - let hour = this.readSwappedNibbleBcdNum(1); - let minute = this.readSwappedNibbleBcdNum(1); - let second = this.readSwappedNibbleBcdNum(1); - let timestamp = Date.UTC(year, month, day, hour, minute, second); - - // If the most significant bit of the least significant nibble is 1, - // the timezone offset is negative (fourth bit from the right => 0x08): - // localtime = UTC + tzOffset - // therefore - // UTC = localtime - tzOffset - let tzOctet = this.readHexOctet(); - let tzOffset = this.octetToBCD(tzOctet & ~0x08) * 15 * 60 * 1000; - tzOffset = (tzOctet & 0x08) ? -tzOffset : tzOffset; - timestamp -= tzOffset; - - return timestamp; - }, - - /** - * Write GSM TP-Service-Centre-Time-Stamp(TP-SCTS). - * - * @see 3GPP TS 23.040 9.2.3.11 - */ - writeTimestamp: function(date) { - this.writeSwappedNibbleBCDNum(date.getFullYear() - PDU_TIMESTAMP_YEAR_OFFSET); - - // The value returned by getMonth() is an integer between 0 and 11. - // 0 is corresponds to January, 1 to February, and so on. - this.writeSwappedNibbleBCDNum(date.getMonth() + 1); - this.writeSwappedNibbleBCDNum(date.getDate()); - this.writeSwappedNibbleBCDNum(date.getHours()); - this.writeSwappedNibbleBCDNum(date.getMinutes()); - this.writeSwappedNibbleBCDNum(date.getSeconds()); - - // the value returned by getTimezoneOffset() is the difference, - // in minutes, between UTC and local time. - // For example, if your time zone is UTC+10 (Australian Eastern Standard Time), - // -600 will be returned. - // In TS 23.040 9.2.3.11, the Time Zone field of TP-SCTS indicates - // the different between the local time and GMT. - // And expressed in quarters of an hours. (so need to divid by 15) - let zone = date.getTimezoneOffset() / 15; - let octet = this.BCDToOctet(zone); - - // the bit3 of the Time Zone field represents the algebraic sign. - // (0: positive, 1: negative). - // For example, if the time zone is -0800 GMT, - // 480 will be returned by getTimezoneOffset(). - // In this case, need to mark sign bit as 1. => 0x08 - if (zone > 0) { - octet = octet | 0x08; - } - this.writeHexOctet(octet); - }, - - /** - * User data can be 7 bit (default alphabet) data, 8 bit data, or 16 bit - * (UCS2) data. - * - * @param msg - * message object for output. - * @param length - * length of user data to read in octets. - */ - readUserData: function(msg, length) { - if (DEBUG) { - this.context.debug("Reading " + length + " bytes of user data."); - } - - let paddingBits = 0; - if (msg.udhi) { - this.readUserDataHeader(msg); - - if (msg.encoding == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - let headerBits = (msg.header.length + 1) * 8; - let headerSeptets = Math.ceil(headerBits / 7); - - length -= headerSeptets; - paddingBits = headerSeptets * 7 - headerBits; - } else { - length -= (msg.header.length + 1); - } - } - - if (DEBUG) { - this.context.debug("After header, " + length + " septets left of user data"); - } - - msg.body = null; - msg.data = null; - - if (length <= 0) { - // No data to read. - return; - } - - switch (msg.encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - // 7 bit encoding allows 140 octets, which means 160 characters - // ((140x8) / 7 = 160 chars) - if (length > PDU_MAX_USER_DATA_7BIT) { - if (DEBUG) { - this.context.debug("PDU error: user data is too long: " + length); - } - break; - } - - let langIndex = msg.udhi ? msg.header.langIndex : PDU_NL_IDENTIFIER_DEFAULT; - let langShiftIndex = msg.udhi ? msg.header.langShiftIndex : PDU_NL_IDENTIFIER_DEFAULT; - msg.body = this.readSeptetsToString(length, paddingBits, langIndex, - langShiftIndex); - break; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - msg.data = this.readHexOctetArray(length); - break; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - msg.body = this.readUCS2String(length); - break; - } - }, - - /** - * Read extra parameters if TP-PI is set. - * - * @param msg - * message object for output. - */ - readExtraParams: function(msg) { - // Because each PDU octet is converted to two UCS2 char2, we should always - // get even messageStringLength in this#_processReceivedSms(). So, we'll - // always need two delimitors at the end. - if (this.context.Buf.getReadAvailable() <= 4) { - return; - } - - // TP-Parameter-Indicator - let pi; - do { - // `The most significant bit in octet 1 and any other TP-PI octets which - // may be added later is reserved as an extension bit which when set to a - // 1 shall indicate that another TP-PI octet follows immediately - // afterwards.` ~ 3GPP TS 23.040 9.2.3.27 - pi = this.readHexOctet(); - } while (pi & PDU_PI_EXTENSION); - - // `If the TP-UDL bit is set to "1" but the TP-DCS bit is set to "0" then - // the receiving entity shall for TP-DCS assume a value of 0x00, i.e. the - // 7bit default alphabet.` ~ 3GPP 23.040 9.2.3.27 - msg.dcs = 0; - msg.encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - - // TP-Protocol-Identifier - if (pi & PDU_PI_PROTOCOL_IDENTIFIER) { - this.readProtocolIndicator(msg); - } - // TP-Data-Coding-Scheme - if (pi & PDU_PI_DATA_CODING_SCHEME) { - this.readDataCodingScheme(msg); - } - // TP-User-Data-Length - if (pi & PDU_PI_USER_DATA_LENGTH) { - let userDataLength = this.readHexOctet(); - this.readUserData(msg, userDataLength); - } - }, - - /** - * Read and decode a PDU-encoded message from the stream. - * - * TODO: add some basic sanity checks like: - * - do we have the minimum number of chars available - */ - readMessage: function() { - // An empty message object. This gets filled below and then returned. - let msg = { - // D:DELIVER, DR:DELIVER-REPORT, S:SUBMIT, SR:SUBMIT-REPORT, - // ST:STATUS-REPORT, C:COMMAND - // M:Mandatory, O:Optional, X:Unavailable - // D DR S SR ST C - SMSC: null, // M M M M M M - mti: null, // M M M M M M - udhi: null, // M M O M M M - sender: null, // M X X X X X - recipient: null, // X X M X M M - pid: null, // M O M O O M - epid: null, // M O M O O M - dcs: null, // M O M O O X - mwi: null, // O O O O O O - replace: false, // O O O O O O - header: null, // M M O M M M - body: null, // M O M O O O - data: null, // M O M O O O - sentTimestamp: null, // M X X X X X - status: null, // X X X X M X - scts: null, // X X X M M X - dt: null, // X X X X M X - }; - - // SMSC info - let smscLength = this.readHexOctet(); - if (smscLength > 0) { - let smscTypeOfAddress = this.readHexOctet(); - // Subtract the type-of-address octet we just read from the length. - msg.SMSC = this.readSwappedNibbleExtendedBcdString(smscLength - 1); - if ((smscTypeOfAddress >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) { - msg.SMSC = '+' + msg.SMSC; - } - } - - // First octet of this SMS-DELIVER or SMS-SUBMIT message - let firstOctet = this.readHexOctet(); - // Message Type Indicator - msg.mti = firstOctet & 0x03; - // User data header indicator - msg.udhi = firstOctet & PDU_UDHI; - - switch (msg.mti) { - case PDU_MTI_SMS_RESERVED: - // `If an MS receives a TPDU with a "Reserved" value in the TP-MTI it - // shall process the message as if it were an "SMS-DELIVER" but store - // the message exactly as received.` ~ 3GPP TS 23.040 9.2.3.1 - case PDU_MTI_SMS_DELIVER: - return this.readDeliverMessage(msg); - case PDU_MTI_SMS_STATUS_REPORT: - return this.readStatusReportMessage(msg); - default: - return null; - } - }, - - /** - * Helper for processing received SMS parcel data. - * - * @param length - * Length of SMS string in the incoming parcel. - * - * @return Message parsed or null for invalid message. - */ - processReceivedSms: function(length) { - if (!length) { - if (DEBUG) this.context.debug("Received empty SMS!"); - return [null, PDU_FCS_UNSPECIFIED]; - } - - let Buf = this.context.Buf; - - // An SMS is a string, but we won't read it as such, so let's read the - // string length and then defer to PDU parsing helper. - let messageStringLength = Buf.readInt32(); - if (DEBUG) this.context.debug("Got new SMS, length " + messageStringLength); - let message = this.readMessage(); - if (DEBUG) this.context.debug("Got new SMS: " + JSON.stringify(message)); - - // Read string delimiters. See Buf.readString(). - Buf.readStringDelimiter(length); - - // Determine result - if (!message) { - return [null, PDU_FCS_UNSPECIFIED]; - } - - if (message.epid == PDU_PID_SHORT_MESSAGE_TYPE_0) { - // `A short message type 0 indicates that the ME must acknowledge receipt - // of the short message but shall discard its contents.` ~ 3GPP TS 23.040 - // 9.2.3.9 - return [null, PDU_FCS_OK]; - } - - if (message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) { - let RIL = this.context.RIL; - switch (message.epid) { - case PDU_PID_ANSI_136_R_DATA: - case PDU_PID_USIM_DATA_DOWNLOAD: - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.isICCServiceAvailable("DATA_DOWNLOAD_SMS_PP")) { - // `If the service "data download via SMS Point-to-Point" is - // allocated and activated in the (U)SIM Service Table, ... then the - // ME shall pass the message transparently to the UICC using the - // ENVELOPE (SMS-PP DOWNLOAD).` ~ 3GPP TS 31.111 7.1.1.1 - RIL.dataDownloadViaSMSPP(message); - - // `the ME shall not display the message, or alert the user of a - // short message waiting.` ~ 3GPP TS 31.111 7.1.1.1 - return [null, PDU_FCS_RESERVED]; - } - - // If the service "data download via SMS-PP" is not available in the - // (U)SIM Service Table, ..., then the ME shall store the message in - // EFsms in accordance with TS 31.102` ~ 3GPP TS 31.111 7.1.1.1 - - // Fall through. - default: - RIL.writeSmsToSIM(message); - break; - } - } - - // TODO: Bug 739143: B2G SMS: Support SMS Storage Full event - if ((message.messageClass != GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]) && !true) { - // `When a mobile terminated message is class 0..., the MS shall display - // the message immediately and send a ACK to the SC ..., irrespective of - // whether there is memory available in the (U)SIM or ME.` ~ 3GPP 23.038 - // clause 4. - - if (message.messageClass == GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]) { - // `If all the short message storage at the MS is already in use, the - // MS shall return "memory capacity exceeded".` ~ 3GPP 23.038 clause 4. - return [null, PDU_FCS_MEMORY_CAPACITY_EXCEEDED]; - } - - return [null, PDU_FCS_UNSPECIFIED]; - } - - return [message, PDU_FCS_OK]; - }, - - /** - * Read and decode a SMS-DELIVER PDU. - * - * @param msg - * message object for output. - */ - readDeliverMessage: function(msg) { - // - Sender Address info - - let senderAddressLength = this.readHexOctet(); - msg.sender = this.readAddress(senderAddressLength); - // - TP-Protocolo-Identifier - - this.readProtocolIndicator(msg); - // - TP-Data-Coding-Scheme - - this.readDataCodingScheme(msg); - // - TP-Service-Center-Time-Stamp - - msg.sentTimestamp = this.readTimestamp(); - // - TP-User-Data-Length - - let userDataLength = this.readHexOctet(); - - // - TP-User-Data - - if (userDataLength > 0) { - this.readUserData(msg, userDataLength); - } - - return msg; - }, - - /** - * Read and decode a SMS-STATUS-REPORT PDU. - * - * @param msg - * message object for output. - */ - readStatusReportMessage: function(msg) { - // TP-Message-Reference - msg.messageRef = this.readHexOctet(); - // TP-Recipient-Address - let recipientAddressLength = this.readHexOctet(); - msg.recipient = this.readAddress(recipientAddressLength); - // TP-Service-Centre-Time-Stamp - msg.scts = this.readTimestamp(); - // TP-Discharge-Time - msg.dt = this.readTimestamp(); - // TP-Status - msg.status = this.readHexOctet(); - - this.readExtraParams(msg); - - return msg; - }, - - /** - * Serialize a SMS-SUBMIT PDU message and write it to the output stream. - * - * This method expects that a data coding scheme has been chosen already - * and that the length of the user data payload in that encoding is known, - * too. Both go hand in hand together anyway. - * - * @param address - * String containing the address (number) of the SMS receiver - * @param userData - * String containing the message to be sent as user data - * @param dcs - * Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET - * constants. - * @param userDataHeaderLength - * Length of embedded user data header, in bytes. The whole header - * size will be userDataHeaderLength + 1; 0 for no header. - * @param encodedBodyLength - * Length of the user data when encoded with the given DCS. For UCS2, - * in bytes; for 7-bit, in septets. - * @param langIndex - * Table index used for normal 7-bit encoded character lookup. - * @param langShiftIndex - * Table index used for escaped 7-bit encoded character lookup. - * @param requestStatusReport - * Request status report. - */ - writeMessage: function(options) { - if (DEBUG) { - this.context.debug("writeMessage: " + JSON.stringify(options)); - } - let Buf = this.context.Buf; - let address = options.number; - let body = options.body; - let dcs = options.dcs; - let userDataHeaderLength = options.userDataHeaderLength; - let encodedBodyLength = options.encodedBodyLength; - let langIndex = options.langIndex; - let langShiftIndex = options.langShiftIndex; - - // SMS-SUBMIT Format: - // - // PDU Type - 1 octet - // Message Reference - 1 octet - // DA - Destination Address - 2 to 12 octets - // PID - Protocol Identifier - 1 octet - // DCS - Data Coding Scheme - 1 octet - // VP - Validity Period - 0, 1 or 7 octets - // UDL - User Data Length - 1 octet - // UD - User Data - 140 octets - - let addressFormat = PDU_TOA_ISDN; // 81 - if (address[0] == '+') { - addressFormat = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91 - address = address.substring(1); - } - //TODO validity is unsupported for now - let validity = 0; - - let headerOctets = (userDataHeaderLength ? userDataHeaderLength + 1 : 0); - let paddingBits; - let userDataLengthInSeptets; - let userDataLengthInOctets; - if (dcs == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - let headerSeptets = Math.ceil(headerOctets * 8 / 7); - userDataLengthInSeptets = headerSeptets + encodedBodyLength; - userDataLengthInOctets = Math.ceil(userDataLengthInSeptets * 7 / 8); - paddingBits = headerSeptets * 7 - headerOctets * 8; - } else { - userDataLengthInOctets = headerOctets + encodedBodyLength; - paddingBits = 0; - } - - let pduOctetLength = 4 + // PDU Type, Message Ref, address length + format - Math.ceil(address.length / 2) + - 3 + // PID, DCS, UDL - userDataLengthInOctets; - if (validity) { - //TODO: add more to pduOctetLength - } - - // Start the string. Since octets are represented in hex, we will need - // twice as many characters as octets. - Buf.writeInt32(pduOctetLength * 2); - - // - PDU-TYPE- - - // +--------+----------+---------+---------+--------+---------+ - // | RP (1) | UDHI (1) | SRR (1) | VPF (2) | RD (1) | MTI (2) | - // +--------+----------+---------+---------+--------+---------+ - // RP: 0 Reply path parameter is not set - // 1 Reply path parameter is set - // UDHI: 0 The UD Field contains only the short message - // 1 The beginning of the UD field contains a header in addition - // of the short message - // SRR: 0 A status report is not requested - // 1 A status report is requested - // VPF: bit4 bit3 - // 0 0 VP field is not present - // 0 1 Reserved - // 1 0 VP field present an integer represented (relative) - // 1 1 VP field present a semi-octet represented (absolute) - // RD: Instruct the SMSC to accept(0) or reject(1) an SMS-SUBMIT - // for a short message still held in the SMSC which has the same - // MR and DA as a previously submitted short message from the - // same OA - // MTI: bit1 bit0 Message Type - // 0 0 SMS-DELIVER (SMSC ==> MS) - // 0 1 SMS-SUBMIT (MS ==> SMSC) - - // PDU type. MTI is set to SMS-SUBMIT - let firstOctet = PDU_MTI_SMS_SUBMIT; - - // Status-Report-Request - if (options.requestStatusReport) { - firstOctet |= PDU_SRI_SRR; - } - - // Validity period - if (validity) { - //TODO: not supported yet, OR with one of PDU_VPF_* - } - // User data header indicator - if (headerOctets) { - firstOctet |= PDU_UDHI; - } - this.writeHexOctet(firstOctet); - - // Message reference 00 - this.writeHexOctet(0x00); - - // - Destination Address - - this.writeHexOctet(address.length); - this.writeHexOctet(addressFormat); - this.writeSwappedNibbleBCD(address); - - // - Protocol Identifier - - this.writeHexOctet(0x00); - - // - Data coding scheme - - // For now it assumes bits 7..4 = 1111 except for the 16 bits use case - this.writeHexOctet(dcs); - - // - Validity Period - - if (validity) { - this.writeHexOctet(validity); - } - - // - User Data - - if (dcs == PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - this.writeHexOctet(userDataLengthInSeptets); - } else { - this.writeHexOctet(userDataLengthInOctets); - } - - if (headerOctets) { - this.writeUserDataHeader(options); - } - - switch (dcs) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - this.writeStringAsSeptets(body, paddingBits, langIndex, langShiftIndex); - break; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - // Unsupported. - break; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - this.writeUCS2String(body); - break; - } - - // End of the string. The string length is always even by definition, so - // we write two \0 delimiters. - Buf.writeUint16(0); - Buf.writeUint16(0); - }, - - /** - * Read GSM CBS message serial number. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.1 - */ - readCbSerialNumber: function(msg) { - let Buf = this.context.Buf; - msg.serial = Buf.readUint8() << 8 | Buf.readUint8(); - msg.geographicalScope = (msg.serial >>> 14) & 0x03; - msg.messageCode = (msg.serial >>> 4) & 0x03FF; - msg.updateNumber = msg.serial & 0x0F; - }, - - /** - * Read GSM CBS message message identifier. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.2 - */ - readCbMessageIdentifier: function(msg) { - let Buf = this.context.Buf; - msg.messageId = Buf.readUint8() << 8 | Buf.readUint8(); - }, - - /** - * Read ETWS information from message identifier and serial Number - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.1 & 9.4.1.2.2 - */ - readCbEtwsInfo: function(msg) { - if ((msg.format != CB_FORMAT_ETWS) - && (msg.messageId >= CB_GSM_MESSAGEID_ETWS_BEGIN) - && (msg.messageId <= CB_GSM_MESSAGEID_ETWS_END)) { - // `In the case of transmitting CBS message for ETWS, a part of - // Message Code can be used to command mobile terminals to activate - // emergency user alert and message popup in order to alert the users.` - msg.etws = { - emergencyUserAlert: msg.messageCode & 0x0200 ? true : false, - popup: msg.messageCode & 0x0100 ? true : false - }; - - let warningType = msg.messageId - CB_GSM_MESSAGEID_ETWS_BEGIN; - if (warningType < CB_ETWS_WARNING_TYPE_NAMES.length) { - msg.etws.warningType = warningType; - } - } - }, - - /** - * Read CBS Data Coding Scheme. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.038 section 5. - */ - readCbDataCodingScheme: function(msg) { - let dcs = this.context.Buf.readUint8(); - if (DEBUG) this.context.debug("PDU: read CBS dcs: " + dcs); - - let language = null, hasLanguageIndicator = false; - // `Any reserved codings shall be assumed to be the GSM 7bit default - // alphabet.` - let encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - let messageClass = PDU_DCS_MSG_CLASS_NORMAL; - - switch (dcs & PDU_DCS_CODING_GROUP_BITS) { - case 0x00: // 0000 - language = CB_DCS_LANG_GROUP_1[dcs & 0x0F]; - break; - - case 0x10: // 0001 - switch (dcs & 0x0F) { - case 0x00: - hasLanguageIndicator = true; - break; - case 0x01: - encoding = PDU_DCS_MSG_CODING_16BITS_ALPHABET; - hasLanguageIndicator = true; - break; - } - break; - - case 0x20: // 0010 - language = CB_DCS_LANG_GROUP_2[dcs & 0x0F]; - break; - - case 0x40: // 01xx - case 0x50: - //case 0x60: Text Compression, not supported - //case 0x70: Text Compression, not supported - case 0x90: // 1001 - encoding = (dcs & 0x0C); - if (encoding == 0x0C) { - encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - } - messageClass = (dcs & PDU_DCS_MSG_CLASS_BITS); - break; - - case 0xF0: - encoding = (dcs & 0x04) ? PDU_DCS_MSG_CODING_8BITS_ALPHABET - : PDU_DCS_MSG_CODING_7BITS_ALPHABET; - switch(dcs & PDU_DCS_MSG_CLASS_BITS) { - case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break; - case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break; - case 0x03: messageClass = PDU_DCS_MSG_CLASS_3; break; - } - break; - - case 0x30: // 0011 (Reserved) - case 0x80: // 1000 (Reserved) - case 0xA0: // 1010..1100 (Reserved) - case 0xB0: - case 0xC0: - break; - - default: - throw new Error("Unsupported CBS data coding scheme: " + dcs); - } - - msg.dcs = dcs; - msg.encoding = encoding; - msg.language = language; - msg.messageClass = GECKO_SMS_MESSAGE_CLASSES[messageClass]; - msg.hasLanguageIndicator = hasLanguageIndicator; - }, - - /** - * Read GSM CBS message page parameter. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.1.2.4 - */ - readCbPageParameter: function(msg) { - let octet = this.context.Buf.readUint8(); - msg.pageIndex = (octet >>> 4) & 0x0F; - msg.numPages = octet & 0x0F; - if (!msg.pageIndex || !msg.numPages) { - // `If a mobile receives the code 0000 in either the first field or the - // second field then it shall treat the CBS message exactly the same as a - // CBS message with page parameter 0001 0001 (i.e. a single page message).` - msg.pageIndex = msg.numPages = 1; - } - }, - - /** - * Read ETWS Primary Notification message warning type. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.3.24 - */ - readCbWarningType: function(msg) { - let Buf = this.context.Buf; - let word = Buf.readUint8() << 8 | Buf.readUint8(); - msg.etws = { - warningType: (word >>> 9) & 0x7F, - popup: word & 0x80 ? true : false, - emergencyUserAlert: word & 0x100 ? true : false - }; - }, - - /** - * Read GSM CB Data - * - * This parameter is a copy of the 'CBS-Message-Information-Page' as sent - * from the CBC to the BSC. - * - * @see 3GPP TS 23.041 section 9.4.1.2.5 - */ - readGsmCbData: function(msg, length) { - let Buf = this.context.Buf; - let bufAdapter = { - context: this.context, - readHexOctet: function() { - return Buf.readUint8(); - } - }; - - msg.body = null; - msg.data = null; - switch (msg.encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - msg.body = this.readSeptetsToString.call(bufAdapter, - Math.floor(length * 8 / 7), 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - if (msg.hasLanguageIndicator) { - msg.language = msg.body.substring(0, 2); - msg.body = msg.body.substring(3); - } - break; - - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - msg.data = Buf.readUint8Array(length); - break; - - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - if (msg.hasLanguageIndicator) { - msg.language = this.readSeptetsToString.call(bufAdapter, 2, 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - length -= 2; - } - msg.body = this.readUCS2String.call(bufAdapter, length); - break; - } - - if (msg.data || !msg.body) { - return; - } - - // According to 9.3.19 CBS-Message-Information-Page in TS 23.041: - // " - // This parameter is of a fixed length of 82 octets and carries up to and - // including 82 octets of user information. Where the user information is - // less than 82 octets, the remaining octets must be filled with padding. - // " - // According to 6.2.1.1 GSM 7 bit Default Alphabet and 6.2.3 UCS2 in - // TS 23.038, the padding character is . - for (let i = msg.body.length - 1; i >= 0; i--) { - if (msg.body.charAt(i) !== '\r') { - msg.body = msg.body.substring(0, i + 1); - break; - } - } - }, - - /** - * Read UMTS CB Data - * - * Octet Number(s) Parameter - * 1 Number-of-Pages - * 2 - 83 CBS-Message-Information-Page 1 - * 84 CBS-Message-Information-Length 1 - * ... - * CBS-Message-Information-Page n - * CBS-Message-Information-Length n - * - * @see 3GPP TS 23.041 section 9.4.2.2.5 - */ - readUmtsCbData: function(msg) { - let Buf = this.context.Buf; - let numOfPages = Buf.readUint8(); - if (numOfPages < 0 || numOfPages > 15) { - throw new Error("Invalid numOfPages: " + numOfPages); - } - - let bufAdapter = { - context: this.context, - readHexOctet: function() { - return Buf.readUint8(); - } - }; - - let removePaddingCharactors = function (text) { - for (let i = text.length - 1; i >= 0; i--) { - if (text.charAt(i) !== '\r') { - return text.substring(0, i + 1); - } - } - return text; - }; - - let totalLength = 0, length, pageLengths = []; - for (let i = 0; i < numOfPages; i++) { - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE); - length = Buf.readUint8(); - totalLength += length; - pageLengths.push(length); - } - - // Seek back to beginning of CB Data. - Buf.seekIncoming(-numOfPages * (CB_MSG_PAGE_INFO_SIZE + 1)); - - switch (msg.encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: { - let body; - msg.body = ""; - for (let i = 0; i < numOfPages; i++) { - body = this.readSeptetsToString.call(bufAdapter, - Math.floor(pageLengths[i] * 8 / 7), - 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - if (msg.hasLanguageIndicator) { - if (!msg.language) { - msg.language = body.substring(0, 2); - } - body = body.substring(3); - } - - msg.body += removePaddingCharactors(body); - - // Skip padding octets - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]); - // Read the octet of CBS-Message-Information-Length - Buf.readUint8(); - } - - break; - } - - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: { - msg.data = new Uint8Array(totalLength); - for (let i = 0, j = 0; i < numOfPages; i++) { - for (let pageLength = pageLengths[i]; pageLength > 0; pageLength--) { - msg.data[j++] = Buf.readUint8(); - } - - // Skip padding octets - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]); - // Read the octet of CBS-Message-Information-Length - Buf.readUint8(); - } - - break; - } - - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: { - msg.body = ""; - for (let i = 0; i < numOfPages; i++) { - let pageLength = pageLengths[i]; - if (msg.hasLanguageIndicator) { - if (!msg.language) { - msg.language = this.readSeptetsToString.call(bufAdapter, - 2, - 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - } else { - Buf.readUint16(); - } - - pageLength -= 2; - } - - msg.body += removePaddingCharactors( - this.readUCS2String.call(bufAdapter, pageLength)); - - // Skip padding octets - Buf.seekIncoming(CB_MSG_PAGE_INFO_SIZE - pageLengths[i]); - // Read the octet of CBS-Message-Information-Length - Buf.readUint8(); - } - - break; - } - } - }, - - /** - * Read Cell GSM/ETWS/UMTS Broadcast Message. - * - * @param pduLength - * total length of the incoming PDU in octets. - */ - readCbMessage: function(pduLength) { - // Validity GSM ETWS UMTS - let msg = { - // Internally used in ril_worker: - serial: null, // O O O - updateNumber: null, // O O O - format: null, // O O O - dcs: 0x0F, // O X O - encoding: PDU_DCS_MSG_CODING_7BITS_ALPHABET, // O X O - hasLanguageIndicator: false, // O X O - data: null, // O X O - body: null, // O X O - pageIndex: 1, // O X X - numPages: 1, // O X X - - // DOM attributes: - geographicalScope: null, // O O O - messageCode: null, // O O O - messageId: null, // O O O - language: null, // O X O - fullBody: null, // O X O - fullData: null, // O X O - messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], // O x O - etws: null // ? O ? - /*{ - warningType: null, // X O X - popup: false, // X O X - emergencyUserAlert: false, // X O X - }*/ - }; - - if (pduLength <= CB_MESSAGE_SIZE_ETWS) { - msg.format = CB_FORMAT_ETWS; - return this.readEtwsCbMessage(msg); - } - - if (pduLength <= CB_MESSAGE_SIZE_GSM) { - msg.format = CB_FORMAT_GSM; - return this.readGsmCbMessage(msg, pduLength); - } - - if (pduLength >= CB_MESSAGE_SIZE_UMTS_MIN && - pduLength <= CB_MESSAGE_SIZE_UMTS_MAX) { - msg.format = CB_FORMAT_UMTS; - return this.readUmtsCbMessage(msg); - } - - throw new Error("Invalid PDU Length: " + pduLength); - }, - - /** - * Read UMTS CBS Message. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 section 9.4.2 - * @see 3GPP TS 25.324 section 10.2 - */ - readUmtsCbMessage: function(msg) { - let Buf = this.context.Buf; - let type = Buf.readUint8(); - if (type != CB_UMTS_MESSAGE_TYPE_CBS) { - throw new Error("Unsupported UMTS Cell Broadcast message type: " + type); - } - - this.readCbMessageIdentifier(msg); - this.readCbSerialNumber(msg); - this.readCbEtwsInfo(msg); - this.readCbDataCodingScheme(msg); - this.readUmtsCbData(msg); - - return msg; - }, - - /** - * Read GSM Cell Broadcast Message. - * - * @param msg - * message object for output. - * @param pduLength - * total length of the incomint PDU in octets. - * - * @see 3GPP TS 23.041 clause 9.4.1.2 - */ - readGsmCbMessage: function(msg, pduLength) { - this.readCbSerialNumber(msg); - this.readCbMessageIdentifier(msg); - this.readCbEtwsInfo(msg); - this.readCbDataCodingScheme(msg); - this.readCbPageParameter(msg); - - // GSM CB message header takes 6 octets. - this.readGsmCbData(msg, pduLength - 6); - - return msg; - }, - - /** - * Read ETWS Primary Notification Message. - * - * @param msg - * message object for output. - * - * @see 3GPP TS 23.041 clause 9.4.1.3 - */ - readEtwsCbMessage: function(msg) { - this.readCbSerialNumber(msg); - this.readCbMessageIdentifier(msg); - this.readCbWarningType(msg); - - // Octet 7..56 is Warning Security Information. However, according to - // section 9.4.1.3.6, `The UE shall ignore this parameter.` So we just skip - // processing it here. - - return msg; - }, - - /** - * Read network name. - * - * @param len Length of the information element. - * @return - * { - * networkName: network name. - * shouldIncludeCi: Should Country's initials included in text string. - * } - * @see TS 24.008 clause 10.5.3.5a. - */ - readNetworkName: function(len) { - // According to TS 24.008 Sec. 10.5.3.5a, the first octet is: - // bit 8: must be 1. - // bit 5-7: Text encoding. - // 000 - GSM default alphabet. - // 001 - UCS2 (16 bit). - // else - reserved. - // bit 4: MS should add the letters for Country's Initials and a space - // to the text string if this bit is true. - // bit 1-3: number of spare bits in last octet. - - let codingInfo = this.readHexOctet(); - if (!(codingInfo & 0x80)) { - return null; - } - - let textEncoding = (codingInfo & 0x70) >> 4; - let shouldIncludeCountryInitials = !!(codingInfo & 0x08); - let spareBits = codingInfo & 0x07; - let resultString; - - switch (textEncoding) { - case 0: - // GSM Default alphabet. - resultString = this.readSeptetsToString( - Math.floor(((len - 1) * 8 - spareBits) / 7), 0, - PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - break; - case 1: - // UCS2 encoded. - resultString = this.context.ICCPDUHelper.readAlphaIdentifier(len - 1); - break; - default: - // Not an available text coding. - return null; - } - - // TODO - Bug 820286: According to shouldIncludeCountryInitials, add - // country initials to the resulting string. - return resultString; - } -}; - -/** - * Provide buffer with bitwise read/write function so make encoding/decoding easier. - */ -function BitBufferHelperObject(/* unused */aContext) { - this.readBuffer = []; - this.writeBuffer = []; -} -BitBufferHelperObject.prototype = { - readCache: 0, - readCacheSize: 0, - readBuffer: null, - readIndex: 0, - writeCache: 0, - writeCacheSize: 0, - writeBuffer: null, - - // Max length is 32 because we use integer as read/write cache. - // All read/write functions are implemented based on bitwise operation. - readBits: function(length) { - if (length <= 0 || length > 32) { - return null; - } - - if (length > this.readCacheSize) { - let bytesToRead = Math.ceil((length - this.readCacheSize) / 8); - for(let i = 0; i < bytesToRead; i++) { - this.readCache = (this.readCache << 8) | (this.readBuffer[this.readIndex++] & 0xFF); - this.readCacheSize += 8; - } - } - - let bitOffset = (this.readCacheSize - length), - resultMask = (1 << length) - 1, - result = 0; - - result = (this.readCache >> bitOffset) & resultMask; - this.readCacheSize -= length; - - return result; - }, - - backwardReadPilot: function(length) { - if (length <= 0) { - return; - } - - // Zero-based position. - let bitIndexToRead = this.readIndex * 8 - this.readCacheSize - length; - - if (bitIndexToRead < 0) { - return; - } - - // Update readIndex, readCache, readCacheSize accordingly. - let readBits = bitIndexToRead % 8; - this.readIndex = Math.floor(bitIndexToRead / 8) + ((readBits) ? 1 : 0); - this.readCache = (readBits) ? this.readBuffer[this.readIndex - 1] : 0; - this.readCacheSize = (readBits) ? (8 - readBits) : 0; - }, - - writeBits: function(value, length) { - if (length <= 0 || length > 32) { - return; - } - - let totalLength = length + this.writeCacheSize; - - // 8-byte cache not full - if (totalLength < 8) { - let valueMask = (1 << length) - 1; - this.writeCache = (this.writeCache << length) | (value & valueMask); - this.writeCacheSize += length; - return; - } - - // Deal with unaligned part - if (this.writeCacheSize) { - let mergeLength = 8 - this.writeCacheSize, - valueMask = (1 << mergeLength) - 1; - - this.writeCache = (this.writeCache << mergeLength) | ((value >> (length - mergeLength)) & valueMask); - this.writeBuffer.push(this.writeCache & 0xFF); - length -= mergeLength; - } - - // Aligned part, just copy - while (length >= 8) { - length -= 8; - this.writeBuffer.push((value >> length) & 0xFF); - } - - // Rest part is saved into cache - this.writeCacheSize = length; - this.writeCache = value & ((1 << length) - 1); - - return; - }, - - // Drop what still in read cache and goto next 8-byte alignment. - // There might be a better naming. - nextOctetAlign: function() { - this.readCache = 0; - this.readCacheSize = 0; - }, - - // Flush current write cache to Buf with padding 0s. - // There might be a better naming. - flushWithPadding: function() { - if (this.writeCacheSize) { - this.writeBuffer.push(this.writeCache << (8 - this.writeCacheSize)); - } - this.writeCache = 0; - this.writeCacheSize = 0; - }, - - startWrite: function(dataBuffer) { - this.writeBuffer = dataBuffer; - this.writeCache = 0; - this.writeCacheSize = 0; - }, - - startRead: function(dataBuffer) { - this.readBuffer = dataBuffer; - this.readCache = 0; - this.readCacheSize = 0; - this.readIndex = 0; - }, - - getWriteBufferSize: function() { - return this.writeBuffer.length; - }, - - overwriteWriteBuffer: function(position, data) { - let writeLength = data.length; - if (writeLength + position >= this.writeBuffer.length) { - writeLength = this.writeBuffer.length - position; - } - for (let i = 0; i < writeLength; i++) { - this.writeBuffer[i + position] = data[i]; - } - } -}; - -/** - * Helper for CDMA PDU - * - * Currently, some function are shared with GsmPDUHelper, they should be - * moved from GsmPDUHelper to a common object shared among GsmPDUHelper and - * CdmaPDUHelper. - */ -function CdmaPDUHelperObject(aContext) { - this.context = aContext; -} -CdmaPDUHelperObject.prototype = { - context: null, - - // 1..........C - // Only "1234567890*#" is defined in C.S0005-D v2.0 - dtmfChars: ".1234567890*#...", - - /** - * Entry point for SMS encoding, the options object is made compatible - * with existing writeMessage() of GsmPDUHelper, but less key is used. - * - * Current used key in options: - * @param number - * String containing the address (number) of the SMS receiver - * @param body - * String containing the message to be sent, segmented part - * @param dcs - * Data coding scheme. One of the PDU_DCS_MSG_CODING_*BITS_ALPHABET - * constants. - * @param encodedBodyLength - * Length of the user data when encoded with the given DCS. For UCS2, - * in bytes; for 7-bit, in septets. - * @param requestStatusReport - * Request status report. - * @param segmentRef - * Reference number of concatenated SMS message - * @param segmentMaxSeq - * Total number of concatenated SMS message - * @param segmentSeq - * Sequence number of concatenated SMS message - */ - writeMessage: function(options) { - if (DEBUG) { - this.context.debug("cdma_writeMessage: " + JSON.stringify(options)); - } - - // Get encoding - options.encoding = this.gsmDcsToCdmaEncoding(options.dcs); - - // Common Header - if (options.segmentMaxSeq > 1) { - this.writeInt(PDU_CDMA_MSG_TELESERIVCIE_ID_WEMT); - } else { - this.writeInt(PDU_CDMA_MSG_TELESERIVCIE_ID_SMS); - } - - this.writeInt(0); - this.writeInt(PDU_CDMA_MSG_CATEGORY_UNSPEC); - - // Just fill out address info in byte, rild will encap them for us - let addrInfo = this.encodeAddr(options.number); - this.writeByte(addrInfo.digitMode); - this.writeByte(addrInfo.numberMode); - this.writeByte(addrInfo.numberType); - this.writeByte(addrInfo.numberPlan); - this.writeByte(addrInfo.address.length); - for (let i = 0; i < addrInfo.address.length; i++) { - this.writeByte(addrInfo.address[i]); - } - - // Subaddress, not supported - this.writeByte(0); // Subaddress : Type - this.writeByte(0); // Subaddress : Odd - this.writeByte(0); // Subaddress : length - - // User Data - let encodeResult = this.encodeUserData(options); - this.writeByte(encodeResult.length); - for (let i = 0; i < encodeResult.length; i++) { - this.writeByte(encodeResult[i]); - } - - encodeResult = null; - }, - - /** - * Data writters - */ - writeInt: function(value) { - this.context.Buf.writeInt32(value); - }, - - writeByte: function(value) { - this.context.Buf.writeInt32(value & 0xFF); - }, - - /** - * Transform GSM DCS to CDMA encoding. - */ - gsmDcsToCdmaEncoding: function(encoding) { - switch (encoding) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - return PDU_CDMA_MSG_CODING_7BITS_ASCII; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - return PDU_CDMA_MSG_CODING_OCTET; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - return PDU_CDMA_MSG_CODING_UNICODE; - } - throw new Error("gsmDcsToCdmaEncoding(): Invalid GSM SMS DCS value: " + encoding); - }, - - /** - * Encode address into CDMA address format, as a byte array. - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.3 Address Parameters - * - * @param address - * String of address to be encoded - */ - encodeAddr: function(address) { - let result = {}; - - result.numberType = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN; - result.numberPlan = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN; - - if (address[0] === '+') { - address = address.substring(1); - } - - // Try encode with DTMF first - result.digitMode = PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF; - result.numberMode = PDU_CDMA_MSG_ADDR_NUMBER_MODE_ANSI; - - result.address = []; - for (let i = 0; i < address.length; i++) { - let addrDigit = this.dtmfChars.indexOf(address.charAt(i)); - if (addrDigit < 0) { - result.digitMode = PDU_CDMA_MSG_ADDR_DIGIT_MODE_ASCII; - result.numberMode = PDU_CDMA_MSG_ADDR_NUMBER_MODE_ASCII; - result.address = []; - break; - } - result.address.push(addrDigit); - } - - // Address can't be encoded with DTMF, then use 7-bit ASCII - if (result.digitMode !== PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF) { - if (address.indexOf("@") !== -1) { - result.numberType = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_NATIONAL; - } - - for (let i = 0; i < address.length; i++) { - result.address.push(address.charCodeAt(i) & 0x7F); - } - } - - return result; - }, - - /** - * Encode SMS contents in options into CDMA userData field. - * Corresponding and required subparameters will be added automatically. - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.7 Bearer Data - * 4.5 Bearer Data Parameters - * - * Current used key in options: - * @param body - * String containing the message to be sent, segmented part - * @param encoding - * Encoding method of CDMA, can be transformed from GSM DCS by function - * cdmaPduHelp.gsmDcsToCdmaEncoding() - * @param encodedBodyLength - * Length of the user data when encoded with the given DCS. For UCS2, - * in bytes; for 7-bit, in septets. - * @param requestStatusReport - * Request status report. - * @param segmentRef - * Reference number of concatenated SMS message - * @param segmentMaxSeq - * Total number of concatenated SMS message - * @param segmentSeq - * Sequence number of concatenated SMS message - */ - encodeUserData: function(options) { - let userDataBuffer = []; - this.context.BitBufferHelper.startWrite(userDataBuffer); - - // Message Identifier - this.encodeUserDataMsgId(options); - - // User Data - this.encodeUserDataMsg(options); - - // Reply Option - this.encodeUserDataReplyOption(options); - - return userDataBuffer; - }, - - /** - * User data subparameter encoder : Message Identifier - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.1 Message Identifier - */ - encodeUserDataMsgId: function(options) { - let BitBufferHelper = this.context.BitBufferHelper; - BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_MSG_ID, 8); - BitBufferHelper.writeBits(3, 8); - BitBufferHelper.writeBits(PDU_CDMA_MSG_TYPE_SUBMIT, 4); - BitBufferHelper.writeBits(1, 16); // TODO: How to get message ID? - if (options.segmentMaxSeq > 1) { - BitBufferHelper.writeBits(1, 1); - } else { - BitBufferHelper.writeBits(0, 1); - } - - BitBufferHelper.flushWithPadding(); - }, - - /** - * User data subparameter encoder : User Data - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.2 User Data - */ - encodeUserDataMsg: function(options) { - let BitBufferHelper = this.context.BitBufferHelper; - BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_BODY, 8); - // Reserve space for length - BitBufferHelper.writeBits(0, 8); - let lengthPosition = BitBufferHelper.getWriteBufferSize(); - - BitBufferHelper.writeBits(options.encoding, 5); - - // Add user data header for message segement - let msgBody = options.body, - msgBodySize = (options.encoding === PDU_CDMA_MSG_CODING_7BITS_ASCII ? - options.encodedBodyLength : - msgBody.length); - if (options.segmentMaxSeq > 1) { - if (options.encoding === PDU_CDMA_MSG_CODING_7BITS_ASCII) { - BitBufferHelper.writeBits(msgBodySize + 7, 8); // Required length for user data header, in septet(7-bit) - - BitBufferHelper.writeBits(5, 8); // total header length 5 bytes - BitBufferHelper.writeBits(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT, 8); // header id 0 - BitBufferHelper.writeBits(3, 8); // length of element for id 0 is 3 - BitBufferHelper.writeBits(options.segmentRef & 0xFF, 8); // Segement reference - BitBufferHelper.writeBits(options.segmentMaxSeq & 0xFF, 8); // Max segment - BitBufferHelper.writeBits(options.segmentSeq & 0xFF, 8); // Current segment - BitBufferHelper.writeBits(0, 1); // Padding to make header data septet(7-bit) aligned - } else { - if (options.encoding === PDU_CDMA_MSG_CODING_UNICODE) { - BitBufferHelper.writeBits(msgBodySize + 3, 8); // Required length for user data header, in 16-bit - } else { - BitBufferHelper.writeBits(msgBodySize + 6, 8); // Required length for user data header, in octet(8-bit) - } - - BitBufferHelper.writeBits(5, 8); // total header length 5 bytes - BitBufferHelper.writeBits(PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT, 8); // header id 0 - BitBufferHelper.writeBits(3, 8); // length of element for id 0 is 3 - BitBufferHelper.writeBits(options.segmentRef & 0xFF, 8); // Segement reference - BitBufferHelper.writeBits(options.segmentMaxSeq & 0xFF, 8); // Max segment - BitBufferHelper.writeBits(options.segmentSeq & 0xFF, 8); // Current segment - } - } else { - BitBufferHelper.writeBits(msgBodySize, 8); - } - - // Encode message based on encoding method - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - for (let i = 0; i < msgBody.length; i++) { - switch (options.encoding) { - case PDU_CDMA_MSG_CODING_OCTET: { - let msgDigit = msgBody.charCodeAt(i); - BitBufferHelper.writeBits(msgDigit, 8); - break; - } - case PDU_CDMA_MSG_CODING_7BITS_ASCII: { - let msgDigit = msgBody.charCodeAt(i), - msgDigitChar = msgBody.charAt(i); - - if (msgDigit >= 32) { - BitBufferHelper.writeBits(msgDigit, 7); - } else { - msgDigit = langTable.indexOf(msgDigitChar); - - if (msgDigit === PDU_NL_EXTENDED_ESCAPE) { - break; - } - if (msgDigit >= 0) { - BitBufferHelper.writeBits(msgDigit, 7); - } else { - msgDigit = langShiftTable.indexOf(msgDigitChar); - if (msgDigit == -1) { - throw new Error("'" + msgDigitChar + "' is not in 7 bit alphabet " - + langIndex + ":" + langShiftIndex + "!"); - } - - if (msgDigit === PDU_NL_RESERVED_CONTROL) { - break; - } - - BitBufferHelper.writeBits(PDU_NL_EXTENDED_ESCAPE, 7); - BitBufferHelper.writeBits(msgDigit, 7); - } - } - break; - } - case PDU_CDMA_MSG_CODING_UNICODE: { - let msgDigit = msgBody.charCodeAt(i); - BitBufferHelper.writeBits(msgDigit, 16); - break; - } - } - } - BitBufferHelper.flushWithPadding(); - - // Fill length - let currentPosition = BitBufferHelper.getWriteBufferSize(); - BitBufferHelper.overwriteWriteBuffer(lengthPosition - 1, [currentPosition - lengthPosition]); - }, - - /** - * User data subparameter encoder : Reply Option - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.11 Reply Option - */ - encodeUserDataReplyOption: function(options) { - if (options.requestStatusReport) { - let BitBufferHelper = this.context.BitBufferHelper; - BitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_REPLY_OPTION, 8); - BitBufferHelper.writeBits(1, 8); - BitBufferHelper.writeBits(0, 1); // USER_ACK_REQ - BitBufferHelper.writeBits(1, 1); // DAK_REQ - BitBufferHelper.flushWithPadding(); - } - }, - - /** - * Entry point for SMS decoding, the returned object is made compatible - * with existing readMessage() of GsmPDUHelper - */ - readMessage: function() { - let message = {}; - - // Teleservice Identifier - message.teleservice = this.readInt(); - - // Message Type - let isServicePresent = this.readByte(); - if (isServicePresent) { - message.messageType = PDU_CDMA_MSG_TYPE_BROADCAST; - } else { - if (message.teleservice) { - message.messageType = PDU_CDMA_MSG_TYPE_P2P; - } else { - message.messageType = PDU_CDMA_MSG_TYPE_ACK; - } - } - - // Service Category - message.service = this.readInt(); - - // Originated Address - let addrInfo = {}; - addrInfo.digitMode = (this.readInt() & 0x01); - addrInfo.numberMode = (this.readInt() & 0x01); - addrInfo.numberType = (this.readInt() & 0x01); - addrInfo.numberPlan = (this.readInt() & 0x01); - addrInfo.addrLength = this.readByte(); - addrInfo.address = []; - for (let i = 0; i < addrInfo.addrLength; i++) { - addrInfo.address.push(this.readByte()); - } - message.sender = this.decodeAddr(addrInfo); - - // Originated Subaddress - addrInfo.Type = (this.readInt() & 0x07); - addrInfo.Odd = (this.readByte() & 0x01); - addrInfo.addrLength = this.readByte(); - for (let i = 0; i < addrInfo.addrLength; i++) { - let addrDigit = this.readByte(); - message.sender += String.fromCharCode(addrDigit); - } - - // Bearer Data - this.decodeUserData(message); - - // Bearer Data Sub-Parameter: User Data - let userData = message[PDU_CDMA_MSG_USERDATA_BODY]; - [message.header, message.body, message.encoding, message.data] = - (userData) ? [userData.header, userData.body, userData.encoding, userData.data] - : [null, null, null, null]; - - // Bearer Data Sub-Parameter: Message Status - // Success Delivery (0) if both Message Status and User Data are absent. - // Message Status absent (-1) if only User Data is available. - let msgStatus = message[PDU_CDMA_MSG_USER_DATA_MSG_STATUS]; - [message.errorClass, message.msgStatus] = - (msgStatus) ? [msgStatus.errorClass, msgStatus.msgStatus] - : ((message.body) ? [-1, -1] : [0, 0]); - - // Transform message to GSM msg - let msg = { - SMSC: "", - mti: 0, - udhi: 0, - sender: message.sender, - recipient: null, - pid: PDU_PID_DEFAULT, - epid: PDU_PID_DEFAULT, - dcs: 0, - mwi: null, - replace: false, - header: message.header, - body: message.body, - data: message.data, - sentTimestamp: message[PDU_CDMA_MSG_USERDATA_TIMESTAMP], - language: message[PDU_CDMA_LANGUAGE_INDICATOR], - status: null, - scts: null, - dt: null, - encoding: message.encoding, - messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - messageType: message.messageType, - serviceCategory: message.service, - subMsgType: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgType, - msgId: message[PDU_CDMA_MSG_USERDATA_MSG_ID].msgId, - errorClass: message.errorClass, - msgStatus: message.msgStatus, - teleservice: message.teleservice - }; - - return msg; - }, - - /** - * Helper for processing received SMS parcel data. - * - * @param length - * Length of SMS string in the incoming parcel. - * - * @return Message parsed or null for invalid message. - */ - processReceivedSms: function(length) { - if (!length) { - if (DEBUG) this.context.debug("Received empty SMS!"); - return [null, PDU_FCS_UNSPECIFIED]; - } - - let message = this.readMessage(); - if (DEBUG) this.context.debug("Got new SMS: " + JSON.stringify(message)); - - // Determine result - if (!message) { - return [null, PDU_FCS_UNSPECIFIED]; - } - - return [message, PDU_FCS_OK]; - }, - - /** - * Data readers - */ - readInt: function() { - return this.context.Buf.readInt32(); - }, - - readByte: function() { - return (this.context.Buf.readInt32() & 0xFF); - }, - - /** - * Decode CDMA address data into address string - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.3 Address Parameters - * - * Required key in addrInfo - * @param addrLength - * Length of address - * @param digitMode - * Address encoding method - * @param address - * Array of encoded address data - */ - decodeAddr: function(addrInfo) { - let result = ""; - for (let i = 0; i < addrInfo.addrLength; i++) { - if (addrInfo.digitMode === PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF) { - result += this.dtmfChars.charAt(addrInfo.address[i]); - } else { - result += String.fromCharCode(addrInfo.address[i]); - } - } - return result; - }, - - /** - * Read userData in parcel buffer and decode into message object. - * Each subparameter will be stored in corresponding key. - * - * @see 3GGP2 C.S0015-B 2.0, 3.4.3.7 Bearer Data - * 4.5 Bearer Data Parameters - */ - decodeUserData: function(message) { - let userDataLength = this.readInt(); - - while (userDataLength > 0) { - let id = this.readByte(), - length = this.readByte(), - userDataBuffer = []; - - for (let i = 0; i < length; i++) { - userDataBuffer.push(this.readByte()); - } - - this.context.BitBufferHelper.startRead(userDataBuffer); - - switch (id) { - case PDU_CDMA_MSG_USERDATA_MSG_ID: - message[id] = this.decodeUserDataMsgId(); - break; - case PDU_CDMA_MSG_USERDATA_BODY: - message[id] = this.decodeUserDataMsg(message[PDU_CDMA_MSG_USERDATA_MSG_ID].userHeader); - break; - case PDU_CDMA_MSG_USERDATA_TIMESTAMP: - message[id] = this.decodeUserDataTimestamp(); - break; - case PDU_CDMA_MSG_USERDATA_REPLY_OPTION: - message[id] = this.decodeUserDataReplyOption(); - break; - case PDU_CDMA_LANGUAGE_INDICATOR: - message[id] = this.decodeLanguageIndicator(); - break; - case PDU_CDMA_MSG_USERDATA_CALLBACK_NUMBER: - message[id] = this.decodeUserDataCallbackNumber(); - break; - case PDU_CDMA_MSG_USER_DATA_MSG_STATUS: - message[id] = this.decodeUserDataMsgStatus(); - break; - } - - userDataLength -= (length + 2); - userDataBuffer = []; - } - }, - - /** - * User data subparameter decoder: Message Identifier - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.1 Message Identifier - */ - decodeUserDataMsgId: function() { - let result = {}; - let BitBufferHelper = this.context.BitBufferHelper; - result.msgType = BitBufferHelper.readBits(4); - result.msgId = BitBufferHelper.readBits(16); - result.userHeader = BitBufferHelper.readBits(1); - - return result; - }, - - /** - * Decode user data header, we only care about segment information - * on CDMA. - * - * This function is mostly copied from gsmPduHelper.readUserDataHeader() but - * change the read function, because CDMA user header decoding is't byte-wise - * aligned. - */ - decodeUserDataHeader: function(encoding) { - let BitBufferHelper = this.context.BitBufferHelper; - let header = {}, - headerSize = BitBufferHelper.readBits(8), - userDataHeaderSize = headerSize + 1, - headerPaddingBits = 0; - - // Calculate header size - if (encoding === PDU_DCS_MSG_CODING_7BITS_ALPHABET) { - // Length is in 7-bit - header.length = Math.ceil(userDataHeaderSize * 8 / 7); - // Calulate padding length - headerPaddingBits = (header.length * 7) - (userDataHeaderSize * 8); - } else if (encoding === PDU_DCS_MSG_CODING_8BITS_ALPHABET) { - header.length = userDataHeaderSize; - } else { - header.length = userDataHeaderSize / 2; - } - - while (headerSize) { - let identifier = BitBufferHelper.readBits(8), - length = BitBufferHelper.readBits(8); - - headerSize -= (2 + length); - - switch (identifier) { - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_8BIT: { - let ref = BitBufferHelper.readBits(8), - max = BitBufferHelper.readBits(8), - seq = BitBufferHelper.readBits(8); - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_8BIT: { - let dstp = BitBufferHelper.readBits(8), - orip = BitBufferHelper.readBits(8); - if ((dstp < PDU_APA_RESERVED_8BIT_PORTS) - || (orip < PDU_APA_RESERVED_8BIT_PORTS)) { - // 3GPP TS 23.040 clause 9.2.3.24.3: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - break; - } - header.destinationPort = dstp; - header.originatorPort = orip; - break; - } - case PDU_IEI_APPLICATION_PORT_ADDRESSING_SCHEME_16BIT: { - let dstp = (BitBufferHelper.readBits(8) << 8) | BitBufferHelper.readBits(8), - orip = (BitBufferHelper.readBits(8) << 8) | BitBufferHelper.readBits(8); - // 3GPP TS 23.040 clause 9.2.3.24.4: "A receiving entity shall - // ignore any information element where the value of the - // Information-Element-Data is Reserved or not supported" - if ((dstp < PDU_APA_VALID_16BIT_PORTS) - && (orip < PDU_APA_VALID_16BIT_PORTS)) { - header.destinationPort = dstp; - header.originatorPort = orip; - } - break; - } - case PDU_IEI_CONCATENATED_SHORT_MESSAGES_16BIT: { - let ref = (BitBufferHelper.readBits(8) << 8) | BitBufferHelper.readBits(8), - max = BitBufferHelper.readBits(8), - seq = BitBufferHelper.readBits(8); - if (max && seq && (seq <= max)) { - header.segmentRef = ref; - header.segmentMaxSeq = max; - header.segmentSeq = seq; - } - break; - } - case PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT: { - let langShiftIndex = BitBufferHelper.readBits(8); - if (langShiftIndex < PDU_NL_SINGLE_SHIFT_TABLES.length) { - header.langShiftIndex = langShiftIndex; - } - break; - } - case PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT: { - let langIndex = BitBufferHelper.readBits(8); - if (langIndex < PDU_NL_LOCKING_SHIFT_TABLES.length) { - header.langIndex = langIndex; - } - break; - } - case PDU_IEI_SPECIAL_SMS_MESSAGE_INDICATION: { - let msgInd = BitBufferHelper.readBits(8) & 0xFF, - msgCount = BitBufferHelper.readBits(8); - /* - * TS 23.040 V6.8.1 Sec 9.2.3.24.2 - * bits 1 0 : basic message indication type - * bits 4 3 2 : extended message indication type - * bits 6 5 : Profile id - * bit 7 : storage type - */ - let storeType = msgInd & PDU_MWI_STORE_TYPE_BIT; - header.mwi = {}; - mwi = header.mwi; - - if (storeType == PDU_MWI_STORE_TYPE_STORE) { - // Store message because TP_UDH indicates so, note this may override - // the setting in DCS, but that is expected - mwi.discard = false; - } else if (mwi.discard === undefined) { - // storeType == PDU_MWI_STORE_TYPE_DISCARD - // only override mwi.discard here if it hasn't already been set - mwi.discard = true; - } - - mwi.msgCount = msgCount & 0xFF; - mwi.active = mwi.msgCount > 0; - - if (DEBUG) { - this.context.debug("MWI in TP_UDH received: " + JSON.stringify(mwi)); - } - break; - } - default: - // Drop unsupported id - for (let i = 0; i < length; i++) { - BitBufferHelper.readBits(8); - } - } - } - - // Consume padding bits - if (headerPaddingBits) { - BitBufferHelper.readBits(headerPaddingBits); - } - - return header; - }, - - getCdmaMsgEncoding: function(encoding) { - // Determine encoding method - switch (encoding) { - case PDU_CDMA_MSG_CODING_7BITS_ASCII: - case PDU_CDMA_MSG_CODING_IA5: - case PDU_CDMA_MSG_CODING_7BITS_GSM: - return PDU_DCS_MSG_CODING_7BITS_ALPHABET; - case PDU_CDMA_MSG_CODING_OCTET: - case PDU_CDMA_MSG_CODING_IS_91: - case PDU_CDMA_MSG_CODING_LATIN_HEBREW: - case PDU_CDMA_MSG_CODING_LATIN: - return PDU_DCS_MSG_CODING_8BITS_ALPHABET; - case PDU_CDMA_MSG_CODING_UNICODE: - case PDU_CDMA_MSG_CODING_SHIFT_JIS: - case PDU_CDMA_MSG_CODING_KOREAN: - return PDU_DCS_MSG_CODING_16BITS_ALPHABET; - } - return null; - }, - - decodeCdmaPDUMsg: function(encoding, msgType, msgBodySize) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - let BitBufferHelper = this.context.BitBufferHelper; - let result = ""; - let msgDigit; - switch (encoding) { - case PDU_CDMA_MSG_CODING_OCTET: // TODO : Require Test - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(8)); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_IS_91: // TODO : Require Test - // Referenced from android code - switch (msgType) { - case PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS: - case PDU_CDMA_MSG_CODING_IS_91_TYPE_SMS_FULL: - case PDU_CDMA_MSG_CODING_IS_91_TYPE_VOICEMAIL_STATUS: - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(6) + 0x20); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_IS_91_TYPE_CLI: - let addrInfo = {}; - addrInfo.digitMode = PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF; - addrInfo.numberMode = PDU_CDMA_MSG_ADDR_NUMBER_MODE_ANSI; - addrInfo.numberType = PDU_CDMA_MSG_ADDR_NUMBER_TYPE_UNKNOWN; - addrInfo.numberPlan = PDU_CDMA_MSG_ADDR_NUMBER_PLAN_UNKNOWN; - addrInfo.addrLength = msgBodySize; - addrInfo.address = []; - for (let i = 0; i < addrInfo.addrLength; i++) { - addrInfo.address.push(BitBufferHelper.readBits(4)); - } - result = this.decodeAddr(addrInfo); - break; - } - // Fall through. - case PDU_CDMA_MSG_CODING_7BITS_ASCII: - case PDU_CDMA_MSG_CODING_IA5: // TODO : Require Test - while(msgBodySize > 0) { - msgDigit = BitBufferHelper.readBits(7); - if (msgDigit >= 32) { - msgDigit = String.fromCharCode(msgDigit); - } else { - if (msgDigit !== PDU_NL_EXTENDED_ESCAPE) { - msgDigit = langTable[msgDigit]; - } else { - msgDigit = BitBufferHelper.readBits(7); - msgBodySize--; - msgDigit = langShiftTable[msgDigit]; - } - } - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_UNICODE: - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(16)); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_7BITS_GSM: // TODO : Require Test - while(msgBodySize > 0) { - msgDigit = BitBufferHelper.readBits(7); - if (msgDigit !== PDU_NL_EXTENDED_ESCAPE) { - msgDigit = langTable[msgDigit]; - } else { - msgDigit = BitBufferHelper.readBits(7); - msgBodySize--; - msgDigit = langShiftTable[msgDigit]; - } - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_LATIN: // TODO : Require Test - // Reference : http://en.wikipedia.org/wiki/ISO/IEC_8859-1 - while(msgBodySize > 0) { - msgDigit = String.fromCharCode(BitBufferHelper.readBits(8)); - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_LATIN_HEBREW: // TODO : Require Test - // Reference : http://en.wikipedia.org/wiki/ISO/IEC_8859-8 - while(msgBodySize > 0) { - msgDigit = BitBufferHelper.readBits(8); - if (msgDigit === 0xDF) { - msgDigit = String.fromCharCode(0x2017); - } else if (msgDigit === 0xFD) { - msgDigit = String.fromCharCode(0x200E); - } else if (msgDigit === 0xFE) { - msgDigit = String.fromCharCode(0x200F); - } else if (msgDigit >= 0xE0 && msgDigit <= 0xFA) { - msgDigit = String.fromCharCode(0x4F0 + msgDigit); - } else { - msgDigit = String.fromCharCode(msgDigit); - } - result += msgDigit; - msgBodySize--; - } - break; - case PDU_CDMA_MSG_CODING_SHIFT_JIS: - // Reference : http://msdn.microsoft.com/en-US/goglobal/cc305152.aspx - // http://demo.icu-project.org/icu-bin/convexp?conv=Shift_JIS - let shift_jis_message = []; - - while (msgBodySize > 0) { - shift_jis_message.push(BitBufferHelper.readBits(8)); - msgBodySize--; - } - - let decoder = new TextDecoder("shift_jis"); - result = decoder.decode(new Uint8Array(shift_jis_message)); - break; - case PDU_CDMA_MSG_CODING_KOREAN: - case PDU_CDMA_MSG_CODING_GSM_DCS: - // Fall through. - default: - break; - } - return result; - }, - - /** - * User data subparameter decoder : User Data - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.2 User Data - */ - decodeUserDataMsg: function(hasUserHeader) { - let BitBufferHelper = this.context.BitBufferHelper; - let result = {}, - encoding = BitBufferHelper.readBits(5), - msgType; - - if (encoding === PDU_CDMA_MSG_CODING_IS_91) { - msgType = BitBufferHelper.readBits(8); - } - result.encoding = this.getCdmaMsgEncoding(encoding); - - let msgBodySize = BitBufferHelper.readBits(8); - - // For segmented SMS, a user header is included before sms content - if (hasUserHeader) { - result.header = this.decodeUserDataHeader(result.encoding); - // header size is included in body size, they are decoded - msgBodySize -= result.header.length; - } - - // Store original payload if enconding is OCTET for further handling of WAP Push, etc. - if (encoding === PDU_CDMA_MSG_CODING_OCTET && msgBodySize > 0) { - result.data = new Uint8Array(msgBodySize); - for (let i = 0; i < msgBodySize; i++) { - result.data[i] = BitBufferHelper.readBits(8); - } - BitBufferHelper.backwardReadPilot(8 * msgBodySize); - } - - // Decode sms content - result.body = this.decodeCdmaPDUMsg(encoding, msgType, msgBodySize); - - return result; - }, - - decodeBcd: function(value) { - return ((value >> 4) & 0xF) * 10 + (value & 0x0F); - }, - - /** - * User data subparameter decoder : Time Stamp - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.4 Message Center Time Stamp - */ - decodeUserDataTimestamp: function() { - let BitBufferHelper = this.context.BitBufferHelper; - let year = this.decodeBcd(BitBufferHelper.readBits(8)), - month = this.decodeBcd(BitBufferHelper.readBits(8)) - 1, - date = this.decodeBcd(BitBufferHelper.readBits(8)), - hour = this.decodeBcd(BitBufferHelper.readBits(8)), - min = this.decodeBcd(BitBufferHelper.readBits(8)), - sec = this.decodeBcd(BitBufferHelper.readBits(8)); - - if (year >= 96 && year <= 99) { - year += 1900; - } else { - year += 2000; - } - - let result = (new Date(year, month, date, hour, min, sec, 0)).valueOf(); - - return result; - }, - - /** - * User data subparameter decoder : Reply Option - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.11 Reply Option - */ - decodeUserDataReplyOption: function() { - let replyAction = this.context.BitBufferHelper.readBits(4), - result = { userAck: (replyAction & 0x8) ? true : false, - deliverAck: (replyAction & 0x4) ? true : false, - readAck: (replyAction & 0x2) ? true : false, - report: (replyAction & 0x1) ? true : false - }; - - return result; - }, - - /** - * User data subparameter decoder : Language Indicator - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.14 Language Indicator - */ - decodeLanguageIndicator: function() { - let language = this.context.BitBufferHelper.readBits(8); - let result = CB_CDMA_LANG_GROUP[language]; - return result; - }, - - /** - * User data subparameter decoder : Call-Back Number - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.15 Call-Back Number - */ - decodeUserDataCallbackNumber: function() { - let BitBufferHelper = this.context.BitBufferHelper; - let digitMode = BitBufferHelper.readBits(1); - if (digitMode) { - let numberType = BitBufferHelper.readBits(3), - numberPlan = BitBufferHelper.readBits(4); - } - let numberFields = BitBufferHelper.readBits(8), - result = ""; - for (let i = 0; i < numberFields; i++) { - if (digitMode === PDU_CDMA_MSG_ADDR_DIGIT_MODE_DTMF) { - let addrDigit = BitBufferHelper.readBits(4); - result += this.dtmfChars.charAt(addrDigit); - } else { - let addrDigit = BitBufferHelper.readBits(8); - result += String.fromCharCode(addrDigit); - } - } - - return result; - }, - - /** - * User data subparameter decoder : Message Status - * - * @see 3GGP2 C.S0015-B 2.0, 4.5.21 Message Status - */ - decodeUserDataMsgStatus: function() { - let BitBufferHelper = this.context.BitBufferHelper; - let result = { - errorClass: BitBufferHelper.readBits(2), - msgStatus: BitBufferHelper.readBits(6) - }; - - return result; - }, - - /** - * Decode information record parcel. - */ - decodeInformationRecord: function() { - let Buf = this.context.Buf; - let records = []; - let numOfRecords = Buf.readInt32(); - - let type; - let record; - for (let i = 0; i < numOfRecords; i++) { - record = {}; - type = Buf.readInt32(); - - switch (type) { - /* - * Every type is encaped by ril, except extended display - */ - case PDU_CDMA_INFO_REC_TYPE_DISPLAY: - case PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY: - record.display = Buf.readString(); - break; - case PDU_CDMA_INFO_REC_TYPE_CALLED_PARTY_NUMBER: - record.calledNumber = {}; - record.calledNumber.number = Buf.readString(); - record.calledNumber.type = Buf.readInt32(); - record.calledNumber.plan = Buf.readInt32(); - record.calledNumber.pi = Buf.readInt32(); - record.calledNumber.si = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_CALLING_PARTY_NUMBER: - record.callingNumber = {}; - record.callingNumber.number = Buf.readString(); - record.callingNumber.type = Buf.readInt32(); - record.callingNumber.plan = Buf.readInt32(); - record.callingNumber.pi = Buf.readInt32(); - record.callingNumber.si = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_CONNECTED_NUMBER: - record.connectedNumber = {}; - record.connectedNumber.number = Buf.readString(); - record.connectedNumber.type = Buf.readInt32(); - record.connectedNumber.plan = Buf.readInt32(); - record.connectedNumber.pi = Buf.readInt32(); - record.connectedNumber.si = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_SIGNAL: - record.signal = {}; - if (!Buf.readInt32()) { // Non-zero if signal is present. - Buf.seekIncoming(3 * Buf.UINT32_SIZE); - continue; - } - record.signal.type = Buf.readInt32(); - record.signal.alertPitch = Buf.readInt32(); - record.signal.signal = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_REDIRECTING_NUMBER: - record.redirect = {}; - record.redirect.number = Buf.readString(); - record.redirect.type = Buf.readInt32(); - record.redirect.plan = Buf.readInt32(); - record.redirect.pi = Buf.readInt32(); - record.redirect.si = Buf.readInt32(); - record.redirect.reason = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_LINE_CONTROL: - record.lineControl = {}; - record.lineControl.polarityIncluded = Buf.readInt32(); - record.lineControl.toggle = Buf.readInt32(); - record.lineControl.reverse = Buf.readInt32(); - record.lineControl.powerDenial = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_T53_CLIR: - record.clirCause = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_T53_AUDIO_CONTROL: - record.audioControl = {}; - record.audioControl.upLink = Buf.readInt32(); - record.audioControl.downLink = Buf.readInt32(); - break; - case PDU_CDMA_INFO_REC_TYPE_T53_RELEASE: - // Fall through - default: - throw new Error("UNSOLICITED_CDMA_INFO_REC(), Unsupported information record type " + type + "\n"); - } - - records.push(record); - } - - return records; - } -}; - -/** - * Helper for processing ICC PDUs. - */ -function ICCPDUHelperObject(aContext) { - this.context = aContext; -} -ICCPDUHelperObject.prototype = { - context: null, - - /** - * Read GSM 8-bit unpacked octets, - * which are default 7-bit alphabets with bit 8 set to 0. - * - * @param numOctets - * Number of octets to be read. - */ - read8BitUnpackedToString: function(numOctets) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let ret = ""; - let escapeFound = false; - let i; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - for(i = 0; i < numOctets; i++) { - let octet = GsmPDUHelper.readHexOctet(); - if (octet == 0xff) { - i++; - break; - } - - if (escapeFound) { - escapeFound = false; - if (octet == PDU_NL_EXTENDED_ESCAPE) { - // According to 3GPP TS 23.038, section 6.2.1.1, NOTE 1, "On - // receipt of this code, a receiving entity shall display a space - // until another extensiion table is defined." - ret += " "; - } else if (octet == PDU_NL_RESERVED_CONTROL) { - // According to 3GPP TS 23.038 B.2, "This code represents a control - // character and therefore must not be used for language specific - // characters." - ret += " "; - } else { - ret += langShiftTable[octet]; - } - } else if (octet == PDU_NL_EXTENDED_ESCAPE) { - escapeFound = true; - } else { - ret += langTable[octet]; - } - } - - let Buf = this.context.Buf; - Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE); - return ret; - }, - - /** - * Write GSM 8-bit unpacked octets. - * - * @param numOctets Number of total octets to be writen, including trailing - * 0xff. - * @param str String to be written. Could be null. - * - * @return The string has been written into Buf. "" if str is null. - */ - writeStringTo8BitUnpacked: function(numOctets, str) { - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - let GsmPDUHelper = this.context.GsmPDUHelper; - - // If the character is GSM extended alphabet, two octets will be written. - // So we need to keep track of number of octets to be written. - let i, j; - let len = str ? str.length : 0; - for (i = 0, j = 0; i < len && j < numOctets; i++) { - let c = str.charAt(i); - let octet = langTable.indexOf(c); - - if (octet == -1) { - // Make sure we still have enough space to write two octets. - if (j + 2 > numOctets) { - break; - } - - octet = langShiftTable.indexOf(c); - if (octet == -1) { - // Fallback to ASCII space. - octet = langTable.indexOf(' '); - } else { - GsmPDUHelper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - j++; - } - } - GsmPDUHelper.writeHexOctet(octet); - j++; - } - - // trailing 0xff - while (j++ < numOctets) { - GsmPDUHelper.writeHexOctet(0xff); - } - - return (str) ? str.substring(0, i) : ""; - }, - - /** - * Write UCS2 String on UICC. - * The default choose 0x81 or 0x82 encode, otherwise use 0x80 encode. - * - * @see TS 102.221, Annex A. - * @param numOctets - * Total number of octets to be written. This includes the length of - * alphaId and the length of trailing unused octets(0xff). - * @param str - * String to be written. - * - * @return The string has been written into Buf. - */ - writeICCUCS2String: function(numOctets, str) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let scheme = 0x80; - let basePointer; - - if (str.length > 2) { - let min = 0xFFFF; - let max = 0; - for (let i = 0; i < str.length; i++) { - let code = str.charCodeAt(i); - // filter out GSM Default Alphabet character - if (code & 0xFF80) { - if (min > code) { - min = code; - } - if (max < code) { - max = code; - } - } - } - - // 0x81 and 0x82 only support 'half-page', i.e., 128 characters. - if ((max - min) >= 0 && (max - min) < 128) { - // 0x81 base pointer is 0hhh hhhh h000 0000, and bit 16 is set to zero, - // therefore it can't compute 0x8000~0xFFFF. - // Since 0x81 only support 128 characters, - // either XX00~XX7f(bit 8 are 0) or XX80~XXff(bit 8 are 1) - if (((min & 0x7f80) == (max & 0x7f80)) && - ((max & 0x8000) == 0)) { - scheme = 0x81; - basePointer = min & 0x7f80; - } else { - scheme = 0x82; - basePointer = min; - } - } - } - - switch (scheme) { - /** - * +------+---------+---------+---------+---------+------+------+ - * | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff | - * +------+---------+---------+---------+---------+------+------+ - */ - case 0x80: { - // 0x80 support UCS2 0000~ffff - GsmPDUHelper.writeHexOctet(0x80); - numOctets--; - // Now the str is UCS2 string, each character will take 2 octets. - if (str.length * 2 > numOctets) { - str = str.substring(0, Math.floor(numOctets / 2)); - } - GsmPDUHelper.writeUCS2String(str); - - // trailing 0xff - for (let i = str.length * 2; i < numOctets; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - return str; - } - /** - * +------+-----+--------------+-----+-----+-----+--------+------+ - * | 0x81 | len | base_pointer | Ch1 | Ch2 | ... | Ch_len | 0xff | - * +------+-----+--------------+-----+-----+-----+--------+------+ - * - * len: The length of characters. - * base_pointer: 0hhh hhhh h000 0000 - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n - base_pointer) | 0x80 - * - */ - case 0x81: { - GsmPDUHelper.writeHexOctet(0x81); - - if (str.length > (numOctets - 3)) { - str = str.substring(0, numOctets - 3); - } - - GsmPDUHelper.writeHexOctet(str.length); - GsmPDUHelper.writeHexOctet((basePointer >> 7) & 0xff); - numOctets -= 3; - break; - } - /* +------+-----+------------------+------------------+-----+-----+-----+--------+ - * | 0x82 | len | base_pointer_msb | base_pointer_lsb | Ch1 | Ch2 | ... | Ch_len | - * +------+-----+------------------+------------------+-----+-----+-----+--------+ - * - * len: The length of characters. - * base_pointer_msb, base_pointer_lsn: base_pointer - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n - base_pointer) | 0x80 - */ - case 0x82: { - GsmPDUHelper.writeHexOctet(0x82); - - if (str.length > (numOctets - 4)) { - str = str.substring(0, numOctets - 4); - } - - GsmPDUHelper.writeHexOctet(str.length); - GsmPDUHelper.writeHexOctet((basePointer >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(basePointer & 0xff); - numOctets -= 4; - break; - } - } - - if (scheme == 0x81 || scheme == 0x82) { - for (let i = 0; i < str.length; i++) { - let code = str.charCodeAt(i); - - // bit 8 = 0, - // GSM default alphabets - if (code >> 8 == 0) { - GsmPDUHelper.writeHexOctet(code & 0x7F); - } else { - // bit 8 = 1, - // UCS2 character whose char code is (code - basePointer) | 0x80 - GsmPDUHelper.writeHexOctet((code - basePointer) | 0x80); - } - } - - // trailing 0xff - for (let i = 0; i < numOctets - str.length; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - } - return str; - }, - - /** - * Read UCS2 String on UICC. - * - * @see TS 101.221, Annex A. - * @param scheme - * Coding scheme for UCS2 on UICC. One of 0x80, 0x81 or 0x82. - * @param numOctets - * Number of octets to be read as UCS2 string. - */ - readICCUCS2String: function(scheme, numOctets) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let str = ""; - switch (scheme) { - /** - * +------+---------+---------+---------+---------+------+------+ - * | 0x80 | Ch1_msb | Ch1_lsb | Ch2_msb | Ch2_lsb | 0xff | 0xff | - * +------+---------+---------+---------+---------+------+------+ - */ - case 0x80: - let isOdd = numOctets % 2; - let i; - for (i = 0; i < numOctets - isOdd; i += 2) { - let code = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - if (code == 0xffff) { - i += 2; - break; - } - str += String.fromCharCode(code); - } - - // Skip trailing 0xff - Buf.seekIncoming((numOctets - i) * Buf.PDU_HEX_OCTET_SIZE); - break; - case 0x81: // Fall through - case 0x82: - /** - * +------+-----+--------+-----+-----+-----+--------+------+ - * | 0x81 | len | offset | Ch1 | Ch2 | ... | Ch_len | 0xff | - * +------+-----+--------+-----+-----+-----+--------+------+ - * - * len : The length of characters. - * offset : 0hhh hhhh h000 0000 - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n & 0x7f) + offset - * - * +------+-----+------------+------------+-----+-----+-----+--------+ - * | 0x82 | len | offset_msb | offset_lsb | Ch1 | Ch2 | ... | Ch_len | - * +------+-----+------------+------------+-----+-----+-----+--------+ - * - * len : The length of characters. - * offset_msb, offset_lsn: offset - * Ch_n: bit 8 = 0 - * GSM default alphabets - * bit 8 = 1 - * UCS2 character whose char code is (Ch_n & 0x7f) + offset - */ - let len = GsmPDUHelper.readHexOctet(); - let offset, headerLen; - if (scheme == 0x81) { - offset = GsmPDUHelper.readHexOctet() << 7; - headerLen = 2; - } else { - offset = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - headerLen = 3; - } - - for (let i = 0; i < len; i++) { - let ch = GsmPDUHelper.readHexOctet(); - if (ch & 0x80) { - // UCS2 - str += String.fromCharCode((ch & 0x7f) + offset); - } else { - // GSM 8bit - let count = 0, gotUCS2 = 0; - while ((i + count + 1 < len)) { - count++; - if (GsmPDUHelper.readHexOctet() & 0x80) { - gotUCS2 = 1; - break; - } - } - // Unread. - // +1 for the GSM alphabet indexed at i, - Buf.seekIncoming(-1 * (count + 1) * Buf.PDU_HEX_OCTET_SIZE); - str += this.read8BitUnpackedToString(count + 1 - gotUCS2); - i += count - gotUCS2; - } - } - - // Skipping trailing 0xff - Buf.seekIncoming((numOctets - len - headerLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - return str; - }, - - /** - * Read Alpha Id and Dialling number from TS TS 151.011 clause 10.5.1 - * - * @param recordSize The size of linear fixed record. - */ - readAlphaIdDiallingNumber: function(recordSize) { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - - let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; - let alphaId = this.readAlphaIdentifier(alphaLen); - - let number = this.readNumberWithLength(); - - // Skip unused octet, CCP - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - - let extRecordNumber = this.context.GsmPDUHelper.readHexOctet(); - Buf.readStringDelimiter(length); - - let contact = null; - if (alphaId || number) { - contact = {alphaId: alphaId, - number: number, - extRecordNumber: extRecordNumber}; - } - - return contact; - }, - - /** - * Write Alpha Identifier and Dialling number from TS 151.011 clause 10.5.1 - * - * @param recordSize The size of linear fixed record. - * @param alphaId Alpha Identifier to be written. - * @param number Dialling Number to be written. - * @param extRecordNumber The record identifier of the EXT. - * - * @return An object contains the alphaId and number - * that have been written into Buf. - */ - writeAlphaIdDiallingNumber: function(recordSize, alphaId, number, extRecordNumber) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - let alphaLen = recordSize - ADN_FOOTER_SIZE_BYTES; - let writtenAlphaId = this.writeAlphaIdentifier(alphaLen, alphaId); - let writtenNumber = this.writeNumberWithLength(number); - - // Write unused CCP octet 0xff. - GsmPDUHelper.writeHexOctet(0xff); - GsmPDUHelper.writeHexOctet((extRecordNumber != null) ? extRecordNumber : 0xff); - - Buf.writeStringDelimiter(strLen); - - return {alphaId: writtenAlphaId, - number: writtenNumber}; - }, - - /** - * Read Alpha Identifier. - * - * @see TS 131.102 - * - * @param numOctets - * Number of octets to be read. - * - * It uses either - * 1. SMS default 7-bit alphabet with bit 8 set to 0. - * 2. UCS2 string. - * - * Unused bytes should be set to 0xff. - */ - readAlphaIdentifier: function(numOctets) { - if (numOctets === 0) { - return ""; - } - - let temp; - // Read the 1st octet to determine the encoding. - if ((temp = this.context.GsmPDUHelper.readHexOctet()) == 0x80 || - temp == 0x81 || - temp == 0x82) { - numOctets--; - return this.readICCUCS2String(temp, numOctets); - } else { - let Buf = this.context.Buf; - Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE); - return this.read8BitUnpackedToString(numOctets); - } - }, - - /** - * Write Alpha Identifier. - * - * @param numOctets - * Total number of octets to be written. This includes the length of - * alphaId and the length of trailing unused octets(0xff). - * @param alphaId - * Alpha Identifier to be written. - * - * @return The Alpha Identifier has been written into Buf. - * - * Unused octets will be written as 0xff. - */ - writeAlphaIdentifier: function(numOctets, alphaId) { - if (numOctets === 0) { - return ""; - } - - // If alphaId is empty or it's of GSM 8 bit. - if (!alphaId || this.context.ICCUtilsHelper.isGsm8BitAlphabet(alphaId)) { - return this.writeStringTo8BitUnpacked(numOctets, alphaId); - } else { - return this.writeICCUCS2String(numOctets, alphaId); - } - }, - - /** - * Read Dialling number. - * - * @see TS 131.102 - * - * @param len - * The Length of BCD number. - * - * From TS 131.102, in EF_ADN, EF_FDN, the field 'Length of BCD number' - * means the total bytes should be allocated to store the TON/NPI and - * the dialing number. - * For example, if the dialing number is 1234567890, - * and the TON/NPI is 0x81, - * The field 'Length of BCD number' should be 06, which is - * 1 byte to store the TON/NPI, 0x81 - * 5 bytes to store the BCD number 2143658709. - * - * Here the definition of the length is different from SMS spec, - * TS 23.040 9.1.2.5, which the length means - * "number of useful semi-octets within the Address-Value field". - */ - readDiallingNumber: function(len) { - if (DEBUG) this.context.debug("PDU: Going to read Dialling number: " + len); - if (len === 0) { - return ""; - } - - let GsmPDUHelper = this.context.GsmPDUHelper; - - // TOA = TON + NPI - let toa = GsmPDUHelper.readHexOctet(); - - let number = GsmPDUHelper.readSwappedNibbleExtendedBcdString(len - 1); - if (number.length <= 0) { - if (DEBUG) this.context.debug("No number provided"); - return ""; - } - if ((toa >> 4) == (PDU_TOA_INTERNATIONAL >> 4)) { - number = '+' + number; - } - return number; - }, - - /** - * Write Dialling Number. - * - * @param number The Dialling number - */ - writeDiallingNumber: function(number) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let toa = PDU_TOA_ISDN; // 81 - if (number[0] == '+') { - toa = PDU_TOA_INTERNATIONAL | PDU_TOA_ISDN; // 91 - number = number.substring(1); - } - GsmPDUHelper.writeHexOctet(toa); - GsmPDUHelper.writeSwappedNibbleBCD(number); - }, - - readNumberWithLength: function() { - let Buf = this.context.Buf; - let number = ""; - let numLen = this.context.GsmPDUHelper.readHexOctet(); - if (numLen != 0xff) { - if (numLen > ADN_MAX_BCD_NUMBER_BYTES) { - if (DEBUG) { - this.context.debug( - "Error: invalid length of BCD number/SSC contents - " + numLen); - } - Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - return number; - } - - number = this.readDiallingNumber(numLen); - Buf.seekIncoming((ADN_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE); - } else { - Buf.seekIncoming(ADN_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - } - - return number; - }, - - /** - * Write Number with Length - * - * @param number The value to be written. - * - * @return The number has been written into Buf. - */ - writeNumberWithLength: function(number) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - if (number) { - let numStart = number[0] == "+" ? 1 : 0; - let writtenNumber = number.substring(0, numStart) + - number.substring(numStart) - .replace(/[^0-9*#,]/g, ""); - let numDigits = writtenNumber.length - numStart; - - if (numDigits > ADN_MAX_NUMBER_DIGITS) { - writtenNumber = writtenNumber.substring(0, ADN_MAX_NUMBER_DIGITS + numStart); - numDigits = writtenNumber.length - numStart; - } - - // +1 for TON/NPI - let numLen = Math.ceil(numDigits / 2) + 1; - GsmPDUHelper.writeHexOctet(numLen); - this.writeDiallingNumber(writtenNumber.replace(/\*/g, "a") - .replace(/\#/g, "b") - .replace(/\,/g, "c")); - // Write trailing 0xff of Dialling Number. - for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES - numLen; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - return writtenNumber; - } else { - // +1 for numLen - for (let i = 0; i < ADN_MAX_BCD_NUMBER_BYTES + 1; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - return ""; - } - } -}; - -function StkCommandParamsFactoryObject(aContext) { - this.context = aContext; -} -StkCommandParamsFactoryObject.prototype = { - context: null, - - createParam: function(cmdDetails, ctlvs, onComplete) { - let method = this[cmdDetails.typeOfCommand]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Unknown proactive command " + - cmdDetails.typeOfCommand.toString(16)); - } - return; - } - method.call(this, cmdDetails, ctlvs, onComplete); - }, - - loadIcons: function(iconIdCtlvs, callback) { - if (!iconIdCtlvs || - !this.context.ICCUtilsHelper.isICCServiceAvailable("IMG")) { - callback(null); - return; - } - - let onerror = (function() { - callback(null); - }).bind(this); - - let onsuccess = (function(aIcons) { - callback(aIcons); - }).bind(this); - - this.context.IconLoader.loadIcons(iconIdCtlvs.map(aCtlv => aCtlv.value.identifier), - onsuccess, - onerror); - }, - - appendIconIfNecessary: function(iconIdCtlvs, result, onComplete) { - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - result.icons = aIcons[0]; - result.iconSelfExplanatory = - iconIdCtlvs[0].value.qualifier == 0 ? true : false; - } - - onComplete(result); - }); - }, - - /** - * Construct a param for Refresh. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processRefresh: function(cmdDetails, ctlvs, onComplete) { - let refreshType = cmdDetails.commandQualifier; - switch (refreshType) { - case STK_REFRESH_FILE_CHANGE: - case STK_REFRESH_NAA_INIT_AND_FILE_CHANGE: - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_FILE_LIST, ctlvs); - if (ctlv) { - let list = ctlv.value.fileList; - if (DEBUG) { - this.context.debug("Refresh, list = " + list); - } - this.context.ICCRecordHelper.fetchICCRecords(); - } - break; - } - - onComplete(null); - }, - - /** - * Construct a param for Poll Interval. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processPollInterval: function(cmdDetails, ctlvs, onComplete) { - // Duration is mandatory. - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_DURATION, ctlvs); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Poll Interval: Required value missing : Duration"); - } - - onComplete(ctlv.value); - }, - - /** - * Construct a param for Poll Off. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processPollOff: function(cmdDetails, ctlvs, onComplete) { - onComplete(null); - }, - - /** - * Construct a param for Set Up Event list. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetUpEventList: function(cmdDetails, ctlvs, onComplete) { - // Event list is mandatory. - let ctlv = this.context.StkProactiveCmdHelper.searchForTag( - COMPREHENSIONTLV_TAG_EVENT_LIST, ctlvs); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Event List: Required value missing : Event List"); - } - - onComplete(ctlv.value || { eventList: null }); - }, - - /** - * Construct a param for Setup Menu. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetupMenu: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let menu = { - // Help information available. - isHelpAvailable: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ITEM, - COMPREHENSIONTLV_TAG_ITEM_ID, - COMPREHENSIONTLV_TAG_NEXT_ACTION_IND, - COMPREHENSIONTLV_TAG_ICON_ID, - COMPREHENSIONTLV_TAG_ICON_ID_LIST - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - menu.title = ctlv.value.identifier; - } - - // Item data object for item 1 is mandatory. - let menuCtlvs = selectedCtlvs[COMPREHENSIONTLV_TAG_ITEM]; - if (!menuCtlvs) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Menu: Required value missing : items"); - } - menu.items = menuCtlvs.map(aCtlv => aCtlv.value); - - // Item identifier is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ITEM_ID); - if (ctlv) { - menu.defaultItem = ctlv.value.identifier - 1; - } - - // Items next action indicator is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_NEXT_ACTION_IND); - if (ctlv) { - menu.nextActionList = ctlv.value; - } - - // Icon identifier is optional. - let iconIdCtlvs = null; - let menuIconCtlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ICON_ID); - if (menuIconCtlv) { - iconIdCtlvs = [menuIconCtlv]; - } - - // Item icon identifier list is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ICON_ID_LIST); - if (ctlv) { - if (!iconIdCtlvs) { - iconIdCtlvs = []; - }; - let iconIdList = ctlv.value; - iconIdCtlvs = iconIdCtlvs.concat(iconIdList.identifiers.map((aId) => { - return { - value: { qualifier: iconIdList.qualifier, identifier: aId } - }; - })); - } - - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - if (menuIconCtlv) { - menu.iconSelfExplanatory = - (iconIdCtlvs.shift().value.qualifier == 0) ? true: false; - menu.icons = aIcons.shift(); - } - - for (let i = 0; i < aIcons.length; i++) { - menu.items[i].icons = aIcons[i]; - menu.items[i].iconSelfExplanatory = - (iconIdCtlvs[i].value.qualifier == 0) ? true: false; - } - } - - onComplete(menu); - }); - }, - - /** - * Construct a param for Select Item. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSelectItem: function(cmdDetails, ctlvs, onComplete) { - this.processSetupMenu(cmdDetails, ctlvs, (menu) => { - // The 1st bit and 2nd bit determines the presentation type. - menu.presentationType = cmdDetails.commandQualifier & 0x03; - onComplete(menu); - }); - }, - - /** - * Construct a param for Display Text. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processDisplayText: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let textMsg = { - isHighPriority: !!(cmdDetails.commandQualifier & 0x01), - userClear: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE, - COMPREHENSIONTLV_TAG_DURATION, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Display Text: Required value missing : Text String"); - } - textMsg.text = ctlv.value.textString; - - // Immediate response is optional. - textMsg.responseNeeded = - !!(selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE)); - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - textMsg.duration = ctlv.value; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - textMsg, - onComplete); - }, - - /** - * Construct a param for Setup Idle Mode Text. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetUpIdleModeText: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let textMsg = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Set Up Idle Text: Required value missing : Text String"); - } - textMsg.text = ctlv.value.textString; - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - textMsg, - onComplete); - }, - - /** - * Construct a param for Get Inkey. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processGetInkey: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let input = { - minLength: 1, - maxLength: 1, - isAlphabet: !!(cmdDetails.commandQualifier & 0x01), - isUCS2: !!(cmdDetails.commandQualifier & 0x02), - // Character sets defined in bit 1 and bit 2 are disable and - // the YES/NO reponse is required. - isYesNoRequested: !!(cmdDetails.commandQualifier & 0x04), - // Help information available. - isHelpAvailable: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_DURATION, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Get InKey: Required value missing : Text String"); - } - input.text = ctlv.value.textString; - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - input.duration = ctlv.value; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - input, - onComplete); - }, - - /** - * Construct a param for Get Input. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processGetInput: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let input = { - isAlphabet: !!(cmdDetails.commandQualifier & 0x01), - isUCS2: !!(cmdDetails.commandQualifier & 0x02), - // User input shall not be revealed - hideInput: !!(cmdDetails.commandQualifier & 0x04), - // User input in SMS packed format - isPacked: !!(cmdDetails.commandQualifier & 0x08), - // Help information available. - isHelpAvailable: !!(cmdDetails.commandQualifier & 0x80) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TEXT_STRING, - COMPREHENSIONTLV_TAG_RESPONSE_LENGTH, - COMPREHENSIONTLV_TAG_DEFAULT_TEXT, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Text string is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TEXT_STRING); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Get Input: Required value missing : Text String"); - } - input.text = ctlv.value.textString; - - // Response length is mandatory. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_RESPONSE_LENGTH); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Get Input: Required value missing : Response Length"); - } - input.minLength = ctlv.value.minLength; - input.maxLength = ctlv.value.maxLength; - - // Default text is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DEFAULT_TEXT); - if (ctlv) { - input.defaultText = ctlv.value.textString; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - input, - onComplete); - }, - - /** - * Construct a param for SendSS/SMS/USSD/DTMF. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processEventNotify: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let textMsg = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - textMsg.text = ctlv.value.identifier; - } - - // According to section 6.4.10 of |ETSI TS 102 223|: - // - // - if the alpha identifier is provided by the UICC and is a null data - // object (i.e. length = '00' and no value part), this is an indication - // that the terminal should not give any information to the user on the - // fact that the terminal is sending a short message; - // - // - if the alpha identifier is not provided by the UICC, the terminal may - // give information to the user concerning what is happening. - // - // ICCPDUHelper reads alpha id as an empty string if the length is zero, - // hence we'll notify the caller when it's not an empty string. - if (textMsg.text !== "") { - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - textMsg, - onComplete); - } - }, - - /** - * Construct a param for Setup Call. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processSetupCall: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let call = {}; - let confirmMessage = {}; - let callMessage = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ADDRESS, - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID, - COMPREHENSIONTLV_TAG_DURATION - ]); - - // Address is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ADDRESS); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Set Up Call: Required value missing : Address"); - } - call.address = ctlv.value.number; - - // Alpha identifier (user confirmation phase) is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - confirmMessage.text = ctlv.value.identifier; - call.confirmMessage = confirmMessage; - } - - // Alpha identifier (call set up phase) is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - callMessage.text = ctlv.value.identifier; - call.callMessage = callMessage; - } - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - call.duration = ctlv.value; - } - - // Icon identifier is optional. - let iconIdCtlvs = selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null; - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - confirmMessage.icons = aIcons[0]; - confirmMessage.iconSelfExplanatory = - (iconIdCtlvs[0].value.qualifier == 0) ? true: false; - call.confirmMessage = confirmMessage; - - if (aIcons.length > 1) { - callMessage.icons = aIcons[1]; - callMessage.iconSelfExplanatory = - (iconIdCtlvs[1].value.qualifier == 0) ? true: false; - call.callMessage = callMessage; - } - } - - onComplete(call); - }); - }, - - /** - * Construct a param for Launch Browser. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processLaunchBrowser: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let browser = { - mode: cmdDetails.commandQualifier & 0x03 - }; - let confirmMessage = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_URL, - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // URL is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_URL); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Launch Browser: Required value missing : URL"); - } - browser.url = ctlv.value.url; - - // Alpha identifier is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - confirmMessage.text = ctlv.value.identifier; - browser.confirmMessage = confirmMessage; - } - - // Icon identifier is optional. - let iconIdCtlvs = selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null; - this.loadIcons(iconIdCtlvs, (aIcons) => { - if (aIcons) { - confirmMessage.icons = aIcons[0]; - confirmMessage.iconSelfExplanatory = - (iconIdCtlvs[0].value.qualifier == 0) ? true: false; - browser.confirmMessage = confirmMessage; - } - - onComplete(browser); - }); - }, - - /** - * Construct a param for Play Tone. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processPlayTone: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let playTone = { - // The vibrate is only defined in TS 102.223. - isVibrate: !!(cmdDetails.commandQualifier & 0x01) - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_TONE, - COMPREHENSIONTLV_TAG_DURATION, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - playTone.text = ctlv.value.identifier; - } - - // Tone is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TONE); - if (ctlv) { - playTone.tone = ctlv.value.tone; - } - - // Duration is optional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_DURATION); - if (ctlv) { - playTone.duration = ctlv.value; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - playTone, - onComplete); - }, - - /** - * Construct a param for Provide Local Information. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processProvideLocalInfo: function(cmdDetails, ctlvs, onComplete) { - let provideLocalInfo = { - localInfoType: cmdDetails.commandQualifier - }; - - onComplete(provideLocalInfo); - }, - - /** - * Construct a param for Timer Management. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processTimerManagement: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let timer = { - timerAction: cmdDetails.commandQualifier - }; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER, - COMPREHENSIONTLV_TAG_TIMER_VALUE - ]); - - // Timer identifier is mandatory. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER); - if (!ctlv) { - this.context.RIL.sendStkTerminalResponse({ - command: cmdDetails, - resultCode: STK_RESULT_REQUIRED_VALUES_MISSING}); - throw new Error("Stk Timer Management: Required value missing : Timer Identifier"); - } - timer.timerId = ctlv.value.timerId; - - // Timer value is conditional. - ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_TIMER_VALUE); - if (ctlv) { - timer.timerValue = ctlv.value.timerValue; - } - - onComplete(timer); - }, - - /** - * Construct a param for BIP commands. - * - * @param cmdDetails - * The value object of CommandDetails TLV. - * @param ctlvs - * The all TLVs in this proactive command. - * @param onComplete - * Callback to be called when complete. - */ - processBipMessage: function(cmdDetails, ctlvs, onComplete) { - let StkProactiveCmdHelper = this.context.StkProactiveCmdHelper; - let bipMsg = {}; - - let selectedCtlvs = StkProactiveCmdHelper.searchForSelectedTags(ctlvs, [ - COMPREHENSIONTLV_TAG_ALPHA_ID, - COMPREHENSIONTLV_TAG_ICON_ID - ]); - - // Alpha identifier is optional. - let ctlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - if (ctlv) { - bipMsg.text = ctlv.value.identifier; - } - - // Icon identifier is optional. - this.appendIconIfNecessary(selectedCtlvs[COMPREHENSIONTLV_TAG_ICON_ID] || null, - bipMsg, - onComplete); - } -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_REFRESH] = function STK_CMD_REFRESH(cmdDetails, ctlvs, onComplete) { - return this.processRefresh(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_POLL_INTERVAL] = function STK_CMD_POLL_INTERVAL(cmdDetails, ctlvs, onComplete) { - return this.processPollInterval(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_POLL_OFF] = function STK_CMD_POLL_OFF(cmdDetails, ctlvs, onComplete) { - return this.processPollOff(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_PROVIDE_LOCAL_INFO] = function STK_CMD_PROVIDE_LOCAL_INFO(cmdDetails, ctlvs, onComplete) { - return this.processProvideLocalInfo(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_EVENT_LIST] = function STK_CMD_SET_UP_EVENT_LIST(cmdDetails, ctlvs, onComplete) { - return this.processSetUpEventList(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_MENU] = function STK_CMD_SET_UP_MENU(cmdDetails, ctlvs, onComplete) { - return this.processSetupMenu(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SELECT_ITEM] = function STK_CMD_SELECT_ITEM(cmdDetails, ctlvs, onComplete) { - return this.processSelectItem(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_DISPLAY_TEXT] = function STK_CMD_DISPLAY_TEXT(cmdDetails, ctlvs, onComplete) { - return this.processDisplayText(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_IDLE_MODE_TEXT] = function STK_CMD_SET_UP_IDLE_MODE_TEXT(cmdDetails, ctlvs, onComplete) { - return this.processSetUpIdleModeText(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_GET_INKEY] = function STK_CMD_GET_INKEY(cmdDetails, ctlvs, onComplete) { - return this.processGetInkey(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_GET_INPUT] = function STK_CMD_GET_INPUT(cmdDetails, ctlvs, onComplete) { - return this.processGetInput(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_SS] = function STK_CMD_SEND_SS(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_USSD] = function STK_CMD_SEND_USSD(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_SMS] = function STK_CMD_SEND_SMS(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_DTMF] = function STK_CMD_SEND_DTMF(cmdDetails, ctlvs, onComplete) { - return this.processEventNotify(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SET_UP_CALL] = function STK_CMD_SET_UP_CALL(cmdDetails, ctlvs, onComplete) { - return this.processSetupCall(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_LAUNCH_BROWSER] = function STK_CMD_LAUNCH_BROWSER(cmdDetails, ctlvs, onComplete) { - return this.processLaunchBrowser(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_PLAY_TONE] = function STK_CMD_PLAY_TONE(cmdDetails, ctlvs, onComplete) { - return this.processPlayTone(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_TIMER_MANAGEMENT] = function STK_CMD_TIMER_MANAGEMENT(cmdDetails, ctlvs, onComplete) { - return this.processTimerManagement(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_OPEN_CHANNEL] = function STK_CMD_OPEN_CHANNEL(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_CLOSE_CHANNEL] = function STK_CMD_CLOSE_CHANNEL(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_RECEIVE_DATA] = function STK_CMD_RECEIVE_DATA(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; -StkCommandParamsFactoryObject.prototype[STK_CMD_SEND_DATA] = function STK_CMD_SEND_DATA(cmdDetails, ctlvs, onComplete) { - return this.processBipMessage(cmdDetails, ctlvs, onComplete); -}; - -function StkProactiveCmdHelperObject(aContext) { - this.context = aContext; -} -StkProactiveCmdHelperObject.prototype = { - context: null, - - retrieve: function(tag, length) { - let method = this[tag]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Unknown comprehension tag " + tag.toString(16)); - } - let Buf = this.context.Buf; - Buf.seekIncoming(length * Buf.PDU_HEX_OCTET_SIZE); - return null; - } - return method.call(this, length); - }, - - /** - * Command Details. - * - * | Byte | Description | Length | - * | 1 | Command details Tag | 1 | - * | 2 | Length = 03 | 1 | - * | 3 | Command number | 1 | - * | 4 | Type of Command | 1 | - * | 5 | Command Qualifier | 1 | - */ - retrieveCommandDetails: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let cmdDetails = { - commandNumber: GsmPDUHelper.readHexOctet(), - typeOfCommand: GsmPDUHelper.readHexOctet(), - commandQualifier: GsmPDUHelper.readHexOctet() - }; - return cmdDetails; - }, - - /** - * Device Identities. - * - * | Byte | Description | Length | - * | 1 | Device Identity Tag | 1 | - * | 2 | Length = 02 | 1 | - * | 3 | Source device Identity | 1 | - * | 4 | Destination device Id | 1 | - */ - retrieveDeviceId: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let deviceId = { - sourceId: GsmPDUHelper.readHexOctet(), - destinationId: GsmPDUHelper.readHexOctet() - }; - return deviceId; - }, - - /** - * Alpha Identifier. - * - * | Byte | Description | Length | - * | 1 | Alpha Identifier Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 ~ | Alpha identfier | X | - * | (Y-1)+X+2 | | | - */ - retrieveAlphaId: function(length) { - let alphaId = { - identifier: this.context.ICCPDUHelper.readAlphaIdentifier(length) - }; - return alphaId; - }, - - /** - * Duration. - * - * | Byte | Description | Length | - * | 1 | Response Length Tag | 1 | - * | 2 | Lenth = 02 | 1 | - * | 3 | Time unit | 1 | - * | 4 | Time interval | 1 | - */ - retrieveDuration: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let duration = { - timeUnit: GsmPDUHelper.readHexOctet(), - timeInterval: GsmPDUHelper.readHexOctet(), - }; - return duration; - }, - - /** - * Address. - * - * | Byte | Description | Length | - * | 1 | Alpha Identifier Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | TON and NPI | 1 | - * | (Y-1)+4 ~ | Dialling number | X | - * | (Y-1)+X+2 | | | - */ - retrieveAddress: function(length) { - let address = { - number : this.context.ICCPDUHelper.readDiallingNumber(length) - }; - return address; - }, - - /** - * Text String. - * - * | Byte | Description | Length | - * | 1 | Text String Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | Data coding scheme | 1 | - * | (Y-1)+4~ | Text String | X | - * | (Y-1)+X+2 | | | - */ - retrieveTextString: function(length) { - if (!length) { - // null string. - return {textString: null}; - } - - let GsmPDUHelper = this.context.GsmPDUHelper; - let text = { - codingScheme: GsmPDUHelper.readHexOctet() - }; - - length--; // -1 for the codingScheme. - switch (text.codingScheme & 0x0c) { - case STK_TEXT_CODING_GSM_7BIT_PACKED: - text.textString = - GsmPDUHelper.readSeptetsToString(Math.floor(length * 8 / 7), 0, 0, 0); - break; - case STK_TEXT_CODING_GSM_8BIT: - text.textString = - this.context.ICCPDUHelper.read8BitUnpackedToString(length); - break; - case STK_TEXT_CODING_UCS2: - text.textString = GsmPDUHelper.readUCS2String(length); - break; - } - return text; - }, - - /** - * Tone. - * - * | Byte | Description | Length | - * | 1 | Tone Tag | 1 | - * | 2 | Lenth = 01 | 1 | - * | 3 | Tone | 1 | - */ - retrieveTone: function(length) { - let tone = { - tone: this.context.GsmPDUHelper.readHexOctet(), - }; - return tone; - }, - - /** - * Item. - * - * | Byte | Description | Length | - * | 1 | Item Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | Identifier of item | 1 | - * | (Y-1)+4 ~ | Text string of item | X | - * | (Y-1)+X+2 | | | - */ - retrieveItem: function(length) { - // TS 102.223 ,clause 6.6.7 SET-UP MENU - // If the "Item data object for item 1" is a null data object - // (i.e. length = '00' and no value part), this is an indication to the ME - // to remove the existing menu from the menu system in the ME. - if (!length) { - return null; - } - let item = { - identifier: this.context.GsmPDUHelper.readHexOctet(), - text: this.context.ICCPDUHelper.readAlphaIdentifier(length - 1) - }; - return item; - }, - - /** - * Item Identifier. - * - * | Byte | Description | Length | - * | 1 | Item Identifier Tag | 1 | - * | 2 | Lenth = 01 | 1 | - * | 3 | Identifier of Item chosen | 1 | - */ - retrieveItemId: function(length) { - let itemId = { - identifier: this.context.GsmPDUHelper.readHexOctet() - }; - return itemId; - }, - - /** - * Response Length. - * - * | Byte | Description | Length | - * | 1 | Response Length Tag | 1 | - * | 2 | Lenth = 02 | 1 | - * | 3 | Minimum length of response | 1 | - * | 4 | Maximum length of response | 1 | - */ - retrieveResponseLength: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let rspLength = { - minLength : GsmPDUHelper.readHexOctet(), - maxLength : GsmPDUHelper.readHexOctet() - }; - return rspLength; - }, - - /** - * File List. - * - * | Byte | Description | Length | - * | 1 | File List Tag | 1 | - * | 2 ~ (Y-1)+2 | Length (X) | Y | - * | (Y-1)+3 | Number of files | 1 | - * | (Y-1)+4 ~ | Files | X | - * | (Y-1)+X+2 | | | - */ - retrieveFileList: function(length) { - let num = this.context.GsmPDUHelper.readHexOctet(); - let fileList = ""; - length--; // -1 for the num octet. - for (let i = 0; i < 2 * length; i++) { - // Didn't use readHexOctet here, - // otherwise 0x00 will be "0", not "00" - fileList += String.fromCharCode(this.context.Buf.readUint16()); - } - return { - fileList: fileList - }; - }, - - /** - * Default Text. - * - * Same as Text String. - */ - retrieveDefaultText: function(length) { - return this.retrieveTextString(length); - }, - - /** - * Event List. - */ - retrieveEventList: function(length) { - if (!length) { - // null means an indication to ME to remove the existing list of events - // in ME. - return null; - } - - let GsmPDUHelper = this.context.GsmPDUHelper; - let eventList = []; - for (let i = 0; i < length; i++) { - eventList.push(GsmPDUHelper.readHexOctet()); - } - return { - eventList: eventList - }; - }, - - /** - * Icon Id. - * - * | Byte | Description | Length | - * | 1 | Icon Identifier Tag | 1 | - * | 2 | Length = 02 | 1 | - * | 3 | Icon qualifier | 1 | - * | 4 | Icon identifier | 1 | - */ - retrieveIconId: function(length) { - if (!length) { - return null; - } - - let iconId = { - qualifier: this.context.GsmPDUHelper.readHexOctet(), - identifier: this.context.GsmPDUHelper.readHexOctet() - }; - return iconId; - }, - - /** - * Icon Id List. - * - * | Byte | Description | Length | - * | 1 | Icon Identifier Tag | 1 | - * | 2 | Length = X | 1 | - * | 3 | Icon qualifier | 1 | - * | 4~ | Icon identifier | X-1 | - * | 4+X-2 | | | - */ - retrieveIconIdList: function(length) { - if (!length) { - return null; - } - - let iconIdList = { - qualifier: this.context.GsmPDUHelper.readHexOctet(), - identifiers: [] - }; - for (let i = 0; i < length - 1; i++) { - iconIdList.identifiers.push(this.context.GsmPDUHelper.readHexOctet()); - } - return iconIdList; - }, - - /** - * Timer Identifier. - * - * | Byte | Description | Length | - * | 1 | Timer Identifier Tag | 1 | - * | 2 | Length = 01 | 1 | - * | 3 | Timer Identifier | 1 | - */ - retrieveTimerId: function(length) { - let id = { - timerId: this.context.GsmPDUHelper.readHexOctet() - }; - return id; - }, - - /** - * Timer Value. - * - * | Byte | Description | Length | - * | 1 | Timer Value Tag | 1 | - * | 2 | Length = 03 | 1 | - * | 3 | Hour | 1 | - * | 4 | Minute | 1 | - * | 5 | Second | 1 | - */ - retrieveTimerValue: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let value = { - timerValue: (GsmPDUHelper.readSwappedNibbleBcdNum(1) * 60 * 60) + - (GsmPDUHelper.readSwappedNibbleBcdNum(1) * 60) + - (GsmPDUHelper.readSwappedNibbleBcdNum(1)) - }; - return value; - }, - - /** - * Immediate Response. - * - * | Byte | Description | Length | - * | 1 | Immediate Response Tag | 1 | - * | 2 | Length = 00 | 1 | - */ - retrieveImmediaResponse: function(length) { - return {}; - }, - - /** - * URL - * - * | Byte | Description | Length | - * | 1 | URL Tag | 1 | - * | 2 ~ (Y+1) | Length(X) | Y | - * | (Y+2) ~ | URL | X | - * | (Y+1+X) | | | - */ - retrieveUrl: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let s = ""; - for (let i = 0; i < length; i++) { - s += String.fromCharCode(GsmPDUHelper.readHexOctet()); - } - return {url: s}; - }, - - /** - * Next Action Indicator List. - * - * | Byte | Description | Length | - * | 1 | Next Action tag | 1 | - * | 1 | Length(X) | 1 | - * | 3~ | Next Action List | X | - * | 3+X-1 | | | - */ - retrieveNextActionList: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let nextActionList = []; - for (let i = 0; i < length; i++) { - nextActionList.push(GsmPDUHelper.readHexOctet()); - } - return nextActionList; - }, - - searchForTag: function(tag, ctlvs) { - for (let ctlv of ctlvs) { - if ((ctlv.tag & ~COMPREHENSIONTLV_FLAG_CR) == tag) { - return ctlv; - } - } - return null; - }, - - searchForSelectedTags: function(ctlvs, tags) { - let ret = { - // Handy utility to de-queue the 1st ctlv of the specified tag. - retrieve: function(aTag) { - return (this[aTag]) ? this[aTag].shift() : null; - } - }; - - ctlvs.forEach((aCtlv) => { - tags.forEach((aTag) => { - if ((aCtlv.tag & ~COMPREHENSIONTLV_FLAG_CR) == aTag) { - if (!ret[aTag]) { - ret[aTag] = []; - } - ret[aTag].push(aCtlv); - } - }); - }); - - return ret; - }, -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_COMMAND_DETAILS] = function COMPREHENSIONTLV_TAG_COMMAND_DETAILS(length) { - return this.retrieveCommandDetails(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DEVICE_ID] = function COMPREHENSIONTLV_TAG_DEVICE_ID(length) { - return this.retrieveDeviceId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ALPHA_ID] = function COMPREHENSIONTLV_TAG_ALPHA_ID(length) { - return this.retrieveAlphaId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DURATION] = function COMPREHENSIONTLV_TAG_DURATION(length) { - return this.retrieveDuration(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ADDRESS] = function COMPREHENSIONTLV_TAG_ADDRESS(length) { - return this.retrieveAddress(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TEXT_STRING] = function COMPREHENSIONTLV_TAG_TEXT_STRING(length) { - return this.retrieveTextString(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TONE] = function COMPREHENSIONTLV_TAG_TONE(length) { - return this.retrieveTone(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ITEM] = function COMPREHENSIONTLV_TAG_ITEM(length) { - return this.retrieveItem(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ITEM_ID] = function COMPREHENSIONTLV_TAG_ITEM_ID(length) { - return this.retrieveItemId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_RESPONSE_LENGTH] = function COMPREHENSIONTLV_TAG_RESPONSE_LENGTH(length) { - return this.retrieveResponseLength(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_FILE_LIST] = function COMPREHENSIONTLV_TAG_FILE_LIST(length) { - return this.retrieveFileList(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_DEFAULT_TEXT] = function COMPREHENSIONTLV_TAG_DEFAULT_TEXT(length) { - return this.retrieveDefaultText(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_EVENT_LIST] = function COMPREHENSIONTLV_TAG_EVENT_LIST(length) { - return this.retrieveEventList(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ICON_ID] = function COMPREHENSIONTLV_TAG_ICON_ID(length) { - return this.retrieveIconId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_ICON_ID_LIST] = function COMPREHENSIONTLV_TAG_ICON_ID_LIST(length) { - return this.retrieveIconIdList(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER] = function COMPREHENSIONTLV_TAG_TIMER_IDENTIFIER(length) { - return this.retrieveTimerId(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_TIMER_VALUE] = function COMPREHENSIONTLV_TAG_TIMER_VALUE(length) { - return this.retrieveTimerValue(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE] = function COMPREHENSIONTLV_TAG_IMMEDIATE_RESPONSE(length) { - return this.retrieveImmediaResponse(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_URL] = function COMPREHENSIONTLV_TAG_URL(length) { - return this.retrieveUrl(length); -}; -StkProactiveCmdHelperObject.prototype[COMPREHENSIONTLV_TAG_NEXT_ACTION_IND] = function COMPREHENSIONTLV_TAG_NEXT_ACTION_IND(length) { - return this.retrieveNextActionList(length); -}; - -function ComprehensionTlvHelperObject(aContext) { - this.context = aContext; -} -ComprehensionTlvHelperObject.prototype = { - context: null, - - /** - * Decode raw data to a Comprehension-TLV. - */ - decode: function() { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let hlen = 0; // For header(tag field + length field) length. - let temp = GsmPDUHelper.readHexOctet(); - hlen++; - - // TS 101.220, clause 7.1.1 - let tag, cr; - switch (temp) { - // TS 101.220, clause 7.1.1 - case 0x0: // Not used. - case 0xff: // Not used. - case 0x80: // Reserved for future use. - throw new Error("Invalid octet when parsing Comprehension TLV :" + temp); - case 0x7f: // Tag is three byte format. - // TS 101.220 clause 7.1.1.2. - // | Byte 1 | Byte 2 | Byte 3 | - // | | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | | - // | 0x7f |CR | Tag Value | - tag = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - hlen += 2; - cr = (tag & 0x8000) !== 0; - tag &= ~0x8000; - break; - default: // Tag is single byte format. - tag = temp; - // TS 101.220 clause 7.1.1.1. - // | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | - // |CR | Tag Value | - cr = (tag & 0x80) !== 0; - tag &= ~0x80; - } - - // TS 101.220 clause 7.1.2, Length Encoding. - // Length | Byte 1 | Byte 2 | Byte 3 | Byte 4 | - // 0 - 127 | 00 - 7f | N/A | N/A | N/A | - // 128-255 | 81 | 80 - ff| N/A | N/A | - // 256-65535| 82 | 0100 - ffff | N/A | - // 65536- | 83 | 010000 - ffffff | - // 16777215 - // - // Length errors: TS 11.14, clause 6.10.6 - - let length; // Data length. - temp = GsmPDUHelper.readHexOctet(); - hlen++; - if (temp < 0x80) { - length = temp; - } else if (temp == 0x81) { - length = GsmPDUHelper.readHexOctet(); - hlen++; - if (length < 0x80) { - throw new Error("Invalid length in Comprehension TLV :" + length); - } - } else if (temp == 0x82) { - length = (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - hlen += 2; - if (lenth < 0x0100) { - throw new Error("Invalid length in 3-byte Comprehension TLV :" + length); - } - } else if (temp == 0x83) { - length = (GsmPDUHelper.readHexOctet() << 16) | - (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - hlen += 3; - if (length < 0x010000) { - throw new Error("Invalid length in 4-byte Comprehension TLV :" + length); - } - } else { - throw new Error("Invalid octet in Comprehension TLV :" + temp); - } - - let ctlv = { - tag: tag, - length: length, - value: this.context.StkProactiveCmdHelper.retrieve(tag, length), - cr: cr, - hlen: hlen - }; - return ctlv; - }, - - decodeChunks: function(length) { - let chunks = []; - let index = 0; - while (index < length) { - let tlv = this.decode(); - chunks.push(tlv); - index += tlv.length; - index += tlv.hlen; - } - return chunks; - }, - - /** - * Write Location Info Comprehension TLV. - * - * @param loc location Information. - */ - writeLocationInfoTlv: function(loc) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(loc.gsmCellId > 0xffff ? 9 : 7); - // From TS 11.14, clause 12.19 - // "The mobile country code (MCC), the mobile network code (MNC), - // the location area code (LAC) and the cell ID are - // coded as in TS 04.08." - // And from TS 04.08 and TS 24.008, - // the format is as follows: - // - // MCC = MCC_digit_1 + MCC_digit_2 + MCC_digit_3 - // - // 8 7 6 5 4 3 2 1 - // +-------------+-------------+ - // | MCC digit 2 | MCC digit 1 | octet 2 - // | MNC digit 3 | MCC digit 3 | octet 3 - // | MNC digit 2 | MNC digit 1 | octet 4 - // +-------------+-------------+ - // - // Also in TS 24.008 - // "However a network operator may decide to - // use only two digits in the MNC in the LAI over the - // radio interface. In this case, bits 5 to 8 of octet 3 - // shall be coded as '1111'". - - // MCC & MNC, 3 octets - let mcc = loc.mcc, mnc; - if (loc.mnc.length == 2) { - mnc = "F" + loc.mnc; - } else { - mnc = loc.mnc[2] + loc.mnc[0] + loc.mnc[1]; - } - GsmPDUHelper.writeSwappedNibbleBCD(mcc + mnc); - - // LAC, 2 octets - GsmPDUHelper.writeHexOctet((loc.gsmLocationAreaCode >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(loc.gsmLocationAreaCode & 0xff); - - // Cell Id - if (loc.gsmCellId > 0xffff) { - // UMTS/WCDMA, gsmCellId is 28 bits. - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 24) & 0xff); - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 16) & 0xff); - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff); - } else { - // GSM, gsmCellId is 16 bits. - GsmPDUHelper.writeHexOctet((loc.gsmCellId >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(loc.gsmCellId & 0xff); - } - }, - - /** - * Given a geckoError string, this function translates it into cause value - * and write the value into buffer. - * - * @param geckoError Error string that is passed to gecko. - */ - writeCauseTlv: function(geckoError) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let cause = -1; - for (let errorNo in RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR) { - if (geckoError == RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[errorNo]) { - cause = errorNo; - break; - } - } - - // Causes specified in 10.5.4.11 of TS 04.08 are less than 128. - // we can ignore causes > 127 since Cause TLV is optional in - // STK_EVENT_TYPE_CALL_DISCONNECTED. - if (cause > 127) { - return; - } - - cause = (cause == -1) ? ERROR_SUCCESS : cause; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_CAUSE | - COMPREHENSIONTLV_FLAG_CR); - GsmPDUHelper.writeHexOctet(2); // For single cause value. - - // TS 04.08, clause 10.5.4.11: - // Code Standard : Standard defined for GSM PLMNS - // Location: User - GsmPDUHelper.writeHexOctet(0x60); - - // TS 04.08, clause 10.5.4.11: ext bit = 1 + 7 bits for cause. - // +-----------------+----------------------------------+ - // | Ext = 1 (1 bit) | Cause (7 bits) | - // +-----------------+----------------------------------+ - GsmPDUHelper.writeHexOctet(0x80 | cause); - }, - - writeDateTimeZoneTlv: function(date) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_DATE_TIME_ZONE); - GsmPDUHelper.writeHexOctet(7); - GsmPDUHelper.writeTimestamp(date); - }, - - writeLanguageTlv: function(language) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_LANGUAGE); - GsmPDUHelper.writeHexOctet(2); - - // ISO 639-1, Alpha-2 code - // TS 123.038, clause 6.2.1, GSM 7 bit Default Alphabet - GsmPDUHelper.writeHexOctet( - PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT].indexOf(language[0])); - GsmPDUHelper.writeHexOctet( - PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT].indexOf(language[1])); - }, - - /** - * Write Timer Value Comprehension TLV. - * - * @param seconds length of time during of the timer. - * @param cr Comprehension Required or not - */ - writeTimerValueTlv: function(seconds, cr) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TIMER_VALUE | - (cr ? COMPREHENSIONTLV_FLAG_CR : 0)); - GsmPDUHelper.writeHexOctet(3); - - // TS 102.223, clause 8.38 - // +----------------+------------------+-------------------+ - // | hours (1 byte) | minutes (1 btye) | seconds (1 byte) | - // +----------------+------------------+-------------------+ - GsmPDUHelper.writeSwappedNibbleBCDNum(Math.floor(seconds / 60 / 60)); - GsmPDUHelper.writeSwappedNibbleBCDNum(Math.floor(seconds / 60) % 60); - GsmPDUHelper.writeSwappedNibbleBCDNum(Math.floor(seconds) % 60); - }, - - writeTextStringTlv: function(text, coding) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let buf = GsmPDUHelper.writeWithBuffer(() => { - // Write Coding. - GsmPDUHelper.writeHexOctet(coding); - - // Write Text String. - switch (coding) { - case STK_TEXT_CODING_UCS2: - GsmPDUHelper.writeUCS2String(text); - break; - case STK_TEXT_CODING_GSM_7BIT_PACKED: - GsmPDUHelper.writeStringAsSeptets(text, 0, 0, 0); - break; - case STK_TEXT_CODING_GSM_8BIT: - GsmPDUHelper.writeStringAs8BitUnpacked(text); - break; - } - }); - - let length = buf.length; - if (length) { - // Write Tag. - GsmPDUHelper.writeHexOctet(COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - // Write Length. - this.writeLength(length); - // Write Value. - for (let i = 0; i < length; i++) { - GsmPDUHelper.writeHexOctet(buf[i]); - } - } - }, - - getSizeOfLengthOctets: function(length) { - if (length >= 0x10000) { - return 4; // 0x83, len_1, len_2, len_3 - } else if (length >= 0x100) { - return 3; // 0x82, len_1, len_2 - } else if (length >= 0x80) { - return 2; // 0x81, len - } else { - return 1; // len - } - }, - - writeLength: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - // TS 101.220 clause 7.1.2, Length Encoding. - // Length | Byte 1 | Byte 2 | Byte 3 | Byte 4 | - // 0 - 127 | 00 - 7f | N/A | N/A | N/A | - // 128-255 | 81 | 80 - ff| N/A | N/A | - // 256-65535| 82 | 0100 - ffff | N/A | - // 65536- | 83 | 010000 - ffffff | - // 16777215 - if (length < 0x80) { - GsmPDUHelper.writeHexOctet(length); - } else if (0x80 <= length && length < 0x100) { - GsmPDUHelper.writeHexOctet(0x81); - GsmPDUHelper.writeHexOctet(length); - } else if (0x100 <= length && length < 0x10000) { - GsmPDUHelper.writeHexOctet(0x82); - GsmPDUHelper.writeHexOctet((length >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(length & 0xff); - } else if (0x10000 <= length && length < 0x1000000) { - GsmPDUHelper.writeHexOctet(0x83); - GsmPDUHelper.writeHexOctet((length >> 16) & 0xff); - GsmPDUHelper.writeHexOctet((length >> 8) & 0xff); - GsmPDUHelper.writeHexOctet(length & 0xff); - } else { - throw new Error("Invalid length value :" + length); - } - }, -}; - -function BerTlvHelperObject(aContext) { - this.context = aContext; -} -BerTlvHelperObject.prototype = { - context: null, - - /** - * Decode Ber TLV. - * - * @param dataLen - * The length of data in bytes. - */ - decode: function(dataLen) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let hlen = 0; - let tag = GsmPDUHelper.readHexOctet(); - hlen++; - - // The length is coded onto 1 or 2 bytes. - // Length | Byte 1 | Byte 2 - // 0 - 127 | length ('00' to '7f') | N/A - // 128 - 255 | '81' | length ('80' to 'ff') - let length; - let temp = GsmPDUHelper.readHexOctet(); - hlen++; - if (temp < 0x80) { - length = temp; - } else if (temp === 0x81) { - length = GsmPDUHelper.readHexOctet(); - hlen++; - if (length < 0x80) { - throw new Error("Invalid length " + length); - } - } else { - throw new Error("Invalid length octet " + temp); - } - - // Header + body length check. - if (dataLen - hlen !== length) { - throw new Error("Unexpected BerTlvHelper value length!!"); - } - - let method = this[tag]; - if (typeof method != "function") { - throw new Error("Unknown Ber tag 0x" + tag.toString(16)); - } - - let value = method.call(this, length); - - return { - tag: tag, - length: length, - value: value - }; - }, - - /** - * Process the value part for FCP template TLV. - * - * @param length - * The length of data in bytes. - */ - processFcpTemplate: function(length) { - let tlvs = this.decodeChunks(length); - return tlvs; - }, - - /** - * Process the value part for proactive command TLV. - * - * @param length - * The length of data in bytes. - */ - processProactiveCommand: function(length) { - let ctlvs = this.context.ComprehensionTlvHelper.decodeChunks(length); - return ctlvs; - }, - - /** - * Decode raw data to a Ber-TLV. - */ - decodeInnerTlv: function() { - let GsmPDUHelper = this.context.GsmPDUHelper; - let tag = GsmPDUHelper.readHexOctet(); - let length = GsmPDUHelper.readHexOctet(); - return { - tag: tag, - length: length, - value: this.retrieve(tag, length) - }; - }, - - decodeChunks: function(length) { - let chunks = []; - let index = 0; - while (index < length) { - let tlv = this.decodeInnerTlv(); - if (tlv.value) { - chunks.push(tlv); - } - index += tlv.length; - // tag + length fields consume 2 bytes. - index += 2; - } - return chunks; - }, - - retrieve: function(tag, length) { - let method = this[tag]; - if (typeof method != "function") { - if (DEBUG) { - this.context.debug("Unknown Ber tag : 0x" + tag.toString(16)); - } - let Buf = this.context.Buf; - Buf.seekIncoming(length * Buf.PDU_HEX_OCTET_SIZE); - return null; - } - return method.call(this, length); - }, - - /** - * File Size Data. - * - * | Byte | Description | Length | - * | 1 | Tag | 1 | - * | 2 | Length | 1 | - * | 3 to X+24 | Number of allocated data bytes in the file | X | - * | | , excluding structural information | | - */ - retrieveFileSizeData: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let fileSizeData = 0; - for (let i = 0; i < length; i++) { - fileSizeData = fileSizeData << 8; - fileSizeData += GsmPDUHelper.readHexOctet(); - } - - return {fileSizeData: fileSizeData}; - }, - - /** - * File Descriptor. - * - * | Byte | Description | Length | - * | 1 | Tag | 1 | - * | 2 | Length | 1 | - * | 3 | File descriptor byte | 1 | - * | 4 | Data coding byte | 1 | - * | 5 ~ 6 | Record length | 2 | - * | 7 | Number of records | 1 | - */ - retrieveFileDescriptor: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - let fileDescriptorByte = GsmPDUHelper.readHexOctet(); - let dataCodingByte = GsmPDUHelper.readHexOctet(); - // See TS 102 221 Table 11.5, we only care the least 3 bits for the - // structure of file. - let fileStructure = fileDescriptorByte & 0x07; - - let fileDescriptor = { - fileStructure: fileStructure - }; - // byte 5 ~ 7 are mandatory for linear fixed and cyclic files, otherwise - // they are not applicable. - if (fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED] || - fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_CYCLIC]) { - fileDescriptor.recordLength = (GsmPDUHelper.readHexOctet() << 8) + - GsmPDUHelper.readHexOctet(); - fileDescriptor.numOfRecords = GsmPDUHelper.readHexOctet(); - } - - return fileDescriptor; - }, - - /** - * File identifier. - * - * | Byte | Description | Length | - * | 1 | Tag | 1 | - * | 2 | Length | 1 | - * | 3 ~ 4 | File identifier | 2 | - */ - retrieveFileIdentifier: function(length) { - let GsmPDUHelper = this.context.GsmPDUHelper; - return {fileId : (GsmPDUHelper.readHexOctet() << 8) + - GsmPDUHelper.readHexOctet()}; - }, - - searchForNextTag: function(tag, iter) { - for (let tlv of iter) { - if (tlv.tag === tag) { - return tlv; - } - } - return null; - } -}; -BerTlvHelperObject.prototype[BER_FCP_TEMPLATE_TAG] = function BER_FCP_TEMPLATE_TAG(length) { - return this.processFcpTemplate(length); -}; -BerTlvHelperObject.prototype[BER_PROACTIVE_COMMAND_TAG] = function BER_PROACTIVE_COMMAND_TAG(length) { - return this.processProactiveCommand(length); -}; -BerTlvHelperObject.prototype[BER_FCP_FILE_SIZE_DATA_TAG] = function BER_FCP_FILE_SIZE_DATA_TAG(length) { - return this.retrieveFileSizeData(length); -}; -BerTlvHelperObject.prototype[BER_FCP_FILE_DESCRIPTOR_TAG] = function BER_FCP_FILE_DESCRIPTOR_TAG(length) { - return this.retrieveFileDescriptor(length); -}; -BerTlvHelperObject.prototype[BER_FCP_FILE_IDENTIFIER_TAG] = function BER_FCP_FILE_IDENTIFIER_TAG(length) { - return this.retrieveFileIdentifier(length); -}; - -/** - * ICC Helper for getting EF path. - */ -function ICCFileHelperObject(aContext) { - this.context = aContext; -} -ICCFileHelperObject.prototype = { - context: null, - - /** - * This function handles only EFs that are common to RUIM, SIM, USIM - * and other types of ICC cards. - */ - getCommonEFPath: function(fileId) { - switch (fileId) { - case ICC_EF_ICCID: - return EF_PATH_MF_SIM; - case ICC_EF_ADN: - case ICC_EF_SDN: // Fall through. - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM; - case ICC_EF_PBR: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK; - case ICC_EF_IMG: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_GRAPHICS; - } - return null; - }, - - /** - * This function handles EFs for SIM. - */ - getSimEFPath: function(fileId) { - switch (fileId) { - case ICC_EF_FDN: - case ICC_EF_MSISDN: - case ICC_EF_SMS: - case ICC_EF_EXT1: - case ICC_EF_EXT2: - case ICC_EF_EXT3: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM; - case ICC_EF_AD: - case ICC_EF_MBDN: - case ICC_EF_MWIS: - case ICC_EF_PLMNsel: - case ICC_EF_SPN: - case ICC_EF_SPDI: - case ICC_EF_SST: - case ICC_EF_PHASE: - case ICC_EF_CBMI: - case ICC_EF_CBMID: - case ICC_EF_CBMIR: - case ICC_EF_OPL: - case ICC_EF_PNN: - case ICC_EF_GID1: - case ICC_EF_CPHS_INFO: - case ICC_EF_CPHS_MBN: - return EF_PATH_MF_SIM + EF_PATH_DF_GSM; - default: - return null; - } - }, - - /** - * This function handles EFs for USIM. - */ - getUSimEFPath: function(fileId) { - switch (fileId) { - case ICC_EF_AD: - case ICC_EF_FDN: - case ICC_EF_MBDN: - case ICC_EF_MWIS: - case ICC_EF_UST: - case ICC_EF_MSISDN: - case ICC_EF_SPN: - case ICC_EF_SPDI: - case ICC_EF_CBMI: - case ICC_EF_CBMID: - case ICC_EF_CBMIR: - case ICC_EF_OPL: - case ICC_EF_PNN: - case ICC_EF_SMS: - case ICC_EF_GID1: - // CPHS spec was provided in 1997 based on SIM requirement, there is no - // detailed info about how these ICC_EF_CPHS_XXX are allocated in USIM. - // What we can do now is to follow what has been done in AOSP to have file - // path equal to MF_SIM/DF_GSM. - case ICC_EF_CPHS_INFO: - case ICC_EF_CPHS_MBN: - return EF_PATH_MF_SIM + EF_PATH_ADF_USIM; - default: - // The file ids in USIM phone book entries are decided by the - // card manufacturer. So if we don't match any of the cases - // above and if its a USIM return the phone book path. - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK; - } - }, - - /** - * This function handles EFs for RUIM - */ - getRuimEFPath: function(fileId) { - switch(fileId) { - case ICC_EF_CSIM_IMSI_M: - case ICC_EF_CSIM_CDMAHOME: - case ICC_EF_CSIM_CST: - case ICC_EF_CSIM_SPN: - return EF_PATH_MF_SIM + EF_PATH_DF_CDMA; - case ICC_EF_FDN: - case ICC_EF_EXT1: - case ICC_EF_EXT2: - case ICC_EF_EXT3: - return EF_PATH_MF_SIM + EF_PATH_DF_TELECOM; - default: - return null; - } - }, - - /** - * Helper function for getting the pathId for the specific ICC record - * depeding on which type of ICC card we are using. - * - * @param fileId - * File id. - * @return The pathId or null in case of an error or invalid input. - */ - getEFPath: function(fileId) { - let path = this.getCommonEFPath(fileId); - if (path) { - return path; - } - - switch (this.context.RIL.appType) { - case CARD_APPTYPE_SIM: - return this.getSimEFPath(fileId); - case CARD_APPTYPE_USIM: - return this.getUSimEFPath(fileId); - case CARD_APPTYPE_RUIM: - return this.getRuimEFPath(fileId); - default: - return null; - } - } -}; - -/** - * Helper for ICC IO functionalities. - */ -function ICCIOHelperObject(aContext) { - this.context = aContext; -} -ICCIOHelperObject.prototype = { - context: null, - - /** - * Load EF with type 'Linear Fixed'. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param recordNumber [optional] - * The number of the record shall be loaded. - * @param recordSize [optional] - * The size of the record. - * @param callback [optional] - * The callback function shall be called when the record(s) is read. - * @param onerror [optional] - * The callback function shall be called when failure. - */ - loadLinearFixedEF: function(options) { - let cb; - let readRecord = (function(options) { - options.command = ICC_COMMAND_READ_RECORD; - options.p1 = options.recordNumber || 1; // Record number - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = options.recordSize; - options.callback = cb || options.callback; - this.context.RIL.iccIO(options); - }).bind(this); - - options.structure = EF_STRUCTURE_LINEAR_FIXED; - options.pathId = this.context.ICCFileHelper.getEFPath(options.fileId); - if (options.recordSize) { - readRecord(options); - return; - } - - cb = options.callback; - options.callback = readRecord; - this.getResponse(options); - }, - - /** - * Load next record from current record Id. - */ - loadNextRecord: function(options) { - options.p1++; - this.context.RIL.iccIO(options); - }, - - /** - * Update EF with type 'Linear Fixed'. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param recordNumber - * The number of the record shall be updated. - * @param dataWriter [optional] - * The function for writing string parameter for the ICC_COMMAND_UPDATE_RECORD. - * @param pin2 [optional] - * PIN2 is required when updating ICC_EF_FDN. - * @param callback [optional] - * The callback function shall be called when the record is updated. - * @param onerror [optional] - * The callback function shall be called when failure. - */ - updateLinearFixedEF: function(options) { - if (!options.fileId || !options.recordNumber) { - throw new Error("Unexpected fileId " + options.fileId + - " or recordNumber " + options.recordNumber); - } - - options.structure = EF_STRUCTURE_LINEAR_FIXED; - options.pathId = this.context.ICCFileHelper.getEFPath(options.fileId); - let cb = options.callback; - options.callback = function callback(options) { - options.callback = cb; - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = options.recordSize; - this.context.RIL.iccIO(options); - }.bind(this); - this.getResponse(options); - }, - - /** - * Load EF with type 'Transparent'. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - * @param callback [optional] - * The callback function shall be called when the record(s) is read. - * @param onerror [optional] - * The callback function shall be called when failure. - */ - loadTransparentEF: function(options) { - options.structure = EF_STRUCTURE_TRANSPARENT; - let cb = options.callback; - options.callback = function callback(options) { - options.callback = cb; - options.command = ICC_COMMAND_READ_BINARY; - options.p2 = 0x00; - options.p3 = options.fileSize; - this.context.RIL.iccIO(options); - }.bind(this); - this.getResponse(options); - }, - - /** - * Use ICC_COMMAND_GET_RESPONSE to query the EF. - * - * @param fileId - * The file to operate on, one of the ICC_EF_* constants. - */ - getResponse: function(options) { - options.command = ICC_COMMAND_GET_RESPONSE; - options.pathId = options.pathId || - this.context.ICCFileHelper.getEFPath(options.fileId); - if (!options.pathId) { - throw new Error("Unknown pathId for " + options.fileId.toString(16)); - } - options.p1 = 0; // For GET_RESPONSE, p1 = 0 - switch (this.context.RIL.appType) { - case CARD_APPTYPE_USIM: - options.p2 = GET_RESPONSE_FCP_TEMPLATE; - options.p3 = 0x00; - break; - // For RUIM, CSIM and ISIM, cf bug 955946: keep the old behavior - case CARD_APPTYPE_RUIM: - case CARD_APPTYPE_CSIM: - case CARD_APPTYPE_ISIM: - // For SIM, this is what we want - case CARD_APPTYPE_SIM: - default: - options.p2 = 0x00; - options.p3 = GET_RESPONSE_EF_SIZE_BYTES; - break; - } - this.context.RIL.iccIO(options); - }, - - /** - * Process ICC I/O response. - */ - processICCIO: function(options) { - let func = this[options.command]; - func.call(this, options); - }, - - /** - * Process a ICC_COMMAND_GET_RESPONSE type command for REQUEST_SIM_IO. - */ - processICCIOGetResponse: function(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - - let peek = this.context.GsmPDUHelper.readHexOctet(); - Buf.seekIncoming(-1 * Buf.PDU_HEX_OCTET_SIZE); - if (peek === BER_FCP_TEMPLATE_TAG) { - this.processUSimGetResponse(options, strLen / 2); - } else { - this.processSimGetResponse(options); - } - Buf.readStringDelimiter(strLen); - - if (options.callback) { - options.callback(options); - } - }, - - /** - * Helper function for processing USIM get response. - */ - processUSimGetResponse: function(options, octetLen) { - let BerTlvHelper = this.context.BerTlvHelper; - - let berTlv = BerTlvHelper.decode(octetLen); - // See TS 102 221 Table 11.4 for the content order of getResponse. - let iter = berTlv.value.values(); - let tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, - iter); - if (!tlv || - (tlv.value.fileStructure !== UICC_EF_STRUCTURE[options.structure])) { - throw new Error("Expected EF structure " + - UICC_EF_STRUCTURE[options.structure] + - " but read " + tlv.value.fileStructure); - } - - if (tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED] || - tlv.value.fileStructure === UICC_EF_STRUCTURE[EF_STRUCTURE_CYCLIC]) { - options.recordSize = tlv.value.recordLength; - options.totalRecords = tlv.value.numOfRecords; - } - - tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); - if (!tlv || (tlv.value.fileId !== options.fileId)) { - throw new Error("Expected file ID " + options.fileId.toString(16) + - " but read " + fileId.toString(16)); - } - - tlv = BerTlvHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); - if (!tlv) { - throw new Error("Unexpected file size data"); - } - options.fileSize = tlv.value.fileSizeData; - }, - - /** - * Helper function for processing SIM get response. - */ - processSimGetResponse: function(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // The format is from TS 51.011, clause 9.2.1 - - // Skip RFU, data[0] data[1]. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - - // File size, data[2], data[3] - options.fileSize = (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - - // 2 bytes File id. data[4], data[5] - let fileId = (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - if (fileId != options.fileId) { - throw new Error("Expected file ID " + options.fileId.toString(16) + - " but read " + fileId.toString(16)); - } - - // Type of file, data[6] - let fileType = GsmPDUHelper.readHexOctet(); - if (fileType != TYPE_EF) { - throw new Error("Unexpected file type " + fileType); - } - - // Skip 1 byte RFU, data[7], - // 3 bytes Access conditions, data[8] data[9] data[10], - // 1 byte File status, data[11], - // 1 byte Length of the following data, data[12]. - Buf.seekIncoming(((RESPONSE_DATA_STRUCTURE - RESPONSE_DATA_FILE_TYPE - 1) * - Buf.PDU_HEX_OCTET_SIZE)); - - // Read Structure of EF, data[13] - let efStructure = GsmPDUHelper.readHexOctet(); - if (efStructure != options.structure) { - throw new Error("Expected EF structure " + options.structure + - " but read " + efStructure); - } - - // Length of a record, data[14]. - // Only available for LINEAR_FIXED and CYCLIC. - if (efStructure == EF_STRUCTURE_LINEAR_FIXED || - efStructure == EF_STRUCTURE_CYCLIC) { - options.recordSize = GsmPDUHelper.readHexOctet(); - options.totalRecords = options.fileSize / options.recordSize; - } else { - Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE); - } - }, - - /** - * Process a ICC_COMMAND_READ_RECORD type command for REQUEST_SIM_IO. - */ - processICCIOReadRecord: function(options) { - if (options.callback) { - options.callback(options); - } - }, - - /** - * Process a ICC_COMMAND_READ_BINARY type command for REQUEST_SIM_IO. - */ - processICCIOReadBinary: function(options) { - if (options.callback) { - options.callback(options); - } - }, - - /** - * Process a ICC_COMMAND_UPDATE_RECORD type command for REQUEST_SIM_IO. - */ - processICCIOUpdateRecord: function(options) { - if (options.callback) { - options.callback(options); - } - }, -}; -ICCIOHelperObject.prototype[ICC_COMMAND_SEEK] = null; -ICCIOHelperObject.prototype[ICC_COMMAND_READ_BINARY] = function ICC_COMMAND_READ_BINARY(options) { - this.processICCIOReadBinary(options); -}; -ICCIOHelperObject.prototype[ICC_COMMAND_READ_RECORD] = function ICC_COMMAND_READ_RECORD(options) { - this.processICCIOReadRecord(options); -}; -ICCIOHelperObject.prototype[ICC_COMMAND_GET_RESPONSE] = function ICC_COMMAND_GET_RESPONSE(options) { - this.processICCIOGetResponse(options); -}; -ICCIOHelperObject.prototype[ICC_COMMAND_UPDATE_BINARY] = null; -ICCIOHelperObject.prototype[ICC_COMMAND_UPDATE_RECORD] = function ICC_COMMAND_UPDATE_RECORD(options) { - this.processICCIOUpdateRecord(options); -}; - -/** - * Helper for ICC records. - */ -function ICCRecordHelperObject(aContext) { - this.context = aContext; - // Cache the possible free record id for all files, use fileId as key. - this._freeRecordIds = {}; -} -ICCRecordHelperObject.prototype = { - context: null, - - /** - * Fetch ICC records. - */ - fetchICCRecords: function() { - switch (this.context.RIL.appType) { - case CARD_APPTYPE_SIM: - case CARD_APPTYPE_USIM: - this.context.SimRecordHelper.fetchSimRecords(); - break; - case CARD_APPTYPE_RUIM: - this.context.RuimRecordHelper.fetchRuimRecords(); - break; - } - }, - - /** - * Read the ICCID. - */ - readICCID: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - RIL.iccInfo.iccid = - GsmPDUHelper.readSwappedNibbleBcdString(octetLen, true); - // Consumes the remaining buffer if any. - let unReadBuffer = this.context.Buf.getReadAvailable() - - this.context.Buf.PDU_HEX_OCTET_SIZE; - if (unReadBuffer > 0) { - this.context.Buf.seekIncoming(unReadBuffer); - } - Buf.readStringDelimiter(strLen); - - if (DEBUG) this.context.debug("ICCID: " + RIL.iccInfo.iccid); - if (RIL.iccInfo.iccid) { - this.context.ICCUtilsHelper.handleICCInfoChange(); - RIL.reportStkServiceIsRunning(); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_ICCID, - callback: callback.bind(this) - }); - }, - - /** - * Read ICC ADN like EF, i.e. EF_ADN, EF_FDN. - * - * @param fileId EF id of the ADN, FDN or SDN. - * @param extFileId EF id of the EXT. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readADNLike: function(fileId, extFileId, onsuccess, onerror) { - let ICCIOHelper = this.context.ICCIOHelper; - - function callback(options) { - let loadNextContactRecord = () => { - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - return; - } - if (DEBUG) { - for (let i = 0; i < contacts.length; i++) { - this.context.debug("contact [" + i + "] " + - JSON.stringify(contacts[i])); - } - } - if (onsuccess) { - onsuccess(contacts); - } - }; - - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if (contact) { - let record = { - recordId: options.p1, - alphaId: contact.alphaId, - number: contact.number - }; - contacts.push(record); - - if (extFileId && contact.extRecordNumber != 0xff) { - this.readExtension(extFileId, contact.extRecordNumber, (number) => { - if (number) { - record.number += number; - } - loadNextContactRecord(); - }, () => loadNextContactRecord()); - return; - } - } - loadNextContactRecord(); - } - - let contacts = []; - ICCIOHelper.loadLinearFixedEF({fileId: fileId, - callback: callback.bind(this), - onerror: onerror}); - }, - - /** - * Update ICC ADN like EFs, like EF_ADN, EF_FDN. - * - * @param fileId EF id of the ADN or FDN. - * @param extRecordNumber The record identifier of the EXT. - * @param contact The contact will be updated. (Shall have recordId property) - * @param pin2 PIN2 is required when updating ICC_EF_FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateADNLike: function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - let updatedContact; - function dataWriter(recordSize) { - updatedContact = this.context.ICCPDUHelper.writeAlphaIdDiallingNumber(recordSize, - contact.alphaId, - contact.number, - extRecordNumber); - } - - function callback(options) { - if (onsuccess) { - onsuccess(updatedContact); - } - } - - if (!contact || !contact.recordId) { - if (onerror) onerror(GECKO_ERROR_INVALID_PARAMETER); - return; - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: contact.recordId, - dataWriter: dataWriter.bind(this), - pin2: pin2, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Read USIM/RUIM Phonebook. - * - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readPBR: function(onsuccess, onerror) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - let ICCIOHelper = this.context.ICCIOHelper; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let RIL = this.context.RIL; - - function callback(options) { - let strLen = Buf.readInt32(); - let octetLen = strLen / 2, readLen = 0; - - let pbrTlvs = []; - while (readLen < octetLen) { - let tag = GsmPDUHelper.readHexOctet(); - if (tag == 0xff) { - readLen++; - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - - let tlvLen = GsmPDUHelper.readHexOctet(); - let tlvs = ICCUtilsHelper.decodeSimTlvs(tlvLen); - pbrTlvs.push({tag: tag, - length: tlvLen, - value: tlvs}); - - readLen += tlvLen + 2; // +2 for tag and tlvLen - } - Buf.readStringDelimiter(strLen); - - if (pbrTlvs.length > 0) { - let pbr = ICCUtilsHelper.parsePbrTlvs(pbrTlvs); - // EF_ADN is mandatory if and only if DF_PHONEBOOK is present. - if (!pbr.adn) { - if (onerror) onerror("Cannot access ADN."); - return; - } - pbrs.push(pbr); - } - - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - if (onsuccess) { - RIL.iccInfoPrivate.pbrs = pbrs; - onsuccess(pbrs); - } - } - } - - if (RIL.iccInfoPrivate.pbrs) { - onsuccess(RIL.iccInfoPrivate.pbrs); - return; - } - - let pbrs = []; - ICCIOHelper.loadLinearFixedEF({fileId : ICC_EF_PBR, - callback: callback.bind(this), - onerror: onerror}); - }, - - /** - * Cache EF_IAP record size. - */ - _iapRecordSize: null, - - /** - * Read ICC EF_IAP. (Index Administration Phonebook) - * - * @see TS 131.102, clause 4.4.2.2 - * - * @param fileId EF id of the IAP. - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readIAP: function(fileId, recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - this._iapRecordSize = options.recordSize; - - let iap = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(iap); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - recordSize: this._iapRecordSize, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Update USIM/RUIM Phonebook EF_IAP. - * - * @see TS 131.102, clause 4.4.2.13 - * - * @param fileId EF id of the IAP. - * @param recordNumber The identifier of the record shall be updated. - * @param iap The IAP value to be written. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateIAP: function(fileId, recordNumber, iap, onsuccess, onerror) { - let dataWriter = function dataWriter(recordSize) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - for (let i = 0; i < iap.length; i++) { - GsmPDUHelper.writeHexOctet(iap[i]); - } - - Buf.writeStringDelimiter(strLen); - }.bind(this); - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: onsuccess, - onerror: onerror - }); - }, - - /** - * Cache EF_Email record size. - */ - _emailRecordSize: null, - - /** - * Read USIM/RUIM Phonebook EF_EMAIL. - * - * @see TS 131.102, clause 4.4.2.13 - * - * @param fileId EF id of the EMAIL. - * @param fileType The type of the EMAIL, one of the ICC_USIM_TYPE* constants. - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readEmail: function(fileId, fileType, recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let ICCPDUHelper = this.context.ICCPDUHelper; - - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let email = null; - this._emailRecordSize = options.recordSize; - - // Read contact's email - // - // | Byte | Description | Length | M/O - // | 1 ~ X | E-mail Address | X | M - // | X+1 | ADN file SFI | 1 | C - // | X+2 | ADN file Record Identifier | 1 | C - // Note: The fields marked as C above are mandatort if the file - // is not type 1 (as specified in EF_PBR) - if (fileType == ICC_USIM_TYPE1_TAG) { - email = ICCPDUHelper.read8BitUnpackedToString(octetLen); - } else { - email = ICCPDUHelper.read8BitUnpackedToString(octetLen - 2); - - // Consumes the remaining buffer - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); // For ADN SFI and Record Identifier - } - - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(email); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - recordSize: this._emailRecordSize, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Update USIM/RUIM Phonebook EF_EMAIL. - * - * @see TS 131.102, clause 4.4.2.13 - * - * @param pbr Phonebook Reference File. - * @param recordNumber The identifier of the record shall be updated. - * @param email The value to be written. - * @param adnRecordId The record Id of ADN, only needed if the fileType of Email is TYPE2. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateEmail: function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { - let fileId = pbr[USIM_PBR_EMAIL].fileId; - let fileType = pbr[USIM_PBR_EMAIL].fileType; - let writtenEmail; - let dataWriter = function dataWriter(recordSize) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - let ICCPDUHelper = this.context.ICCPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - if (fileType == ICC_USIM_TYPE1_TAG) { - writtenEmail = ICCPDUHelper.writeStringTo8BitUnpacked(recordSize, email); - } else { - writtenEmail = ICCPDUHelper.writeStringTo8BitUnpacked(recordSize - 2, email); - GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff); - GsmPDUHelper.writeHexOctet(adnRecordId); - } - - Buf.writeStringDelimiter(strLen); - }.bind(this); - - let callback = (options) => { - if (onsuccess) { - onsuccess(writtenEmail); - } - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: callback, - onerror: onerror - }); - }, - - /** - * Cache EF_ANR record size. - */ - _anrRecordSize: null, - - /** - * Read USIM/RUIM Phonebook EF_ANR. - * - * @see TS 131.102, clause 4.4.2.9 - * - * @param fileId EF id of the ANR. - * @param fileType One of the ICC_USIM_TYPE* constants. - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readANR: function(fileId, fileType, recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let number = null; - this._anrRecordSize = options.recordSize; - - // Skip EF_AAS Record ID. - Buf.seekIncoming(1 * Buf.PDU_HEX_OCTET_SIZE); - - number = this.context.ICCPDUHelper.readNumberWithLength(); - - // Skip 2 unused octets, CCP and EXT1. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - - // For Type 2 there are two extra octets. - if (fileType == ICC_USIM_TYPE2_TAG) { - // Skip 2 unused octets, ADN SFI and Record Identifier. - Buf.seekIncoming(2 * Buf.PDU_HEX_OCTET_SIZE); - } - - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(number); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - recordSize: this._anrRecordSize, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Update USIM/RUIM Phonebook EF_ANR. - * - * @see TS 131.102, clause 4.4.2.9 - * - * @param pbr Phonebook Reference File. - * @param recordNumber The identifier of the record shall be updated. - * @param number The value to be written. - * @param adnRecordId The record Id of ADN, only needed if the fileType of Email is TYPE2. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateANR: function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { - let fileId = pbr[USIM_PBR_ANR0].fileId; - let fileType = pbr[USIM_PBR_ANR0].fileType; - let writtenNumber; - let dataWriter = function dataWriter(recordSize) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - // Write String length - let strLen = recordSize * 2; - Buf.writeInt32(strLen); - - // EF_AAS record Id. Unused for now. - GsmPDUHelper.writeHexOctet(0xff); - - writtenNumber = this.context.ICCPDUHelper.writeNumberWithLength(number); - - // Write unused octets 0xff, CCP and EXT1. - GsmPDUHelper.writeHexOctet(0xff); - GsmPDUHelper.writeHexOctet(0xff); - - // For Type 2 there are two extra octets. - if (fileType == ICC_USIM_TYPE2_TAG) { - GsmPDUHelper.writeHexOctet(pbr.adn.sfi || 0xff); - GsmPDUHelper.writeHexOctet(adnRecordId); - } - - Buf.writeStringDelimiter(strLen); - }.bind(this); - - let callback = (options) => { - if (onsuccess) { - onsuccess(writtenNumber); - } - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: callback, - onerror: onerror - }); - }, - - /** - * Cache the possible free record id for all files. - */ - _freeRecordIds: null, - - /** - * Find free record id. - * - * @param fileId EF id. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - findFreeRecordId: function(fileId, onsuccess, onerror) { - let ICCIOHelper = this.context.ICCIOHelper; - - function callback(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let readLen = 0; - - while (readLen < octetLen) { - let octet = GsmPDUHelper.readHexOctet(); - readLen++; - if (octet != 0xff) { - break; - } - } - - let nextRecord = (options.p1 % options.totalRecords) + 1; - - if (readLen == octetLen) { - // Find free record, assume next record is probably free. - this._freeRecordIds[fileId] = nextRecord; - if (onsuccess) { - onsuccess(options.p1); - } - return; - } else { - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - } - - Buf.readStringDelimiter(strLen); - - if (nextRecord !== recordNumber) { - options.p1 = nextRecord; - this.context.RIL.iccIO(options); - } else { - // No free record found. - delete this._freeRecordIds[fileId]; - if (DEBUG) { - this.context.debug(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } - onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } - } - - // Start searching free records from the possible one. - let recordNumber = this._freeRecordIds[fileId] || 1; - ICCIOHelper.loadLinearFixedEF({fileId: fileId, - recordNumber: recordNumber, - callback: callback.bind(this), - onerror: onerror}); - }, - - /** - * Read Extension Number from TS 151.011 clause 10.5.10, TS 31.102, clause 4.4.2.4 - * - * @param fileId EF Extension id - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readExtension: function(fileId, recordNumber, onsuccess, onerror) { - let callback = (options) => { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - let recordType = this.context.GsmPDUHelper.readHexOctet(); - let number = ""; - - // TS 31.102, clause 4.4.2.4 EFEXT1 - // Case 1, Extension1 record is additional data - if (recordType & 0x02) { - let numLen = this.context.GsmPDUHelper.readHexOctet(); - if (numLen != 0xff) { - if (numLen > EXT_MAX_BCD_NUMBER_BYTES) { - if (DEBUG) { - this.context.debug( - "Error: invalid length of BCD number/SSC contents - " + numLen); - } - // +1 to skip Identifier - Buf.seekIncoming((EXT_MAX_BCD_NUMBER_BYTES + 1) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(length); - onerror(); - return; - } - - number = this.context.GsmPDUHelper.readSwappedNibbleExtendedBcdString(numLen); - if (DEBUG) this.context.debug("Contact Extension Number: "+ number); - Buf.seekIncoming((EXT_MAX_BCD_NUMBER_BYTES - numLen) * Buf.PDU_HEX_OCTET_SIZE); - } else { - Buf.seekIncoming(EXT_MAX_BCD_NUMBER_BYTES * Buf.PDU_HEX_OCTET_SIZE); - } - } else { - // Don't support Case 2, Extension1 record is Called Party Subaddress. - // +1 skip numLen - Buf.seekIncoming((EXT_MAX_BCD_NUMBER_BYTES + 1) * Buf.PDU_HEX_OCTET_SIZE); - } - - // Skip Identifier - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(length); - onsuccess(number); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - callback: callback, - onerror: onerror - }); - }, - - /** - * Update Extension. - * - * @param fileId EF id of the EXT. - * @param recordNumber The number of the record shall be updated. - * @param number Dialling Number to be written. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateExtension: function(fileId, recordNumber, number, onsuccess, onerror) { - let dataWriter = (recordSize) => { - let GsmPDUHelper = this.context.GsmPDUHelper; - // Write String length - let strLen = recordSize * 2; - let Buf = this.context.Buf; - Buf.writeInt32(strLen); - - // We don't support extension chain. - if (number.length > EXT_MAX_NUMBER_DIGITS) { - number = number.substring(0, EXT_MAX_NUMBER_DIGITS); - } - - let numLen = Math.ceil(number.length / 2); - // Write Extension record - GsmPDUHelper.writeHexOctet(0x02); - GsmPDUHelper.writeHexOctet(numLen); - GsmPDUHelper.writeSwappedNibbleBCD(number); - // Write trailing 0xff of Extension data. - for (let i = 0; i < EXT_MAX_BCD_NUMBER_BYTES - numLen; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - // Write trailing 0xff for Identifier. - GsmPDUHelper.writeHexOctet(0xff); - Buf.writeStringDelimiter(strLen); - }; - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: onsuccess, - onerror: onerror - }); - }, - - /** - * Clean an EF record. - * - * @param fileId EF id. - * @param recordNumber The number of the record shall be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - cleanEFRecord: function(fileId, recordNumber, onsuccess, onerror) { - let dataWriter = (recordSize) => { - let GsmPDUHelper = this.context.GsmPDUHelper; - let Buf = this.context.Buf; - // Write String length - let strLen = recordSize * 2; - - Buf.writeInt32(strLen); - // Write record to 0xff - for (let i = 0; i < recordSize; i++) { - GsmPDUHelper.writeHexOctet(0xff); - } - Buf.writeStringDelimiter(strLen); - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - dataWriter: dataWriter, - callback: onsuccess, - onerror: onerror - }); - }, - - /** - * Get ADNLike extension record number. - * - * @param fileId EF id of the ADN or FDN. - * @param recordNumber EF record id of the ADN or FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - getADNLikeExtensionRecordNumber: function(fileId, recordNumber, onsuccess, onerror) { - let callback = (options) => { - let Buf = this.context.Buf; - let length = Buf.readInt32(); - - // Skip alphaLen, numLen, BCD Number, CCP octets. - Buf.seekIncoming((options.recordSize -1) * Buf.PDU_HEX_OCTET_SIZE); - - let extRecordNumber = this.context.GsmPDUHelper.readHexOctet(); - Buf.readStringDelimiter(length); - - onsuccess(extRecordNumber); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: fileId, - recordNumber: recordNumber, - callback: callback, - onerror: onerror - }); - }, -}; - -/** - * Helper for (U)SIM Records. - */ -function SimRecordHelperObject(aContext) { - this.context = aContext; -} -SimRecordHelperObject.prototype = { - context: null, - - /** - * Fetch (U)SIM records. - */ - fetchSimRecords: function() { - this.context.RIL.getIMSI(); - this.readAD(); - // CPHS was widely introduced in Europe during GSM(2G) era to provide easier - // access to carrier's core service like voicemail, call forwarding, manual - // PLMN selection, and etc. - // Addition EF like EF_CPHS_MBN, EF_CPHS_CPHS_CFF, EF_CPHS_VWI, etc are - // introduced to support these feature. - // In USIM, the replancement of these EFs are provided. (EF_MBDN, EF_MWIS, ...) - // However, some carriers in Europe still rely on these EFs. - this.readCphsInfo(() => this.readSST(), - (aErrorMsg) => { - this.context.debug("Failed to read CPHS_INFO: " + aErrorMsg); - this.readSST(); - }); - }, - - /** - * Read EF_phase. - * This EF is only available in SIM. - */ - readSimPhase: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - - let GsmPDUHelper = this.context.GsmPDUHelper; - let phase = GsmPDUHelper.readHexOctet(); - // If EF_phase is coded '03' or greater, an ME supporting STK shall - // perform the PROFILE DOWNLOAD procedure. - if (RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD && - phase >= ICC_PHASE_2_PROFILE_DOWNLOAD_REQUIRED) { - this.context.RIL.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE); - } - - Buf.readStringDelimiter(strLen); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_PHASE, - callback: callback.bind(this) - }); - }, - - /** - * Read the MSISDN from the (U)SIM. - */ - readMSISDN: function() { - function callback(options) { - let RIL = this.context.RIL; - - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if (!contact || - (RIL.iccInfo.msisdn !== undefined && - RIL.iccInfo.msisdn === contact.number)) { - return; - } - RIL.iccInfo.msisdn = contact.number; - if (DEBUG) this.context.debug("MSISDN: " + RIL.iccInfo.msisdn); - this.context.ICCUtilsHelper.handleICCInfoChange(); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_MSISDN, - callback: callback.bind(this) - }); - }, - - /** - * Read the AD (Administrative Data) from the (U)SIM. - */ - readAD: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let ad = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - let str = ""; - for (let i = 0; i < ad.length; i++) { - str += ad[i] + ", "; - } - this.context.debug("AD: " + str); - } - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let RIL = this.context.RIL; - // TS 31.102, clause 4.2.18 EFAD - let mncLength = 0; - if (ad && ad[3]) { - mncLength = ad[3] & 0x0f; - if (mncLength != 0x02 && mncLength != 0x03) { - mncLength = 0; - } - } - // The 4th byte of the response is the length of MNC. - let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi, - mncLength); - if (mccMnc) { - RIL.iccInfo.mcc = mccMnc.mcc; - RIL.iccInfo.mnc = mccMnc.mnc; - ICCUtilsHelper.handleICCInfoChange(); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_AD, - callback: callback.bind(this) - }); - }, - - /** - * Read the SPN (Service Provider Name) from the (U)SIM. - */ - readSPN: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let spnDisplayCondition = this.context.GsmPDUHelper.readHexOctet(); - // Minus 1 because the first octet is used to store display condition. - let spn = this.context.ICCPDUHelper.readAlphaIdentifier(octetLen - 1); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - this.context.debug("SPN: spn = " + spn + - ", spnDisplayCondition = " + spnDisplayCondition); - } - - let RIL = this.context.RIL; - RIL.iccInfoPrivate.spnDisplayCondition = spnDisplayCondition; - RIL.iccInfo.spn = spn; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - ICCUtilsHelper.updateDisplayCondition(); - ICCUtilsHelper.handleICCInfoChange(); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_SPN, - callback: callback.bind(this) - }); - }, - - readIMG: function(recordNumber, onsuccess, onerror) { - function callback(options) { - let RIL = this.context.RIL; - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - - let numInstances = GsmPDUHelper.readHexOctet(); - - // Data length is defined as 9n+1 or 9n+2. See TS 31.102, sub-clause - // 4.6.1.1. However, it's likely to have padding appended so we have a - // rather loose check. - if (octetLen < (9 * numInstances + 1)) { - Buf.seekIncoming((octetLen - 1) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - if (onerror) { - onerror(); - } - return; - } - - let imgDescriptors = []; - for (let i = 0; i < numInstances; i++) { - imgDescriptors[i] = { - width: GsmPDUHelper.readHexOctet(), - height: GsmPDUHelper.readHexOctet(), - codingScheme: GsmPDUHelper.readHexOctet(), - fileId: (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(), - offset: (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(), - dataLen: (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet() - }; - } - Buf.seekIncoming((octetLen - 9 * numInstances - 1) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - - let instances = []; - let currentInstance = 0; - let readNextInstance = (function(img) { - instances[currentInstance] = img; - currentInstance++; - - if (currentInstance < numInstances) { - let imgDescriptor = imgDescriptors[currentInstance]; - this.readIIDF(imgDescriptor.fileId, - imgDescriptor.offset, - imgDescriptor.dataLen, - imgDescriptor.codingScheme, - readNextInstance, - onerror); - } else { - if (onsuccess) { - onsuccess(instances); - } - } - }).bind(this); - - this.readIIDF(imgDescriptors[0].fileId, - imgDescriptors[0].offset, - imgDescriptors[0].dataLen, - imgDescriptors[0].codingScheme, - readNextInstance, - onerror); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_IMG, - recordNumber: recordNumber, - callback: callback.bind(this), - onerror: onerror - }); - }, - - readIIDF: function(fileId, offset, dataLen, codingScheme, onsuccess, onerror) { - // Valid fileId is '4FXX', see TS 31.102, clause 4.6.1.2. - if ((fileId >> 8) != 0x4F) { - if (onerror) { - onerror(); - } - return; - } - - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - let GsmPDUHelper = this.context.GsmPDUHelper; - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - - if (octetLen < offset + dataLen) { - // Data length is not enough. See TS 31.102, clause 4.6.1.1, the - // paragraph "Bytes 8 and 9: Length of Image Instance Data." - Buf.seekIncoming(octetLen * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - if (onerror) { - onerror(); - } - return; - } - - Buf.seekIncoming(offset * Buf.PDU_HEX_OCTET_SIZE); - - let rawData = { - width: GsmPDUHelper.readHexOctet(), - height: GsmPDUHelper.readHexOctet(), - codingScheme: codingScheme - }; - - switch (codingScheme) { - case ICC_IMG_CODING_SCHEME_BASIC: - rawData.body = GsmPDUHelper.readHexOctetArray( - dataLen - ICC_IMG_HEADER_SIZE_BASIC); - Buf.seekIncoming((octetLen - offset - dataLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - - case ICC_IMG_CODING_SCHEME_COLOR: - case ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY: - rawData.bitsPerImgPoint = GsmPDUHelper.readHexOctet(); - let num = GsmPDUHelper.readHexOctet(); - // The value 0 shall be interpreted as 256. See TS 31.102, Annex B.2. - rawData.numOfClutEntries = (num === 0) ? 0x100 : num; - rawData.clutOffset = (GsmPDUHelper.readHexOctet() << 8) | - GsmPDUHelper.readHexOctet(); - rawData.body = GsmPDUHelper.readHexOctetArray( - dataLen - ICC_IMG_HEADER_SIZE_COLOR); - - Buf.seekIncoming((rawData.clutOffset - offset - dataLen) * - Buf.PDU_HEX_OCTET_SIZE); - let clut = GsmPDUHelper.readHexOctetArray(rawData.numOfClutEntries * - ICC_CLUT_ENTRY_SIZE); - - rawData.clut = clut; - } - - Buf.readStringDelimiter(strLen); - - if (onsuccess) { - onsuccess(rawData); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: fileId, - pathId: this.context.ICCFileHelper.getEFPath(ICC_EF_IMG), - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Read the (U)SIM Service Table from the (U)SIM. - */ - readSST: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let sst = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - RIL.iccInfoPrivate.sst = sst; - if (DEBUG) { - let str = ""; - for (let i = 0; i < sst.length; i++) { - str += sst[i] + ", "; - } - this.context.debug("SST: " + str); - } - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.isICCServiceAvailable("MSISDN")) { - if (DEBUG) this.context.debug("MSISDN: MSISDN is available"); - this.readMSISDN(); - } else { - if (DEBUG) this.context.debug("MSISDN: MSISDN service is not available"); - } - - // Fetch SPN and PLMN list, if some of them are available. - if (ICCUtilsHelper.isICCServiceAvailable("SPN")) { - if (DEBUG) this.context.debug("SPN: SPN is available"); - this.readSPN(); - } else { - if (DEBUG) this.context.debug("SPN: SPN service is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("MDN")) { - if (DEBUG) this.context.debug("MDN: MDN available."); - this.readMBDN(); - } else { - if (DEBUG) this.context.debug("MDN: MDN service is not available"); - - if (ICCUtilsHelper.isCphsServiceAvailable("MBN")) { - // read CPHS_MBN in advance if MBDN is not available. - this.readCphsMBN(); - } else { - if (DEBUG) this.context.debug("CPHS_MBN: CPHS_MBN service is not available"); - } - } - - if (ICCUtilsHelper.isICCServiceAvailable("MWIS")) { - if (DEBUG) this.context.debug("MWIS: MWIS is available"); - this.readMWIS(); - } else { - if (DEBUG) this.context.debug("MWIS: MWIS is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("SPDI")) { - if (DEBUG) this.context.debug("SPDI: SPDI available."); - this.readSPDI(); - } else { - if (DEBUG) this.context.debug("SPDI: SPDI service is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("PNN")) { - if (DEBUG) this.context.debug("PNN: PNN is available"); - this.readPNN(); - } else { - if (DEBUG) this.context.debug("PNN: PNN is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("OPL")) { - if (DEBUG) this.context.debug("OPL: OPL is available"); - this.readOPL(); - } else { - if (DEBUG) this.context.debug("OPL: OPL is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("GID1")) { - if (DEBUG) this.context.debug("GID1: GID1 is available"); - this.readGID1(); - } else { - if (DEBUG) this.context.debug("GID1: GID1 is not available"); - } - - if (ICCUtilsHelper.isICCServiceAvailable("CBMI")) { - this.readCBMI(); - } else { - RIL.cellBroadcastConfigs.CBMI = null; - } - if (ICCUtilsHelper.isICCServiceAvailable("DATA_DOWNLOAD_SMS_CB")) { - this.readCBMID(); - } else { - RIL.cellBroadcastConfigs.CBMID = null; - } - if (ICCUtilsHelper.isICCServiceAvailable("CBMIR")) { - this.readCBMIR(); - } else { - RIL.cellBroadcastConfigs.CBMIR = null; - } - RIL._mergeAllCellBroadcastConfigs(); - } - - // ICC_EF_UST has the same value with ICC_EF_SST. - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_SST, - callback: callback.bind(this) - }); - }, - - /** - * Read (U)SIM MBDN. (Mailbox Dialling Number) - * - * @see TS 131.102, clause 4.2.60 - */ - readMBDN: function() { - function callback(options) { - let RIL = this.context.RIL; - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if ((!contact || - ((!contact.alphaId || contact.alphaId == "") && - (!contact.number || contact.number == ""))) && - this.context.ICCUtilsHelper.isCphsServiceAvailable("MBN")) { - // read CPHS_MBN in advance if MBDN is invalid or empty. - this.readCphsMBN(); - return; - } - - if (!contact || - (RIL.iccInfoPrivate.mbdn !== undefined && - RIL.iccInfoPrivate.mbdn === contact.number)) { - return; - } - RIL.iccInfoPrivate.mbdn = contact.number; - if (DEBUG) { - this.context.debug("MBDN, alphaId=" + contact.alphaId + - " number=" + contact.number); - } - contact.rilMessageType = "iccmbdn"; - RIL.sendChromeMessage(contact); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_MBDN, - callback: callback.bind(this) - }); - }, - - /** - * Read ICC MWIS. (Message Waiting Indication Status) - * - * @see TS 31.102, clause 4.2.63 for USIM and TS 51.011, clause 10.3.45 for SIM. - */ - readMWIS: function() { - function callback(options) { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let mwis = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - if (!mwis) { - return; - } - RIL.iccInfoPrivate.mwis = mwis; //Keep raw MWIS for updateMWIS() - - let mwi = {}; - // b8 b7 B6 b5 b4 b3 b2 b1 4.2.63, TS 31.102 version 11.6.0 - // | | | | | | | |__ Voicemail - // | | | | | | |_____ Fax - // | | | | | |________ Electronic Mail - // | | | | |___________ Other - // | | | |______________ Videomail - // |__|__|_________________ RFU - mwi.active = ((mwis[0] & 0x01) != 0); - - if (mwi.active) { - // In TS 23.040 msgCount is in the range from 0 to 255. - // The value 255 shall be taken to mean 255 or greater. - // - // However, There is no definition about 0 when MWI is active. - // - // Normally, when mwi is active, the msgCount must be larger than 0. - // Refer to other reference phone, - // 0 is usually treated as UNKNOWN for storing 2nd level MWI status (DCS). - mwi.msgCount = (mwis[1] === 0) ? GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN - : mwis[1]; - } else { - mwi.msgCount = 0; - } - - RIL.sendChromeMessage({ rilMessageType: "iccmwis", - mwi: mwi }); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_MWIS, - recordNumber: 1, // Get 1st Subscriber Profile. - callback: callback.bind(this) - }); - }, - - /** - * Update ICC MWIS. (Message Waiting Indication Status) - * - * @see TS 31.102, clause 4.2.63 for USIM and TS 51.011, clause 10.3.45 for SIM. - */ - updateMWIS: function(mwi) { - let RIL = this.context.RIL; - if (!RIL.iccInfoPrivate.mwis) { - return; - } - - function dataWriter(recordSize) { - let mwis = RIL.iccInfoPrivate.mwis; - - let msgCount = - (mwi.msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : mwi.msgCount; - - [mwis[0], mwis[1]] = (mwi.active) ? [(mwis[0] | 0x01), msgCount] - : [(mwis[0] & 0xFE), 0]; - - let strLen = recordSize * 2; - let Buf = this.context.Buf; - Buf.writeInt32(strLen); - - let GsmPDUHelper = this.context.GsmPDUHelper; - for (let i = 0; i < mwis.length; i++) { - GsmPDUHelper.writeHexOctet(mwis[i]); - } - - Buf.writeStringDelimiter(strLen); - } - - this.context.ICCIOHelper.updateLinearFixedEF({ - fileId: ICC_EF_MWIS, - recordNumber: 1, // Update 1st Subscriber Profile. - dataWriter: dataWriter.bind(this) - }); - }, - - /** - * Read the SPDI (Service Provider Display Information) from the (U)SIM. - * - * See TS 131.102 section 4.2.66 for USIM and TS 51.011 section 10.3.50 - * for SIM. - */ - readSPDI: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let readLen = 0; - let endLoop = false; - - let RIL = this.context.RIL; - RIL.iccInfoPrivate.SPDI = null; - - let GsmPDUHelper = this.context.GsmPDUHelper; - while ((readLen < octetLen) && !endLoop) { - let tlvTag = GsmPDUHelper.readHexOctet(); - let tlvLen = GsmPDUHelper.readHexOctet(); - readLen += 2; // For tag and length fields. - switch (tlvTag) { - case SPDI_TAG_SPDI: - // The value part itself is a TLV. - continue; - case SPDI_TAG_PLMN_LIST: - // This PLMN list is what we want. - RIL.iccInfoPrivate.SPDI = this.readPLMNEntries(tlvLen / 3); - readLen += tlvLen; - endLoop = true; - break; - default: - // We don't care about its content if its tag is not SPDI nor - // PLMN_LIST. - endLoop = true; - break; - } - } - - // Consume unread octets. - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - this.context.debug("SPDI: " + JSON.stringify(RIL.iccInfoPrivate.SPDI)); - } - let ICCUtilsHelper = this.context.ICCUtilsHelper; - if (ICCUtilsHelper.updateDisplayCondition()) { - ICCUtilsHelper.handleICCInfoChange(); - } - } - - // PLMN List is Servive 51 in USIM, EF_SPDI - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_SPDI, - callback: callback.bind(this) - }); - }, - - _readCbmiHelper: function(which) { - let RIL = this.context.RIL; - - function callback() { - let Buf = this.context.Buf; - let strLength = Buf.readInt32(); - - // Each Message Identifier takes two octets and each octet is encoded - // into two chars. - let numIds = strLength / 4, list = null; - if (numIds) { - list = []; - let GsmPDUHelper = this.context.GsmPDUHelper; - for (let i = 0, id; i < numIds; i++) { - id = GsmPDUHelper.readHexOctet() << 8 | GsmPDUHelper.readHexOctet(); - // `Unused entries shall be set to 'FF FF'.` - if (id != 0xFFFF) { - list.push(id); - list.push(id + 1); - } - } - } - if (DEBUG) { - this.context.debug(which + ": " + JSON.stringify(list)); - } - - Buf.readStringDelimiter(strLength); - - RIL.cellBroadcastConfigs[which] = list; - RIL._mergeAllCellBroadcastConfigs(); - } - - function onerror() { - RIL.cellBroadcastConfigs[which] = null; - RIL._mergeAllCellBroadcastConfigs(); - } - - let fileId = GLOBAL["ICC_EF_" + which]; - this.context.ICCIOHelper.loadTransparentEF({ - fileId: fileId, - callback: callback.bind(this), - onerror: onerror.bind(this) - }); - }, - - /** - * Read EFcbmi (Cell Broadcast Message Identifier selection) - * - * @see 3GPP TS 31.102 v110.02.0 section 4.2.14 EFcbmi - * @see 3GPP TS 51.011 v5.0.0 section 10.3.13 EFcbmi - */ - readCBMI: function() { - this._readCbmiHelper("CBMI"); - }, - - /** - * Read EFcbmid (Cell Broadcast Message Identifier for Data Download) - * - * @see 3GPP TS 31.102 v110.02.0 section 4.2.20 EFcbmid - * @see 3GPP TS 51.011 v5.0.0 section 10.3.26 EFcbmid - */ - readCBMID: function() { - this._readCbmiHelper("CBMID"); - }, - - /** - * Read EFcbmir (Cell Broadcast Message Identifier Range selection) - * - * @see 3GPP TS 31.102 v110.02.0 section 4.2.22 EFcbmir - * @see 3GPP TS 51.011 v5.0.0 section 10.3.28 EFcbmir - */ - readCBMIR: function() { - let RIL = this.context.RIL; - - function callback() { - let Buf = this.context.Buf; - let strLength = Buf.readInt32(); - - // Each Message Identifier range takes four octets and each octet is - // encoded into two chars. - let numIds = strLength / 8, list = null; - if (numIds) { - list = []; - let GsmPDUHelper = this.context.GsmPDUHelper; - for (let i = 0, from, to; i < numIds; i++) { - // `Bytes one and two of each range identifier equal the lower value - // of a cell broadcast range, bytes three and four equal the upper - // value of a cell broadcast range.` - from = GsmPDUHelper.readHexOctet() << 8 | GsmPDUHelper.readHexOctet(); - to = GsmPDUHelper.readHexOctet() << 8 | GsmPDUHelper.readHexOctet(); - // `Unused entries shall be set to 'FF FF'.` - if ((from != 0xFFFF) && (to != 0xFFFF)) { - list.push(from); - list.push(to + 1); - } - } - } - if (DEBUG) { - this.context.debug("CBMIR: " + JSON.stringify(list)); - } - - Buf.readStringDelimiter(strLength); - - RIL.cellBroadcastConfigs.CBMIR = list; - RIL._mergeAllCellBroadcastConfigs(); - } - - function onerror() { - RIL.cellBroadcastConfigs.CBMIR = null; - RIL._mergeAllCellBroadcastConfigs(); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CBMIR, - callback: callback.bind(this), - onerror: onerror.bind(this) - }); - }, - - /** - * Read OPL (Operator PLMN List) from (U)SIM. - * - * See 3GPP TS 31.102 Sec. 4.2.59 for USIM - * 3GPP TS 51.011 Sec. 10.3.42 for SIM. - */ - readOPL: function() { - let ICCIOHelper = this.context.ICCIOHelper; - let opl = []; - function callback(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - // The first 7 bytes are LAI (for UMTS) and the format of LAI is defined - // in 3GPP TS 23.003, Sec 4.1 - // +-------------+---------+ - // | Octet 1 - 3 | MCC/MNC | - // +-------------+---------+ - // | Octet 4 - 7 | LAC | - // +-------------+---------+ - let mccMnc = [GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet()]; - if (mccMnc[0] != 0xFF || mccMnc[1] != 0xFF || mccMnc[2] != 0xFF) { - let oplElement = {}; - let semiOctets = []; - for (let i = 0; i < mccMnc.length; i++) { - semiOctets.push((mccMnc[i] & 0xf0) >> 4); - semiOctets.push(mccMnc[i] & 0x0f); - } - let reformat = [semiOctets[1], semiOctets[0], semiOctets[3], - semiOctets[5], semiOctets[4], semiOctets[2]]; - let buf = ""; - for (let i = 0; i < reformat.length; i++) { - if (reformat[i] != 0xF) { - buf += GsmPDUHelper.semiOctetToExtendedBcdChar(reformat[i]); - } - if (i === 2) { - // 0-2: MCC - oplElement.mcc = buf; - buf = ""; - } else if (i === 5) { - // 3-5: MNC - oplElement.mnc = buf; - } - } - // LAC/TAC - oplElement.lacTacStart = - (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - oplElement.lacTacEnd = - (GsmPDUHelper.readHexOctet() << 8) | GsmPDUHelper.readHexOctet(); - // PLMN Network Name Record Identifier - oplElement.pnnRecordId = GsmPDUHelper.readHexOctet(); - if (DEBUG) { - this.context.debug("OPL: [" + (opl.length + 1) + "]: " + - JSON.stringify(oplElement)); - } - opl.push(oplElement); - } else { - Buf.seekIncoming(5 * Buf.PDU_HEX_OCTET_SIZE); - } - Buf.readStringDelimiter(strLen); - - let RIL = this.context.RIL; - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - RIL.iccInfoPrivate.OPL = opl; - RIL.overrideICCNetworkName(); - } - } - - ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_OPL, - callback: callback.bind(this)}); - }, - - /** - * Read PNN (PLMN Network Name) from (U)SIM. - * - * See 3GPP TS 31.102 Sec. 4.2.58 for USIM - * 3GPP TS 51.011 Sec. 10.3.41 for SIM. - */ - readPNN: function() { - let ICCIOHelper = this.context.ICCIOHelper; - function callback(options) { - let pnnElement; - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - let readLen = 0; - - let GsmPDUHelper = this.context.GsmPDUHelper; - while (readLen < octetLen) { - let tlvTag = GsmPDUHelper.readHexOctet(); - - if (tlvTag == 0xFF) { - // Unused byte - readLen++; - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - break; - } - - // Needs this check to avoid initializing twice. - pnnElement = pnnElement || {}; - - let tlvLen = GsmPDUHelper.readHexOctet(); - - switch (tlvTag) { - case PNN_IEI_FULL_NETWORK_NAME: - pnnElement.fullName = GsmPDUHelper.readNetworkName(tlvLen); - break; - case PNN_IEI_SHORT_NETWORK_NAME: - pnnElement.shortName = GsmPDUHelper.readNetworkName(tlvLen); - break; - default: - Buf.seekIncoming(tlvLen * Buf.PDU_HEX_OCTET_SIZE); - break; - } - - readLen += (tlvLen + 2); // +2 for tlvTag and tlvLen - } - Buf.readStringDelimiter(strLen); - - pnn.push(pnnElement); - - let RIL = this.context.RIL; - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - if (DEBUG) { - for (let i = 0; i < pnn.length; i++) { - this.context.debug("PNN: [" + i + "]: " + JSON.stringify(pnn[i])); - } - } - RIL.iccInfoPrivate.PNN = pnn; - RIL.overrideICCNetworkName(); - } - } - - let pnn = []; - ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_PNN, - callback: callback.bind(this)}); - }, - - /** - * Read the list of PLMN (Public Land Mobile Network) entries - * We cannot directly rely on readSwappedNibbleBcdToString(), - * since it will no correctly handle some corner-cases that are - * not a problem in our case (0xFF 0xFF 0xFF). - * - * @param length The number of PLMN records. - * @return An array of string corresponding to the PLMNs. - */ - readPLMNEntries: function(length) { - let plmnList = []; - // Each PLMN entry has 3 bytes. - if (DEBUG) { - this.context.debug("PLMN entries length = " + length); - } - let GsmPDUHelper = this.context.GsmPDUHelper; - let index = 0; - while (index < length) { - // Unused entries will be 0xFFFFFF, according to EF_SPDI - // specs (TS 131 102, section 4.2.66) - try { - let plmn = [GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet(), - GsmPDUHelper.readHexOctet()]; - if (DEBUG) { - this.context.debug("Reading PLMN entry: [" + index + "]: '" + plmn + "'"); - } - if (plmn[0] != 0xFF && - plmn[1] != 0xFF && - plmn[2] != 0xFF) { - let semiOctets = []; - for (let idx = 0; idx < plmn.length; idx++) { - semiOctets.push((plmn[idx] & 0xF0) >> 4); - semiOctets.push(plmn[idx] & 0x0F); - } - - // According to TS 24.301, 9.9.3.12, the semi octets is arranged - // in format: - // Byte 1: MCC[2] | MCC[1] - // Byte 2: MNC[3] | MCC[3] - // Byte 3: MNC[2] | MNC[1] - // Therefore, we need to rearrange them. - let reformat = [semiOctets[1], semiOctets[0], semiOctets[3], - semiOctets[5], semiOctets[4], semiOctets[2]]; - let buf = ""; - let plmnEntry = {}; - for (let i = 0; i < reformat.length; i++) { - if (reformat[i] != 0xF) { - buf += GsmPDUHelper.semiOctetToExtendedBcdChar(reformat[i]); - } - if (i === 2) { - // 0-2: MCC - plmnEntry.mcc = buf; - buf = ""; - } else if (i === 5) { - // 3-5: MNC - plmnEntry.mnc = buf; - } - } - if (DEBUG) { - this.context.debug("PLMN = " + plmnEntry.mcc + ", " + plmnEntry.mnc); - } - plmnList.push(plmnEntry); - } - } catch (e) { - if (DEBUG) { - this.context.debug("PLMN entry " + index + " is invalid."); - } - break; - } - index ++; - } - return plmnList; - }, - - /** - * Read the SMS from the ICC. - * - * @param recordNumber The number of the record shall be loaded. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readSMS: function(recordNumber, onsuccess, onerror) { - function callback(options) { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - - // TS 51.011, 10.5.3 EF_SMS - // b3 b2 b1 - // 0 0 1 message received by MS from network; message read - // 0 1 1 message received by MS from network; message to be read - // 1 1 1 MS originating message; message to be sent - // 1 0 1 MS originating message; message sent to the network: - let GsmPDUHelper = this.context.GsmPDUHelper; - let status = GsmPDUHelper.readHexOctet(); - - let message = GsmPDUHelper.readMessage(); - message.simStatus = status; - - // Consumes the remaining buffer - Buf.seekIncoming(Buf.getReadAvailable() - Buf.PDU_HEX_OCTET_SIZE); - - Buf.readStringDelimiter(strLen); - - if (message) { - onsuccess(message); - } else { - onerror("Failed to decode SMS on SIM #" + recordNumber); - } - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_SMS, - recordNumber: recordNumber, - callback: callback.bind(this), - onerror: onerror - }); - }, - - readGID1: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - RIL.iccInfoPrivate.gid1 = Buf.readString(); - if (DEBUG) { - this.context.debug("GID1: " + RIL.iccInfoPrivate.gid1); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_GID1, - callback: callback.bind(this) - }); - }, - - /** - * Read CPHS Phase & Service Table from CPHS Info. - * - * @See B.3.1.1 CPHS Information in CPHS Phase 2. - * - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readCphsInfo: function(onsuccess, onerror) { - function callback() { - try { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - let octetLen = strLen / 2; - let cphsInfo = this.context.GsmPDUHelper.readHexOctetArray(octetLen); - Buf.readStringDelimiter(strLen); - if (DEBUG) { - let str = ""; - for (let i = 0; i < cphsInfo.length; i++) { - str += cphsInfo[i] + ", "; - } - this.context.debug("CPHS INFO: " + str); - } - - /** - * CPHS INFORMATION - * - * Byte 1: CPHS Phase - * 01 phase 1 - * 02 phase 2 - * etc. - * - * Byte 2: CPHS Service Table - * +----+----+----+----+----+----+----+----+ - * | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | - * +----+----+----+----+----+----+----+----+ - * | ONSF | MBN | SST | CSP | - * | Phase 2 | ALL | Phase 1 | All | - * +----+----+----+----+----+----+----+----+ - * - * Byte 3: CPHS Service Table continued - * +----+----+----+----+----+----+----+----+ - * | b8 | b7 | b6 | b5 | b4 | b3 | b2 | b1 | - * +----+----+----+----+----+----+----+----+ - * | RFU | RFU | RFU | INFO_NUM| - * | | | | Phase 2 | - * +----+----+----+----+----+----+----+----+ - */ - let cphsPhase = cphsInfo[0]; - if (cphsPhase == 1) { - // Clear 'Phase 2 only' services. - cphsInfo[1] &= 0x3F; - // We don't know whether Byte 3 is available in CPHS phase 1 or not. - // Add boundary check before accessing it. - if (cphsInfo.length > 2) { - cphsInfo[2] = 0x00; - } - } else if (cphsPhase == 2) { - // Clear 'Phase 1 only' services. - cphsInfo[1] &= 0xF3; - } else { - throw new Error("Unknown CPHS phase: " + cphsPhase); - } - - RIL.iccInfoPrivate.cphsSt = cphsInfo.subarray(1); - onsuccess(); - } catch(e) { - onerror(e.toString()); - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CPHS_INFO, - callback: callback.bind(this), - onerror: onerror - }); - }, - - /** - * Read CPHS MBN. (Mailbox Numbers) - * - * @See B.4.2.2 Voice Message Retrieval and Indicator Clearing - */ - readCphsMBN: function() { - function callback(options) { - let RIL = this.context.RIL; - let contact = - this.context.ICCPDUHelper.readAlphaIdDiallingNumber(options.recordSize); - if (!contact || - (RIL.iccInfoPrivate.mbdn !== undefined && - RIL.iccInfoPrivate.mbdn === contact.number)) { - return; - } - RIL.iccInfoPrivate.mbdn = contact.number; - if (DEBUG) { - this.context.debug("CPHS_MDN, alphaId=" + contact.alphaId + - " number=" + contact.number); - } - contact.rilMessageType = "iccmbdn"; - RIL.sendChromeMessage(contact); - } - - this.context.ICCIOHelper.loadLinearFixedEF({ - fileId: ICC_EF_CPHS_MBN, - callback: callback.bind(this) - }); - } -}; - -function RuimRecordHelperObject(aContext) { - this.context = aContext; -} -RuimRecordHelperObject.prototype = { - context: null, - - fetchRuimRecords: function() { - this.getIMSI_M(); - this.readCST(); - this.readCDMAHome(); - this.context.RIL.getCdmaSubscription(); - }, - - /** - * Get IMSI_M from CSIM/RUIM. - * See 3GPP2 C.S0065 Sec. 5.2.2 - */ - getIMSI_M: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let encodedImsi = this.context.GsmPDUHelper.readHexOctetArray(strLen / 2); - Buf.readStringDelimiter(strLen); - - if ((encodedImsi[CSIM_IMSI_M_PROGRAMMED_BYTE] & 0x80)) { // IMSI_M programmed - let RIL = this.context.RIL; - RIL.iccInfoPrivate.imsi = this.decodeIMSI(encodedImsi); - RIL.sendChromeMessage({rilMessageType: "iccimsi", - imsi: RIL.iccInfoPrivate.imsi}); - - let ICCUtilsHelper = this.context.ICCUtilsHelper; - let mccMnc = ICCUtilsHelper.parseMccMncFromImsi(RIL.iccInfoPrivate.imsi); - if (mccMnc) { - RIL.iccInfo.mcc = mccMnc.mcc; - RIL.iccInfo.mnc = mccMnc.mnc; - ICCUtilsHelper.handleICCInfoChange(); - } - } - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CSIM_IMSI_M, - callback: callback.bind(this) - }); - }, - - /** - * Decode IMSI from IMSI_M - * See 3GPP2 C.S0005 Sec. 2.3.1 - * +---+---------+------------+---+--------+---------+---+---------+--------+ - * |RFU| MCC | programmed |RFU| MNC | MIN1 |RFU| MIN2 | CLASS | - * +---+---------+------------+---+--------+---------+---+---------+--------+ - * | 6 | 10 bits | 8 bits | 1 | 7 bits | 24 bits | 6 | 10 bits | 8 bits | - * +---+---------+------------+---+--------+---------+---+---------+--------+ - */ - decodeIMSI: function(encodedImsi) { - // MCC: 10 bits, 3 digits - let encodedMCC = ((encodedImsi[CSIM_IMSI_M_MCC_BYTE + 1] & 0x03) << 8) + - (encodedImsi[CSIM_IMSI_M_MCC_BYTE] & 0xff); - let mcc = this.decodeIMSIValue(encodedMCC, 3); - - // MNC: 7 bits, 2 digits - let encodedMNC = encodedImsi[CSIM_IMSI_M_MNC_BYTE] & 0x7f; - let mnc = this.decodeIMSIValue(encodedMNC, 2); - - // MIN2: 10 bits, 3 digits - let encodedMIN2 = ((encodedImsi[CSIM_IMSI_M_MIN2_BYTE + 1] & 0x03) << 8) + - (encodedImsi[CSIM_IMSI_M_MIN2_BYTE] & 0xff); - let min2 = this.decodeIMSIValue(encodedMIN2, 3); - - // MIN1: 10+4+10 bits, 3+1+3 digits - let encodedMIN1First3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 2] & 0xff) << 2) + - ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0xc0) >> 6); - let min1First3 = this.decodeIMSIValue(encodedMIN1First3, 3); - - let encodedFourthDigit = (encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x3c) >> 2; - if (encodedFourthDigit > 9) { - encodedFourthDigit = 0; - } - let fourthDigit = encodedFourthDigit.toString(); - - let encodedMIN1Last3 = ((encodedImsi[CSIM_IMSI_M_MIN1_BYTE + 1] & 0x03) << 8) + - (encodedImsi[CSIM_IMSI_M_MIN1_BYTE] & 0xff); - let min1Last3 = this.decodeIMSIValue(encodedMIN1Last3, 3); - - return mcc + mnc + min2 + min1First3 + fourthDigit + min1Last3; - }, - - /** - * Decode IMSI Helper function - * See 3GPP2 C.S0005 section 2.3.1.1 - */ - decodeIMSIValue: function(encoded, length) { - let offset = length === 3 ? 111 : 11; - let value = encoded + offset; - - for (let base = 10, temp = value, i = 0; i < length; i++) { - if (temp % 10 === 0) { - value -= base; - } - temp = Math.floor(value / base); - base = base * 10; - } - - let s = value.toString(); - while (s.length < length) { - s = "0" + s; - } - - return s; - }, - - /** - * Read CDMAHOME for CSIM. - * See 3GPP2 C.S0023 Sec. 3.4.8. - */ - readCDMAHome: function() { - let ICCIOHelper = this.context.ICCIOHelper; - - function callback(options) { - let Buf = this.context.Buf; - let GsmPDUHelper = this.context.GsmPDUHelper; - - let strLen = Buf.readInt32(); - let tempOctet = GsmPDUHelper.readHexOctet(); - cdmaHomeSystemId.push(((GsmPDUHelper.readHexOctet() & 0x7f) << 8) | tempOctet); - tempOctet = GsmPDUHelper.readHexOctet(); - cdmaHomeNetworkId.push(((GsmPDUHelper.readHexOctet() & 0xff) << 8) | tempOctet); - - // Consuming the last octet: band class. - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - - Buf.readStringDelimiter(strLen); - if (options.p1 < options.totalRecords) { - ICCIOHelper.loadNextRecord(options); - } else { - if (DEBUG) { - this.context.debug("CDMAHome system id: " + - JSON.stringify(cdmaHomeSystemId)); - this.context.debug("CDMAHome network id: " + - JSON.stringify(cdmaHomeNetworkId)); - } - this.context.RIL.cdmaHome = { - systemId: cdmaHomeSystemId, - networkId: cdmaHomeNetworkId - }; - } - } - - let cdmaHomeSystemId = [], cdmaHomeNetworkId = []; - ICCIOHelper.loadLinearFixedEF({fileId: ICC_EF_CSIM_CDMAHOME, - callback: callback.bind(this)}); - }, - - /** - * Read CDMA Service Table. - * See 3GPP2 C.S0023 Sec. 3.4.18 - */ - readCST: function() { - function callback() { - let Buf = this.context.Buf; - let RIL = this.context.RIL; - - let strLen = Buf.readInt32(); - // Each octet is encoded into two chars. - RIL.iccInfoPrivate.cst = - this.context.GsmPDUHelper.readHexOctetArray(strLen / 2); - Buf.readStringDelimiter(strLen); - - if (DEBUG) { - let str = ""; - for (let i = 0; i < RIL.iccInfoPrivate.cst.length; i++) { - str += RIL.iccInfoPrivate.cst[i] + ", "; - } - this.context.debug("CST: " + str); - } - - if (this.context.ICCUtilsHelper.isICCServiceAvailable("SPN")) { - if (DEBUG) this.context.debug("SPN: SPN is available"); - this.readSPN(); - } - } - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CSIM_CST, - callback: callback.bind(this) - }); - }, - - readSPN: function() { - function callback() { - let Buf = this.context.Buf; - let strLen = Buf.readInt32(); - let octetLen = strLen / 2; - - let GsmPDUHelper = this.context.GsmPDUHelper; - let displayCondition = GsmPDUHelper.readHexOctet(); - let codingScheme = GsmPDUHelper.readHexOctet(); - // Skip one octet: language indicator. - Buf.seekIncoming(Buf.PDU_HEX_OCTET_SIZE); - let readLen = 3; - - // SPN String ends up with 0xff. - let userDataBuffer = []; - - while (readLen < octetLen) { - let octet = GsmPDUHelper.readHexOctet(); - readLen++; - if (octet == 0xff) { - break; - } - userDataBuffer.push(octet); - } - - this.context.BitBufferHelper.startRead(userDataBuffer); - - let CdmaPDUHelper = this.context.CdmaPDUHelper; - let msgLen; - switch (CdmaPDUHelper.getCdmaMsgEncoding(codingScheme)) { - case PDU_DCS_MSG_CODING_7BITS_ALPHABET: - msgLen = Math.floor(userDataBuffer.length * 8 / 7); - break; - case PDU_DCS_MSG_CODING_8BITS_ALPHABET: - msgLen = userDataBuffer.length; - break; - case PDU_DCS_MSG_CODING_16BITS_ALPHABET: - msgLen = Math.floor(userDataBuffer.length / 2); - break; - } - - let RIL = this.context.RIL; - RIL.iccInfo.spn = CdmaPDUHelper.decodeCdmaPDUMsg(codingScheme, null, msgLen); - if (DEBUG) { - this.context.debug("CDMA SPN: " + RIL.iccInfo.spn + - ", Display condition: " + displayCondition); - } - RIL.iccInfoPrivate.spnDisplayCondition = displayCondition; - Buf.seekIncoming((octetLen - readLen) * Buf.PDU_HEX_OCTET_SIZE); - Buf.readStringDelimiter(strLen); - } - - this.context.ICCIOHelper.loadTransparentEF({ - fileId: ICC_EF_CSIM_SPN, - callback: callback.bind(this) - }); - } -}; - -/** - * Helper functions for ICC utilities. - */ -function ICCUtilsHelperObject(aContext) { - this.context = aContext; -} -ICCUtilsHelperObject.prototype = { - context: null, - - /** - * Get network names by using EF_OPL and EF_PNN - * - * @See 3GPP TS 31.102 sec. 4.2.58 and sec. 4.2.59 for USIM, - * 3GPP TS 51.011 sec. 10.3.41 and sec. 10.3.42 for SIM. - * - * @param mcc The mobile country code of the network. - * @param mnc The mobile network code of the network. - * @param lac The location area code of the network. - */ - getNetworkNameFromICC: function(mcc, mnc, lac) { - let RIL = this.context.RIL; - let iccInfoPriv = RIL.iccInfoPrivate; - let iccInfo = RIL.iccInfo; - let pnnEntry; - - if (!mcc || !mnc || lac == null || lac < 0) { - return null; - } - - // We won't get network name if there is no PNN file. - if (!iccInfoPriv.PNN) { - return null; - } - - if (!this.isICCServiceAvailable("OPL")) { - // When OPL is not present: - // According to 3GPP TS 31.102 Sec. 4.2.58 and 3GPP TS 51.011 Sec. 10.3.41, - // If EF_OPL is not present, the first record in this EF is used for the - // default network name when registered to the HPLMN. - // If we haven't get pnnEntry assigned, we should try to assign default - // value to it. - if (mcc == iccInfo.mcc && mnc == iccInfo.mnc) { - pnnEntry = iccInfoPriv.PNN[0]; - } - } else { - let GsmPDUHelper = this.context.GsmPDUHelper; - let wildChar = GsmPDUHelper.extendedBcdChars.charAt(0x0d); - // According to 3GPP TS 31.102 Sec. 4.2.59 and 3GPP TS 51.011 Sec. 10.3.42, - // the ME shall use this EF_OPL in association with the EF_PNN in place - // of any network name stored within the ME's internal list and any network - // name received when registered to the PLMN. - let length = iccInfoPriv.OPL ? iccInfoPriv.OPL.length : 0; - for (let i = 0; i < length; i++) { - let unmatch = false; - let opl = iccInfoPriv.OPL[i]; - // Try to match the MCC/MNC. Besides, A BCD value of 'D' in any of the - // MCC and/or MNC digits shall be used to indicate a "wild" value for - // that corresponding MCC/MNC digit. - if (opl.mcc.indexOf(wildChar) !== -1) { - for (let j = 0; j < opl.mcc.length; j++) { - if (opl.mcc[j] !== wildChar && opl.mcc[j] !== mcc[j]) { - unmatch = true; - break; - } - } - if (unmatch) { - continue; - } - } else { - if (mcc !== opl.mcc) { - continue; - } - } - - if (mnc.length !== opl.mnc.length) { - continue; - } - - if (opl.mnc.indexOf(wildChar) !== -1) { - for (let j = 0; j < opl.mnc.length; j++) { - if (opl.mnc[j] !== wildChar && opl.mnc[j] !== mnc[j]) { - unmatch = true; - break; - } - } - if (unmatch) { - continue; - } - } else { - if (mnc !== opl.mnc) { - continue; - } - } - - // Try to match the location area code. If current local area code is - // covered by lac range that specified in the OPL entry, use the PNN - // that specified in the OPL entry. - if ((opl.lacTacStart === 0x0 && opl.lacTacEnd == 0xFFFE) || - (opl.lacTacStart <= lac && opl.lacTacEnd >= lac)) { - if (opl.pnnRecordId === 0) { - // See 3GPP TS 31.102 Sec. 4.2.59 and 3GPP TS 51.011 Sec. 10.3.42, - // A value of '00' indicates that the name is to be taken from other - // sources. - return null; - } - pnnEntry = iccInfoPriv.PNN[opl.pnnRecordId - 1]; - break; - } - } - } - - if (!pnnEntry) { - return null; - } - - // Return a new object to avoid global variable, PNN, be modified by accident. - return { fullName: pnnEntry.fullName || "", - shortName: pnnEntry.shortName || "" }; - }, - - /** - * This will compute the spnDisplay field of the network. - * See TS 22.101 Annex A and TS 51.011 10.3.11 for details. - * - * @return True if some of iccInfo is changed in by this function. - */ - updateDisplayCondition: function() { - let RIL = this.context.RIL; - - // If EFspn isn't existed in SIM or it haven't been read yet, we should - // just set isDisplayNetworkNameRequired = true and - // isDisplaySpnRequired = false - let iccInfo = RIL.iccInfo; - let iccInfoPriv = RIL.iccInfoPrivate; - let displayCondition = iccInfoPriv.spnDisplayCondition; - let origIsDisplayNetworkNameRequired = iccInfo.isDisplayNetworkNameRequired; - let origIsDisplaySPNRequired = iccInfo.isDisplaySpnRequired; - - if (displayCondition === undefined) { - iccInfo.isDisplayNetworkNameRequired = true; - iccInfo.isDisplaySpnRequired = false; - } else if (RIL._isCdma) { - // CDMA family display rule. - let cdmaHome = RIL.cdmaHome; - let cell = RIL.voiceRegistrationState.cell; - let sid = cell && cell.cdmaSystemId; - let nid = cell && cell.cdmaNetworkId; - - iccInfo.isDisplayNetworkNameRequired = false; - - // If display condition is 0x0, we don't even need to check network id - // or system id. - if (displayCondition === 0x0) { - iccInfo.isDisplaySpnRequired = false; - } else { - // CDMA SPN Display condition dosen't specify whenever network name is - // reqired. - if (!cdmaHome || - !cdmaHome.systemId || - cdmaHome.systemId.length === 0 || - cdmaHome.systemId.length != cdmaHome.networkId.length || - !sid || !nid) { - // CDMA Home haven't been ready, or we haven't got the system id and - // network id of the network we register to, assuming we are in home - // network. - iccInfo.isDisplaySpnRequired = true; - } else { - // Determine if we are registered in the home service area. - // System ID and Network ID are described in 3GPP2 C.S0005 Sec. 2.6.5.2. - let inHomeArea = false; - for (let i = 0; i < cdmaHome.systemId.length; i++) { - let homeSid = cdmaHome.systemId[i], - homeNid = cdmaHome.networkId[i]; - if (homeSid === 0 || homeNid === 0 // Reserved system id/network id - || homeSid != sid) { - continue; - } - // According to 3GPP2 C.S0005 Sec. 2.6.5.2, NID number 65535 means - // all networks in the system should be considered as home. - if (homeNid == 65535 || homeNid == nid) { - inHomeArea = true; - break; - } - } - iccInfo.isDisplaySpnRequired = inHomeArea; - } - } - } else { - // GSM family display rule. - let operatorMnc = RIL.operator ? RIL.operator.mnc : -1; - let operatorMcc = RIL.operator ? RIL.operator.mcc : -1; - - // First detect if we are on HPLMN or one of the PLMN - // specified by the SIM card. - let isOnMatchingPlmn = false; - - // If the current network is the one defined as mcc/mnc - // in SIM card, it's okay. - if (iccInfo.mcc == operatorMcc && iccInfo.mnc == operatorMnc) { - isOnMatchingPlmn = true; - } - - // Test to see if operator's mcc/mnc match mcc/mnc of PLMN. - if (!isOnMatchingPlmn && iccInfoPriv.SPDI) { - let iccSpdi = iccInfoPriv.SPDI; // PLMN list - for (let plmn in iccSpdi) { - let plmnMcc = iccSpdi[plmn].mcc; - let plmnMnc = iccSpdi[plmn].mnc; - isOnMatchingPlmn = (plmnMcc == operatorMcc) && (plmnMnc == operatorMnc); - if (isOnMatchingPlmn) { - break; - } - } - } - - // See 3GPP TS 22.101 A.4 Service Provider Name indication, and TS 31.102 - // clause 4.2.12 EF_SPN for detail. - if (isOnMatchingPlmn) { - // The first bit of display condition tells us if we should display - // registered PLMN. - if (DEBUG) { - this.context.debug("PLMN is HPLMN or PLMN " + "is in PLMN list"); - } - - // TS 31.102 Sec. 4.2.66 and TS 51.011 Sec. 10.3.50 - // EF_SPDI contains a list of PLMNs in which the Service Provider Name - // shall be displayed. - iccInfo.isDisplaySpnRequired = true; - iccInfo.isDisplayNetworkNameRequired = (displayCondition & 0x01) !== 0; - } else { - // The second bit of display condition tells us if we should display - // registered PLMN. - if (DEBUG) { - this.context.debug("PLMN isn't HPLMN and PLMN isn't in PLMN list"); - } - - iccInfo.isDisplayNetworkNameRequired = true; - iccInfo.isDisplaySpnRequired = (displayCondition & 0x02) === 0; - } - } - - if (DEBUG) { - this.context.debug("isDisplayNetworkNameRequired = " + - iccInfo.isDisplayNetworkNameRequired); - this.context.debug("isDisplaySpnRequired = " + iccInfo.isDisplaySpnRequired); - } - - return ((origIsDisplayNetworkNameRequired !== iccInfo.isDisplayNetworkNameRequired) || - (origIsDisplaySPNRequired !== iccInfo.isDisplaySpnRequired)); - }, - - decodeSimTlvs: function(tlvsLen) { - let GsmPDUHelper = this.context.GsmPDUHelper; - - let index = 0; - let tlvs = []; - while (index < tlvsLen) { - let simTlv = { - tag : GsmPDUHelper.readHexOctet(), - length : GsmPDUHelper.readHexOctet(), - }; - simTlv.value = GsmPDUHelper.readHexOctetArray(simTlv.length); - tlvs.push(simTlv); - index += simTlv.length + 2; // The length of 'tag' and 'length' field. - } - return tlvs; - }, - - /** - * Parse those TLVs and convert it to an object. - */ - parsePbrTlvs: function(pbrTlvs) { - let pbr = {}; - for (let i = 0; i < pbrTlvs.length; i++) { - let pbrTlv = pbrTlvs[i]; - let anrIndex = 0; - for (let j = 0; j < pbrTlv.value.length; j++) { - let tlv = pbrTlv.value[j]; - let tagName = USIM_TAG_NAME[tlv.tag]; - - // ANR could have multiple files. We save it as anr0, anr1,...etc. - if (tlv.tag == ICC_USIM_EFANR_TAG) { - tagName += anrIndex; - anrIndex++; - } - pbr[tagName] = tlv; - pbr[tagName].fileType = pbrTlv.tag; - pbr[tagName].fileId = (tlv.value[0] << 8) | tlv.value[1]; - pbr[tagName].sfi = tlv.value[2]; - - // For Type 2, the order of files is in the same order in IAP. - if (pbrTlv.tag == ICC_USIM_TYPE2_TAG) { - pbr[tagName].indexInIAP = j; - } - } - } - - return pbr; - }, - - /** - * Update the ICC information to RadioInterfaceLayer. - */ - handleICCInfoChange: function() { - let RIL = this.context.RIL; - RIL.iccInfo.rilMessageType = "iccinfochange"; - RIL.sendChromeMessage(RIL.iccInfo); - }, - - /** - * Get whether specificed (U)SIM service is available. - * - * @param geckoService - * Service name like "ADN", "BDN", etc. - * - * @return true if the service is enabled, false otherwise. - */ - isICCServiceAvailable: function(geckoService) { - let RIL = this.context.RIL; - let serviceTable = RIL._isCdma ? RIL.iccInfoPrivate.cst: - RIL.iccInfoPrivate.sst; - let index, bitmask; - if (RIL.appType == CARD_APPTYPE_SIM || RIL.appType == CARD_APPTYPE_RUIM) { - /** - * Service id is valid in 1..N, and 2 bits are used to code each service. - * - * +----+-- --+----+----+ - * | b8 | ... | b2 | b1 | - * +----+-- --+----+----+ - * - * b1 = 0, service not allocated. - * 1, service allocated. - * b2 = 0, service not activated. - * 1, service activated. - * - * @see 3GPP TS 51.011 10.3.7. - */ - let simService; - if (RIL.appType == CARD_APPTYPE_SIM) { - simService = GECKO_ICC_SERVICES.sim[geckoService]; - } else { - simService = GECKO_ICC_SERVICES.ruim[geckoService]; - } - if (!simService) { - return false; - } - simService -= 1; - index = Math.floor(simService / 4); - bitmask = 2 << ((simService % 4) << 1); - } else if (RIL.appType == CARD_APPTYPE_USIM) { - /** - * Service id is valid in 1..N, and 1 bit is used to code each service. - * - * +----+-- --+----+----+ - * | b8 | ... | b2 | b1 | - * +----+-- --+----+----+ - * - * b1 = 0, service not avaiable. - * 1, service available. - * - * @see 3GPP TS 31.102 4.2.8. - */ - let usimService = GECKO_ICC_SERVICES.usim[geckoService]; - if (!usimService) { - return false; - } - usimService -= 1; - index = Math.floor(usimService / 8); - bitmask = 1 << ((usimService % 8) << 0); - } - - return (serviceTable !== null) && - (index < serviceTable.length) && - ((serviceTable[index] & bitmask) !== 0); - }, - - /** - * Get whether specificed CPHS service is available. - * - * @param geckoService - * Service name like "MDN", etc. - * - * @return true if the service is enabled, false otherwise. - */ - isCphsServiceAvailable: function(geckoService) { - let RIL = this.context.RIL; - let serviceTable = RIL.iccInfoPrivate.cphsSt; - - if (!(serviceTable instanceof Uint8Array)) { - return false; - } - - /** - * Service id is valid in 1..N, and 2 bits are used to code each service. - * - * +----+-- --+----+----+ - * | b8 | ... | b2 | b1 | - * +----+-- --+----+----+ - * - * b1 = 0, service not allocated. - * 1, service allocated. - * b2 = 0, service not activated. - * 1, service activated. - * - * @See B.3.1.1 CPHS Information in CPHS Phase 2. - */ - let cphsService = GECKO_ICC_SERVICES.cphs[geckoService]; - - if (!cphsService) { - return false; - } - cphsService -= 1; - let index = Math.floor(cphsService / 4); - let bitmask = 2 << ((cphsService % 4) << 1); - - return (index < serviceTable.length) && - ((serviceTable[index] & bitmask) !== 0); - }, - - /** - * Check if the string is of GSM default 7-bit coded alphabets with bit 8 - * set to 0. - * - * @param str String to be checked. - */ - isGsm8BitAlphabet: function(str) { - if (!str) { - return false; - } - - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - for (let i = 0; i < str.length; i++) { - let c = str.charAt(i); - let octet = langTable.indexOf(c); - if (octet == -1) { - octet = langShiftTable.indexOf(c); - if (octet == -1) { - return false; - } - } - } - - return true; - }, - - /** - * Parse MCC/MNC from IMSI. If there is no available value for the length of - * mnc, it will use the data in MCC table to parse. - * - * @param imsi - * The imsi of icc. - * @param mncLength [optional] - * The length of mnc. - * Zero indicates we haven't got a valid mnc length. - * - * @return An object contains the parsing result of mcc and mnc. - * Or null if any error occurred. - */ - parseMccMncFromImsi: function(imsi, mncLength) { - if (!imsi) { - return null; - } - - // MCC is the first 3 digits of IMSI. - let mcc = imsi.substr(0,3); - if (!mncLength) { - // Check the MCC/MNC table for MNC length = 3 first for the case we don't - // have the 4th byte data from EF_AD. - if (PLMN_HAVING_3DIGITS_MNC[mcc] && - PLMN_HAVING_3DIGITS_MNC[mcc].indexOf(imsi.substr(3, 3)) !== -1) { - mncLength = 3; - } else { - // Check the MCC table to decide the length of MNC. - let index = MCC_TABLE_FOR_MNC_LENGTH_IS_3.indexOf(mcc); - mncLength = (index !== -1) ? 3 : 2; - } - } - let mnc = imsi.substr(3, mncLength); - if (DEBUG) { - this.context.debug("IMSI: " + imsi + " MCC: " + mcc + " MNC: " + mnc); - } - - return { mcc: mcc, mnc: mnc}; - }, -}; - -/** - * Helper for ICC Contacts. - */ -function ICCContactHelperObject(aContext) { - this.context = aContext; -} -ICCContactHelperObject.prototype = { - context: null, - - /** - * Helper function to check DF_PHONEBOOK. - */ - hasDfPhoneBook: function(appType) { - switch (appType) { - case CARD_APPTYPE_SIM: - return false; - case CARD_APPTYPE_USIM: - return true; - case CARD_APPTYPE_RUIM: - let ICCUtilsHelper = this.context.ICCUtilsHelper; - return ICCUtilsHelper.isICCServiceAvailable("ENHANCED_PHONEBOOK"); - default: - return false; - } - }, - - /** - * Helper function to read ICC contacts. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readICCContacts: function(appType, contactType, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - - switch (contactType) { - case GECKO_CARDCONTACT_TYPE_ADN: - if (!this.hasDfPhoneBook(appType)) { - ICCRecordHelper.readADNLike(ICC_EF_ADN, - (ICCUtilsHelper.isICCServiceAvailable("EXT1")) ? ICC_EF_EXT1 : null, - onsuccess, onerror); - } else { - this.readUSimContacts(onsuccess, onerror); - } - break; - case GECKO_CARDCONTACT_TYPE_FDN: - if (!ICCUtilsHelper.isICCServiceAvailable("FDN")) { - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - ICCRecordHelper.readADNLike(ICC_EF_FDN, - (ICCUtilsHelper.isICCServiceAvailable("EXT2")) ? ICC_EF_EXT2 : null, - onsuccess, onerror); - break; - case GECKO_CARDCONTACT_TYPE_SDN: - if (!ICCUtilsHelper.isICCServiceAvailable("SDN")) { - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - - ICCRecordHelper.readADNLike(ICC_EF_SDN, - (ICCUtilsHelper.isICCServiceAvailable("EXT3")) ? ICC_EF_EXT3 : null, - onsuccess, onerror); - break; - default: - if (DEBUG) { - this.context.debug("Unsupported contactType :" + contactType); - } - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - }, - - /** - * Helper function to find free contact record. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - findFreeICCContact: function(appType, contactType, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - switch (contactType) { - case GECKO_CARDCONTACT_TYPE_ADN: - if (!this.hasDfPhoneBook(appType)) { - ICCRecordHelper.findFreeRecordId(ICC_EF_ADN, onsuccess.bind(null, 0), onerror); - } else { - let gotPbrCb = function gotPbrCb(pbrs) { - this.findUSimFreeADNRecordId(pbrs, onsuccess, onerror); - }.bind(this); - - ICCRecordHelper.readPBR(gotPbrCb, onerror); - } - break; - case GECKO_CARDCONTACT_TYPE_FDN: - ICCRecordHelper.findFreeRecordId(ICC_EF_FDN, onsuccess.bind(null, 0), onerror); - break; - default: - if (DEBUG) { - this.context.debug("Unsupported contactType :" + contactType); - } - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - }, - - /** - * Cache the pbr index of the possible free record. - */ - _freePbrIndex: 0, - - /** - * Find free ADN record id in USIM. - * - * @param pbrs All Phonebook Reference Files read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - findUSimFreeADNRecordId: function(pbrs, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - function callback(pbrIndex, recordId) { - // Assume other free records are probably in the same phonebook set. - this._freePbrIndex = pbrIndex; - onsuccess(pbrIndex, recordId); - } - - let nextPbrIndex = -1; - (function findFreeRecordId(pbrIndex) { - if (nextPbrIndex === this._freePbrIndex) { - // No free record found, reset the pbr index of free record. - this._freePbrIndex = 0; - if (DEBUG) { - this.context.debug(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } - onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND); - return; - } - - let pbr = pbrs[pbrIndex]; - nextPbrIndex = (pbrIndex + 1) % pbrs.length; - ICCRecordHelper.findFreeRecordId( - pbr.adn.fileId, - callback.bind(this, pbrIndex), - findFreeRecordId.bind(this, nextPbrIndex)); - }).call(this, this._freePbrIndex); - }, - - /** - * Helper function to add a new ICC contact. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param contact The contact will be added. - * @param pin2 PIN2 is required for FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - addICCContact: function(appType, contactType, contact, pin2, onsuccess, onerror) { - let foundFreeCb = (function foundFreeCb(pbrIndex, recordId) { - contact.pbrIndex = pbrIndex; - contact.recordId = recordId; - this.updateICCContact(appType, contactType, contact, pin2, onsuccess, onerror); - }).bind(this); - - // Find free record first. - this.findFreeICCContact(appType, contactType, foundFreeCb, onerror); - }, - - /** - * Helper function to update ICC contact. - * - * @param appType One of CARD_APPTYPE_*. - * @param contactType One of GECKO_CARDCONTACT_TYPE_*. - * @param contact The contact will be updated. - * @param pin2 PIN2 is required for FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateICCContact: function(appType, contactType, contact, pin2, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let ICCUtilsHelper = this.context.ICCUtilsHelper; - - let updateContactCb = (updatedContact) => { - updatedContact.pbrIndex = contact.pbrIndex; - updatedContact.recordId = contact.recordId; - onsuccess(updatedContact); - } - - switch (contactType) { - case GECKO_CARDCONTACT_TYPE_ADN: - if (!this.hasDfPhoneBook(appType)) { - if (ICCUtilsHelper.isICCServiceAvailable("EXT1")) { - this.updateADNLikeWithExtension(ICC_EF_ADN, ICC_EF_EXT1, - contact, null, - updateContactCb, onerror); - } else { - ICCRecordHelper.updateADNLike(ICC_EF_ADN, 0xff, - contact, null, - updateContactCb, onerror); - } - } else { - this.updateUSimContact(contact, updateContactCb, onerror); - } - break; - case GECKO_CARDCONTACT_TYPE_FDN: - if (!pin2) { - onerror(GECKO_ERROR_SIM_PIN2); - return; - } - if (!ICCUtilsHelper.isICCServiceAvailable("FDN")) { - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - if (ICCUtilsHelper.isICCServiceAvailable("EXT2")) { - this.updateADNLikeWithExtension(ICC_EF_FDN, ICC_EF_EXT2, - contact, pin2, - updateContactCb, onerror); - } else { - ICCRecordHelper.updateADNLike(ICC_EF_FDN, - 0xff, - contact, pin2, - updateContactCb, onerror); - } - break; - default: - if (DEBUG) { - this.context.debug("Unsupported contactType :" + contactType); - } - onerror(CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - break; - } - }, - - /** - * Read contacts from USIM. - * - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readUSimContacts: function(onsuccess, onerror) { - let gotPbrCb = function gotPbrCb(pbrs) { - this.readAllPhonebookSets(pbrs, onsuccess, onerror); - }.bind(this); - - this.context.ICCRecordHelper.readPBR(gotPbrCb, onerror); - }, - - /** - * Read all Phonebook sets. - * - * @param pbrs All Phonebook Reference Files read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readAllPhonebookSets: function(pbrs, onsuccess, onerror) { - let allContacts = [], pbrIndex = 0; - let readPhonebook = function(contacts) { - if (contacts) { - allContacts = allContacts.concat(contacts); - } - - let cLen = contacts ? contacts.length : 0; - for (let i = 0; i < cLen; i++) { - contacts[i].pbrIndex = pbrIndex; - } - - pbrIndex++; - if (pbrIndex >= pbrs.length) { - if (onsuccess) { - onsuccess(allContacts); - } - return; - } - - this.readPhonebookSet(pbrs[pbrIndex], readPhonebook, onerror); - }.bind(this); - - this.readPhonebookSet(pbrs[pbrIndex], readPhonebook, onerror); - }, - - /** - * Read from Phonebook Reference File. - * - * @param pbr Phonebook Reference File to be read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readPhonebookSet: function(pbr, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let gotAdnCb = function gotAdnCb(contacts) { - this.readSupportedPBRFields(pbr, contacts, onsuccess, onerror); - }.bind(this); - - ICCRecordHelper.readADNLike(pbr.adn.fileId, - (pbr.ext1) ? pbr.ext1.fileId : null, gotAdnCb, onerror); - }, - - /** - * Read supported Phonebook fields. - * - * @param pbr Phone Book Reference file. - * @param contacts Contacts stored on ICC. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readSupportedPBRFields: function(pbr, contacts, onsuccess, onerror) { - let fieldIndex = 0; - (function readField() { - let field = USIM_PBR_FIELDS[fieldIndex]; - fieldIndex += 1; - if (!field) { - if (onsuccess) { - onsuccess(contacts); - } - return; - } - - this.readPhonebookField(pbr, contacts, field, readField.bind(this), onerror); - }).call(this); - }, - - /** - * Read Phonebook field. - * - * @param pbr The phonebook reference file. - * @param contacts Contacts stored on ICC. - * @param field Phonebook field to be retrieved. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readPhonebookField: function(pbr, contacts, field, onsuccess, onerror) { - if (!pbr[field]) { - if (onsuccess) { - onsuccess(contacts); - } - return; - } - - (function doReadContactField(n) { - if (n >= contacts.length) { - // All contact's fields are read. - if (onsuccess) { - onsuccess(contacts); - } - return; - } - - // get n-th contact's field. - this.readContactField(pbr, contacts[n], field, - doReadContactField.bind(this, n + 1), onerror); - }).call(this, 0); - }, - - /** - * Read contact's field from USIM. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to get field. - * @param field Phonebook field to be retrieved. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - readContactField: function(pbr, contact, field, onsuccess, onerror) { - let gotRecordIdCb = function gotRecordIdCb(recordId) { - if (recordId == 0xff) { - if (onsuccess) { - onsuccess(); - } - return; - } - - let fileId = pbr[field].fileId; - let fileType = pbr[field].fileType; - let gotFieldCb = function gotFieldCb(value) { - if (value) { - // Move anr0 anr1,.. into anr[]. - if (field.startsWith(USIM_PBR_ANR)) { - if (!contact[USIM_PBR_ANR]) { - contact[USIM_PBR_ANR] = []; - } - contact[USIM_PBR_ANR].push(value); - } else { - contact[field] = value; - } - } - - if (onsuccess) { - onsuccess(); - } - }.bind(this); - - let ICCRecordHelper = this.context.ICCRecordHelper; - // Detect EF to be read, for anr, it could have anr0, anr1,... - let ef = field.startsWith(USIM_PBR_ANR) ? USIM_PBR_ANR : field; - switch (ef) { - case USIM_PBR_EMAIL: - ICCRecordHelper.readEmail(fileId, fileType, recordId, gotFieldCb, onerror); - break; - case USIM_PBR_ANR: - ICCRecordHelper.readANR(fileId, fileType, recordId, gotFieldCb, onerror); - break; - default: - if (DEBUG) { - this.context.debug("Unsupported field :" + field); - } - onerror(CONTACT_ERR_FIELD_NOT_SUPPORTED); - break; - } - }.bind(this); - - this.getContactFieldRecordId(pbr, contact, field, gotRecordIdCb, onerror); - }, - - /** - * Get the recordId. - * - * If the fileType of field is ICC_USIM_TYPE1_TAG, use corresponding ADN recordId. - * otherwise get the recordId from IAP. - * - * @see TS 131.102, clause 4.4.2.2 - * - * @param pbr The phonebook reference file. - * @param contact The contact will be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - getContactFieldRecordId: function(pbr, contact, field, onsuccess, onerror) { - if (pbr[field].fileType == ICC_USIM_TYPE1_TAG) { - // If the file type is ICC_USIM_TYPE1_TAG, use corresponding ADN recordId. - if (onsuccess) { - onsuccess(contact.recordId); - } - } else if (pbr[field].fileType == ICC_USIM_TYPE2_TAG) { - // If the file type is ICC_USIM_TYPE2_TAG, the recordId shall be got from IAP. - let gotIapCb = function gotIapCb(iap) { - let indexInIAP = pbr[field].indexInIAP; - let recordId = iap[indexInIAP]; - - if (onsuccess) { - onsuccess(recordId); - } - }.bind(this); - - this.context.ICCRecordHelper.readIAP(pbr.iap.fileId, contact.recordId, - gotIapCb, onerror); - } else { - if (DEBUG) { - this.context.debug("USIM PBR files in Type 3 format are not supported."); - } - onerror(CONTACT_ERR_REQUEST_NOT_SUPPORTED); - } - }, - - /** - * Update USIM contact. - * - * @param contact The contact will be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateUSimContact: function(contact, onsuccess, onerror) { - let gotPbrCb = function gotPbrCb(pbrs) { - let pbr = pbrs[contact.pbrIndex]; - if (!pbr) { - if (DEBUG) { - this.context.debug(CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); - } - onerror(CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); - return; - } - this.updatePhonebookSet(pbr, contact, onsuccess, onerror); - }.bind(this); - - this.context.ICCRecordHelper.readPBR(gotPbrCb, onerror); - }, - - /** - * Update fields in Phonebook Reference File. - * - * @param pbr Phonebook Reference File to be read. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updatePhonebookSet: function(pbr, contact, onsuccess, onerror) { - let updateAdnCb = function(updatedContact) { - this.updateSupportedPBRFields(pbr, contact, (updatedContactField) => { - onsuccess(Object.assign(updatedContact, updatedContactField)); - }, onerror); - }.bind(this); - - if (pbr.ext1) { - this.updateADNLikeWithExtension(pbr.adn.fileId, pbr.ext1.fileId, - contact, null, updateAdnCb, onerror); - } else { - this.context.ICCRecordHelper.updateADNLike(pbr.adn.fileId, 0xff, contact, - null, updateAdnCb, onerror); - } - }, - - /** - * Update supported Phonebook fields. - * - * @param pbr Phone Book Reference file. - * @param contact Contact to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateSupportedPBRFields: function(pbr, contact, onsuccess, onerror) { - let fieldIndex = 0; - let contactField = {}; - - (function updateField() { - let field = USIM_PBR_FIELDS[fieldIndex]; - fieldIndex += 1; - - if (!field) { - if (onsuccess) { - onsuccess(contactField); - } - return; - } - - // Check if PBR has this field. - if (!pbr[field]) { - updateField.call(this); - return; - } - - this.updateContactField(pbr, contact, field, (fieldEntry) => { - contactField = Object.assign(contactField, fieldEntry); - updateField.call(this); - }, (errorMsg) => { - // Bug 1194149, there are some sim cards without sufficient - // Type 2 USIM contact fields record. We allow user continue - // importing contacts. - if (errorMsg === CONTACT_ERR_NO_FREE_RECORD_FOUND) { - updateField.call(this); - return; - } - onerror(errorMsg); - }); - }).call(this); - }, - - /** - * Update contact's field from USIM. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateContactField: function(pbr, contact, field, onsuccess, onerror) { - if (pbr[field].fileType === ICC_USIM_TYPE1_TAG) { - this.updateContactFieldType1(pbr, contact, field, onsuccess, onerror); - } else if (pbr[field].fileType === ICC_USIM_TYPE2_TAG) { - this.updateContactFieldType2(pbr, contact, field, onsuccess, onerror); - } else { - if (DEBUG) { - this.context.debug("USIM PBR files in Type 3 format are not supported."); - } - onerror(CONTACT_ERR_REQUEST_NOT_SUPPORTED); - } - }, - - /** - * Update Type 1 USIM contact fields. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateContactFieldType1: function(pbr, contact, field, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - if (field === USIM_PBR_EMAIL) { - ICCRecordHelper.updateEmail(pbr, contact.recordId, contact.email, null, - (updatedEmail) => { - onsuccess({email: updatedEmail}); - }, onerror); - } else if (field === USIM_PBR_ANR0) { - let anr = Array.isArray(contact.anr) ? contact.anr[0] : null; - ICCRecordHelper.updateANR(pbr, contact.recordId, anr, null, - (updatedANR) => { - // ANR could have multiple files. If we support more than one anr, - // we will save it as anr0, anr1,...etc. - onsuccess((updatedANR) ? {anr: [updatedANR]} : null); - }, onerror); - } else { - if (DEBUG) { - this.context.debug("Unsupported field :" + field); - } - onerror(CONTACT_ERR_FIELD_NOT_SUPPORTED); - } - }, - - /** - * Update Type 2 USIM contact fields. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateContactFieldType2: function(pbr, contact, field, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - // Case 1 : EF_IAP[adnRecordId] doesn't have a value(0xff) - // Find a free recordId for EF_field - // Update field with that free recordId. - // Update IAP. - // - // Case 2: EF_IAP[adnRecordId] has a value - // update EF_field[iap[field.indexInIAP]] - - let gotIapCb = function gotIapCb(iap) { - let recordId = iap[pbr[field].indexInIAP]; - if (recordId === 0xff) { - // If the value in IAP[index] is 0xff, which means the contact stored on - // the SIM doesn't have the additional attribute (email or anr). - // So if the contact to be updated doesn't have the attribute either, - // we don't have to update it. - if ((field === USIM_PBR_EMAIL && contact.email) || - (field === USIM_PBR_ANR0 && - (Array.isArray(contact.anr) && contact.anr[0]))) { - // Case 1. - this.addContactFieldType2(pbr, contact, field, onsuccess, onerror); - } else { - if (onsuccess) { - onsuccess(); - } - } - return; - } - - // Case 2. - if (field === USIM_PBR_EMAIL) { - ICCRecordHelper.updateEmail(pbr, recordId, contact.email, contact.recordId, - (updatedEmail) => { - onsuccess({email: updatedEmail}); - }, onerror); - } else if (field === USIM_PBR_ANR0) { - let anr = Array.isArray(contact.anr) ? contact.anr[0] : null; - ICCRecordHelper.updateANR(pbr, recordId, anr, contact.recordId, - (updatedANR) => { - // ANR could have multiple files. If we support more than one anr, - // we will save it as anr0, anr1,...etc. - onsuccess((updatedANR) ? {anr: [updatedANR]} : null); - }, onerror); - } else { - if (DEBUG) { - this.context.debug("Unsupported field :" + field); - } - onerror(CONTACT_ERR_FIELD_NOT_SUPPORTED); - } - - }.bind(this); - - ICCRecordHelper.readIAP(pbr.iap.fileId, contact.recordId, gotIapCb, onerror); - }, - - /** - * Add Type 2 USIM contact fields. - * - * @param pbr The phonebook reference file. - * @param contact The contact needs to be updated. - * @param field Phonebook field to be updated. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - addContactFieldType2: function(pbr, contact, field, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let successCb = function successCb(recordId) { - - let updateCb = function updateCb(contactField) { - this.updateContactFieldIndexInIAP(pbr, contact.recordId, field, recordId, () => { - onsuccess(contactField); - }, onerror); - }.bind(this); - - if (field === USIM_PBR_EMAIL) { - ICCRecordHelper.updateEmail(pbr, recordId, contact.email, contact.recordId, - (updatedEmail) => { - updateCb({email: updatedEmail}); - }, onerror); - } else if (field === USIM_PBR_ANR0) { - ICCRecordHelper.updateANR(pbr, recordId, contact.anr[0], contact.recordId, - (updatedANR) => { - // ANR could have multiple files. If we support more than one anr, - // we will save it as anr0, anr1,...etc. - updateCb((updatedANR) ? {anr: [updatedANR]} : null); - }, onerror); - } - }.bind(this); - - let errorCb = function errorCb(errorMsg) { - if (DEBUG) { - this.context.debug(errorMsg + " USIM field " + field); - } - onerror(errorMsg); - }.bind(this); - - ICCRecordHelper.findFreeRecordId(pbr[field].fileId, successCb, errorCb); - }, - - /** - * Update IAP value. - * - * @param pbr The phonebook reference file. - * @param recordNumber The record identifier of EF_IAP. - * @param field Phonebook field. - * @param value The value of 'field' in IAP. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - * - */ - updateContactFieldIndexInIAP: function(pbr, recordNumber, field, value, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - - let gotIAPCb = function gotIAPCb(iap) { - iap[pbr[field].indexInIAP] = value; - ICCRecordHelper.updateIAP(pbr.iap.fileId, recordNumber, iap, onsuccess, onerror); - }.bind(this); - ICCRecordHelper.readIAP(pbr.iap.fileId, recordNumber, gotIAPCb, onerror); - }, - - /** - * Update ICC ADN like EFs with Extension, like EF_ADN, EF_FDN. - * - * @param fileId EF id of the ADN or FDN. - * @param extFileId EF id of the EXT. - * @param contact The contact will be updated. (Shall have recordId property) - * @param pin2 PIN2 is required when updating ICC_EF_FDN. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - updateADNLikeWithExtension: function(fileId, extFileId, contact, pin2, onsuccess, onerror) { - let ICCRecordHelper = this.context.ICCRecordHelper; - let extNumber; - - if (contact.number) { - let numStart = contact.number[0] == "+" ? 1 : 0; - let number = contact.number.substring(0, numStart) + - this.context.GsmPDUHelper.stringToExtendedBcd( - contact.number.substring(numStart)); - extNumber = number.substr(numStart + ADN_MAX_NUMBER_DIGITS, - EXT_MAX_NUMBER_DIGITS); - } - - ICCRecordHelper.getADNLikeExtensionRecordNumber(fileId, contact.recordId, - (extRecordNumber) => { - let updateADNLike = (extRecordNumber) => { - ICCRecordHelper.updateADNLike(fileId, extRecordNumber, contact, - pin2, (updatedContact) => { - if (extNumber && extRecordNumber != 0xff) { - updatedContact.number = updatedContact.number.concat(extNumber); - } - onsuccess(updatedContact); - }, onerror); - }; - - let updateExtension = (extRecordNumber) => { - ICCRecordHelper.updateExtension(extFileId, extRecordNumber, extNumber, - () => updateADNLike(extRecordNumber), - () => updateADNLike(0xff)); - }; - - if (extNumber) { - if (extRecordNumber != 0xff) { - updateExtension(extRecordNumber); - return; - } - - ICCRecordHelper.findFreeRecordId(extFileId, - (extRecordNumber) => updateExtension(extRecordNumber), - (errorMsg) => { - if (DEBUG) { - this.context.debug("Couldn't find free extension record Id for " + extFileId + ": " + errorMsg); - } - updateADNLike(0xff); - }); - return; - } - - if (extRecordNumber != 0xff) { - ICCRecordHelper.cleanEFRecord(extFileId, extRecordNumber, - () => updateADNLike(0xff), onerror); - return; - } - - updateADNLike(0xff); - }, onerror); - }, -}; - -function IconLoaderObject(aContext) { - this.context = aContext; -} -IconLoaderObject.prototype = { - context: null, - - /** - * Load icons. - * - * @param recordNumbers Array of the record identifiers of EF_IMG. - * @param onsuccess Callback to be called when success. - * @param onerror Callback to be called when error. - */ - loadIcons: function(recordNumbers, onsuccess, onerror) { - if (!recordNumbers || !recordNumbers.length) { - if (onerror) { - onerror(); - } - return; - } - - this._start({ - recordNumbers: recordNumbers, - onsuccess: onsuccess, - onerror: onerror}); - }, - - _start: function(options) { - let callback = (function(icons) { - if (!options.icons) { - options.icons = []; - } - for (let i = 0; i < icons.length; i++) { - icons[i] = this._parseRawData(icons[i]); - } - options.icons[options.currentRecordIndex] = icons; - options.currentRecordIndex++; - - let recordNumbers = options.recordNumbers; - if (options.currentRecordIndex < recordNumbers.length) { - let recordNumber = recordNumbers[options.currentRecordIndex]; - this.context.SimRecordHelper.readIMG(recordNumber, - callback, - options.onerror); - } else { - if (options.onsuccess) { - options.onsuccess(options.icons); - } - } - }).bind(this); - - options.currentRecordIndex = 0; - this.context.SimRecordHelper.readIMG(options.recordNumbers[0], - callback, - options.onerror); - }, - - _parseRawData: function(rawData) { - let codingScheme = rawData.codingScheme; - - switch (codingScheme) { - case ICC_IMG_CODING_SCHEME_BASIC: - return this._decodeBasicImage(rawData.width, rawData.height, rawData.body); - - case ICC_IMG_CODING_SCHEME_COLOR: - case ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY: - return this._decodeColorImage(codingScheme, - rawData.width, rawData.height, - rawData.bitsPerImgPoint, - rawData.numOfClutEntries, - rawData.clut, rawData.body); - } - - return null; - }, - - _decodeBasicImage: function(width, height, body) { - let numOfPixels = width * height; - let pixelIndex = 0; - let currentByteIndex = 0; - let currentByte = 0x00; - - const BLACK = 0x000000FF; - const WHITE = 0xFFFFFFFF; - - let pixels = []; - while (pixelIndex < numOfPixels) { - // Reassign data and index for every byte (8 bits). - if (pixelIndex % 8 == 0) { - currentByte = body[currentByteIndex++]; - } - let bit = (currentByte >> (7 - (pixelIndex % 8))) & 0x01; - pixels[pixelIndex++] = bit ? WHITE : BLACK; - } - - return {pixels: pixels, - codingScheme: GECKO_IMG_CODING_SCHEME_BASIC, - width: width, - height: height}; - }, - - _decodeColorImage: function(codingScheme, width, height, bitsPerImgPoint, - numOfClutEntries, clut, body) { - let mask = 0xff >> (8 - bitsPerImgPoint); - let bitsStartOffset = 8 - bitsPerImgPoint; - let bitIndex = bitsStartOffset; - let numOfPixels = width * height; - let pixelIndex = 0; - let currentByteIndex = 0; - let currentByte = body[currentByteIndex++]; - - let pixels = []; - while (pixelIndex < numOfPixels) { - // Reassign data and index for every byte (8 bits). - if (bitIndex < 0) { - currentByte = body[currentByteIndex++]; - bitIndex = bitsStartOffset; - } - let clutEntry = ((currentByte >> bitIndex) & mask); - let clutIndex = clutEntry * ICC_CLUT_ENTRY_SIZE; - let alpha = codingScheme == ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY && - clutEntry == numOfClutEntries - 1; - pixels[pixelIndex++] = alpha ? 0x00 - : (clut[clutIndex] << 24 | - clut[clutIndex + 1] << 16 | - clut[clutIndex + 2] << 8 | - 0xFF) >>> 0; - bitIndex -= bitsPerImgPoint; - } - - return {pixels: pixels, - codingScheme: ICC_IMG_CODING_SCHEME_TO_GECKO[codingScheme], - width: width, - height: height}; - }, -}; - -/** - * Global stuff. - */ - -function Context(aClientId) { - this.clientId = aClientId; - - this.Buf = new BufObject(this); - this.RIL = new RilObject(this); - this.RIL.initRILState(); -} -Context.prototype = { - clientId: null, - Buf: null, - RIL: null, - - debug: function(aMessage) { - GLOBAL.debug("[" + this.clientId + "] " + aMessage); - } -}; - -(function() { - let lazySymbols = [ - "BerTlvHelper", "BitBufferHelper", "CdmaPDUHelper", - "ComprehensionTlvHelper", "GsmPDUHelper", "ICCContactHelper", - "ICCFileHelper", "ICCIOHelper", "ICCPDUHelper", "ICCRecordHelper", - "ICCUtilsHelper", "RuimRecordHelper", "SimRecordHelper", - "StkCommandParamsFactory", "StkProactiveCmdHelper", "IconLoader", - ]; - - for (let i = 0; i < lazySymbols.length; i++) { - let symbol = lazySymbols[i]; - Object.defineProperty(Context.prototype, symbol, { - get: function() { - let real = new GLOBAL[symbol + "Object"](this); - Object.defineProperty(this, symbol, { - value: real, - enumerable: true - }); - return real; - }, - configurable: true, - enumerable: true - }); - } -})(); - -var ContextPool = { - _contexts: [], - - handleRilMessage: function(aClientId, aUint8Array) { - let context = this._contexts[aClientId]; - context.Buf.processIncoming(aUint8Array); - }, - - handleChromeMessage: function(aMessage) { - let clientId = aMessage.rilMessageClientId; - if (clientId != null) { - let context = this._contexts[clientId]; - context.RIL.handleChromeMessage(aMessage); - return; - } - - if (DEBUG) debug("Received global chrome message " + JSON.stringify(aMessage)); - let method = this[aMessage.rilMessageType]; - if (typeof method != "function") { - if (DEBUG) { - debug("Don't know what to do"); - } - return; - } - method.call(this, aMessage); - }, - - setInitialOptions: function(aOptions) { - DEBUG = DEBUG_WORKER || aOptions.debug; - - let quirks = aOptions.quirks; - RILQUIRKS_CALLSTATE_EXTRA_UINT32 = quirks.callstateExtraUint32; - RILQUIRKS_REQUEST_USE_DIAL_EMERGENCY_CALL = quirks.requestUseDialEmergencyCall; - RILQUIRKS_SIM_APP_STATE_EXTRA_FIELDS = quirks.simAppStateExtraFields; - RILQUIRKS_EXTRA_UINT32_2ND_CALL = quirks.extraUint2ndCall; - RILQUIRKS_HAVE_QUERY_ICC_LOCK_RETRY_COUNT = quirks.haveQueryIccLockRetryCount; - RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = quirks.sendStkProfileDownload; - RILQUIRKS_DATA_REGISTRATION_ON_DEMAND = quirks.dataRegistrationOnDemand; - RILQUIRKS_SUBSCRIPTION_CONTROL = quirks.subscriptionControl; - RILQUIRKS_SIGNAL_EXTRA_INT32 = quirks.signalExtraInt; - RILQUIRKS_AVAILABLE_NETWORKS_EXTRA_STRING = quirks.availableNetworkExtraStr; - RILQUIRKS_SMSC_ADDRESS_FORMAT = quirks.smscAddressFormat; - }, - - setDebugFlag: function(aOptions) { - DEBUG = DEBUG_WORKER || aOptions.debug; - }, - - registerClient: function(aOptions) { - let clientId = aOptions.clientId; - this._contexts[clientId] = new Context(clientId); - }, -}; - -function onRILMessage(aClientId, aUint8Array) { - ContextPool.handleRilMessage(aClientId, aUint8Array); -} - -onmessage = function onmessage(event) { - ContextPool.handleChromeMessage(event.data); -}; - -onerror = function onerror(event) { - if (DEBUG) debug("onerror" + event.message + "\n"); -}; diff --git a/dom/system/gonk/ril_worker_buf_object.js b/dom/system/gonk/ril_worker_buf_object.js deleted file mode 100644 index 70018c5b2..000000000 --- a/dom/system/gonk/ril_worker_buf_object.js +++ /dev/null @@ -1,168 +0,0 @@ -/* global require */ -/* global DEBUG, DEBUG_WORKER */ -/* global RESPONSE_TYPE_SOLICITED */ -/* global RESPONSE_TYPE_UNSOLICITED */ - -"use strict"; - -/** - * This is a specialized worker buffer for the Parcel protocol. - * - * NOTE: To prevent including/importing twice, this file should be included - * in a file which already includes 'ril_consts.js' and 'require.js'. - */ -(function(exports) { - - // Set to true in ril_consts.js to see debug messages - let DEBUG = DEBUG_WORKER; - // Need to inherit it. - let Buf = require("resource://gre/modules/workers/worker_buf.js").Buf; - - let BufObject = function(aContext) { - this.context = aContext; - // This gets incremented each time we send out a parcel. - this.mToken = 1; - // Maps tokens we send out with requests to the request type, so that - // when we get a response parcel back, we know what request it was for. - this.mTokenRequestMap = new Map(); - // This is because the underlying 'Buf' is still using the 'init' pattern, so - // this derived one needs to invoke it. - // Using 'apply' style to mark it's a parent method calling explicitly. - Buf._init.apply(this); - - // Remapping the request type to different values based on RIL version. - // We only have to do this for SUBSCRIPTION right now, so I just make it - // simple. A generic logic or structure could be discussed if we have more - // use cases, especially the cases from different partners. - this._requestMap = {}; - // RIL version 8. - // For the CAF's proprietary parcels. Please see - // https://www.codeaurora.org/cgit/quic/la/platform/hardware/ril/tree/include/telephony/ril.h?h=b2g_jb_3.2 - let map = {}; - map[REQUEST_SET_UICC_SUBSCRIPTION] = 114; - map[REQUEST_SET_DATA_SUBSCRIPTION] = 115; - this._requestMap[8] = map; - // RIL version 9. - // For the CAF's proprietary parcels. Please see - // https://www.codeaurora.org/cgit/quic/la/platform/hardware/ril/tree/include/telephony/ril.h?h=b2g_kk_3.5 - map = {}; - map[REQUEST_SET_UICC_SUBSCRIPTION] = 115; - map[REQUEST_SET_DATA_SUBSCRIPTION] = 116; - this._requestMap[9] = map; - }; - - /** - * "inherit" the basic worker buffer. - */ - BufObject.prototype = Object.create(Buf); - - /** - * Process one parcel. - */ - BufObject.prototype.processParcel = function() { - let responseType = this.readInt32(); - - let requestType, options; - if (responseType == RESPONSE_TYPE_SOLICITED) { - let token = this.readInt32(); - let error = this.readInt32(); - - options = this.mTokenRequestMap.get(token); - if (!options) { - if (DEBUG) { - this.context.debug("Suspicious uninvited request found: " + - token + ". Ignored!"); - } - return; - } - - this.mTokenRequestMap.delete(token); - requestType = options.rilRequestType; - - if (error !== ERROR_SUCCESS) { - options.errorMsg = RIL_ERROR_TO_GECKO_ERROR[error] || - GECKO_ERROR_UNSPECIFIED_ERROR; - } - if (DEBUG) { - this.context.debug("Solicited response for request type " + requestType + - ", token " + token + ", error " + error); - } - } else if (responseType == RESPONSE_TYPE_UNSOLICITED) { - requestType = this.readInt32(); - if (DEBUG) { - this.context.debug("Unsolicited response for request type " + requestType); - } - } else { - if (DEBUG) { - this.context.debug("Unknown response type: " + responseType); - } - return; - } - - this.context.RIL.handleParcel(requestType, this.readAvailable, options); - }; - - /** - * Start a new outgoing parcel. - * - * @param type - * Integer specifying the request type. - * @param options [optional] - * Object containing information about the request, e.g. the - * original main thread message object that led to the RIL request. - */ - BufObject.prototype.newParcel = function(type, options) { - if (DEBUG) { - this.context.debug("New outgoing parcel of type " + type); - } - - // We're going to leave room for the parcel size at the beginning. - this.outgoingIndex = this.PARCEL_SIZE_SIZE; - this.writeInt32(this._reMapRequestType(type)); - this.writeInt32(this.mToken); - - if (!options) { - options = {}; - } - options.rilRequestType = type; - this.mTokenRequestMap.set(this.mToken, options); - this.mToken++; - return this.mToken; - }; - - BufObject.prototype.simpleRequest = function(type, options) { - this.newParcel(type, options); - this.sendParcel(); - }; - - BufObject.prototype.onSendParcel = function(parcel) { - self.postRILMessage(this.context.clientId, parcel); - }; - - /** - * Remapping the request type to different values based on RIL version. - * We only have to do this for SUBSCRIPTION right now, so I just make it - * simple. A generic logic or structure could be discussed if we have more - * use cases, especially the cases from different partners. - */ - BufObject.prototype._reMapRequestType = function(type) { - for (let version in this._requestMap) { - if (this.context.RIL.version <= version) { - let newType = this._requestMap[version][type]; - if (newType) { - if (DEBUG) { - this.context.debug("Remap request type to " + newType); - } - return newType; - } - } - } - return type; - }; - - // Before we make sure to form it as a module would not add extra - // overhead of module loading, we need to define it in this way - // rather than 'module.exports' it as a module component. - exports.BufObject = BufObject; -})(self); // in worker self is the global - diff --git a/dom/system/gonk/ril_worker_telephony_request_queue.js b/dom/system/gonk/ril_worker_telephony_request_queue.js deleted file mode 100644 index 4dba7a42f..000000000 --- a/dom/system/gonk/ril_worker_telephony_request_queue.js +++ /dev/null @@ -1,157 +0,0 @@ -/* global DEBUG, DEBUG_WORKER */ -/* global REQUEST_GET_CURRENT_CALLS */ -/* global REQUEST_ANSWER, REQUEST_CONFERENCE, REQUEST_DIAL */ -/* global REQUEST_DIAL_EMERGENCY_CALL, REQUEST_HANGUP */ -/* global REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND */ -/* global REQUEST_HANGUP_WAITING_OR_BACKGROUND */ -/* global REQUEST_SEPARATE_CONNECTION */ -/* global REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, REQUEST_UDUB */ - -"use strict"; - -(function(exports) { - - const TELEPHONY_REQUESTS = [ - REQUEST_GET_CURRENT_CALLS, - REQUEST_ANSWER, - REQUEST_CONFERENCE, - REQUEST_DIAL, - REQUEST_DIAL_EMERGENCY_CALL, - REQUEST_HANGUP, - REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND, - REQUEST_HANGUP_WAITING_OR_BACKGROUND, - REQUEST_SEPARATE_CONNECTION, - REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE, - REQUEST_UDUB - ]; - - // Set to true in ril_consts.js to see debug messages - let DEBUG = DEBUG_WORKER; - - /** - * Queue entry; only used in the queue. - */ - let TelephonyRequestEntry = function(request, callback) { - this.request = request; - this.callback = callback; - }; - - let TelephonyRequestQueue = function(ril) { - this.ril = ril; - this.currentQueue = null; // Point to the current running queue. - - this.queryQueue = []; - this.controlQueue = []; - }; - - TelephonyRequestQueue.prototype._getQueue = function(request) { - return (request === REQUEST_GET_CURRENT_CALLS) ? this.queryQueue - : this.controlQueue; - }; - - TelephonyRequestQueue.prototype._getAnotherQueue = function(queue) { - return (this.queryQueue === queue) ? this.controlQueue : this.queryQueue; - }; - - TelephonyRequestQueue.prototype._find = function(queue, request) { - for (let i = 0; i < queue.length; ++i) { - if (queue[i].request === request) { - return i; - } - } - return -1; - }; - - TelephonyRequestQueue.prototype._startQueue = function(queue) { - if (queue.length === 0) { - return; - } - - // We only need to keep one entry for queryQueue. - if (queue === this.queryQueue) { - queue.splice(1, queue.length - 1); - } - - this.currentQueue = queue; - for (let entry of queue) { - this._executeEntry(entry); - } - }; - - TelephonyRequestQueue.prototype._executeEntry = function(entry) { - if (DEBUG) { - this.debug("execute " + this._getRequestName(entry.request)); - } - entry.callback(); - }; - - TelephonyRequestQueue.prototype._getRequestName = function(request) { - let method = this.ril[request]; - return (typeof method === 'function') ? method.name : ""; - }; - - TelephonyRequestQueue.prototype.debug = function(msg) { - this.ril.context.debug("[TeleQ] " + msg); - }; - - TelephonyRequestQueue.prototype.isValidRequest = function(request) { - return TELEPHONY_REQUESTS.indexOf(request) !== -1; - }; - - TelephonyRequestQueue.prototype.push = function(request, callback) { - if (!this.isValidRequest(request)) { - if (DEBUG) { - this.debug("Error: " + this._getRequestName(request) + - " is not a telephony request"); - } - return; - } - - if (DEBUG) { - this.debug("push " + this._getRequestName(request)); - } - let entry = new TelephonyRequestEntry(request, callback); - let queue = this._getQueue(request); - queue.push(entry); - - // Try to run the request. - if (this.currentQueue === queue) { - this._executeEntry(entry); - } else if (!this.currentQueue) { - this._startQueue(queue); - } - }; - - TelephonyRequestQueue.prototype.pop = function(request) { - if (!this.isValidRequest(request)) { - if (DEBUG) { - this.debug("Error: " + this._getRequestName(request) + - " is not a telephony request"); - } - return; - } - - if (DEBUG) { - this.debug("pop " + this._getRequestName(request)); - } - let queue = this._getQueue(request); - let index = this._find(queue, request); - if (index === -1) { - throw new Error("Cannot find the request in telephonyRequestQueue."); - } else { - queue.splice(index, 1); - } - - if (queue.length === 0) { - this.currentQueue = null; - this._startQueue(this._getAnotherQueue(queue)); - } - }; - - - // Before we make sure to form it as a module would not add extra - // overhead of module loading, we need to define it in this way - // rather than 'module.exports' it as a module component. - exports.TelephonyRequestQueue = TelephonyRequestQueue; -})(self); // in worker self is the global - diff --git a/dom/system/gonk/systemlibs.js b/dom/system/gonk/systemlibs.js deleted file mode 100644 index a27b30e20..000000000 --- a/dom/system/gonk/systemlibs.js +++ /dev/null @@ -1,201 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -if (!this.ctypes) { - // We're likely being loaded as a JSM. - this.EXPORTED_SYMBOLS = [ "libcutils", "netHelpers" ]; - Components.utils.import("resource://gre/modules/ctypes.jsm"); -} - -const SYSTEM_PROPERTY_KEY_MAX = 32; -const SYSTEM_PROPERTY_VALUE_MAX = 92; - -// We leave this as 'undefined' instead of setting it to 'false'. That -// way a file that includes us can have it defined already without us -// overriding the value here. -var DEBUG; - -/** - * Expose some system-level functions. - */ -this.libcutils = (function() { - let lib; - try { - lib = ctypes.open("libcutils.so"); - } catch(ex) { - // Return a fallback option in case libcutils.so isn't present (e.g. - // when building Firefox with MOZ_B2G_RIL. - if (DEBUG) { - dump("Could not load libcutils.so. Using fake propdb.\n"); - } - let fake_propdb = Object.create(null); - return { - property_get: function(key, defaultValue) { - if (key in fake_propdb) { - return fake_propdb[key]; - } - return defaultValue === undefined ? null : defaultValue; - }, - property_set: function(key, value) { - fake_propdb[key] = value; - } - }; - } - - let c_property_get = lib.declare("property_get", ctypes.default_abi, - ctypes.int, // return value: length - ctypes.char.ptr, // key - ctypes.char.ptr, // value - ctypes.char.ptr); // default - let c_property_set = lib.declare("property_set", ctypes.default_abi, - ctypes.int, // return value: success - ctypes.char.ptr, // key - ctypes.char.ptr); // value - let c_value_buf = ctypes.char.array(SYSTEM_PROPERTY_VALUE_MAX)(); - - return { - - /** - * Get a system property. - * - * @param key - * Name of the property - * @param defaultValue [optional] - * Default value to return if the property isn't set (default: null) - */ - property_get: function(key, defaultValue) { - if (defaultValue === undefined) { - defaultValue = null; - } - c_property_get(key, c_value_buf, defaultValue); - return c_value_buf.readString(); - }, - - /** - * Set a system property - * - * @param key - * Name of the property - * @param value - * Value to set the property to. - */ - property_set: function(key, value) { - let rv = c_property_set(key, value); - if (rv) { - throw Error('libcutils.property_set("' + key + '", "' + value + - '") failed with error ' + rv); - } - } - - }; -})(); - -/** - * Helpers for conversions. - */ -this.netHelpers = { - - /** - * Swap byte orders for 32-bit value - */ - swap32: function(n) { - return (((n >> 24) & 0xFF) << 0) | - (((n >> 16) & 0xFF) << 8) | - (((n >> 8) & 0xFF) << 16) | - (((n >> 0) & 0xFF) << 24); - }, - - /** - * Convert network byte order to host byte order - * Note: Assume that the system is little endian - */ - ntohl: function(n) { - return this.swap32(n); - }, - - /** - * Convert host byte order to network byte order - * Note: Assume that the system is little endian - */ - htonl: function(n) { - return this.swap32(n); - }, - - /** - * Convert integer representation of an IP address to the string - * representation. - * - * @param ip - * IP address in number format. - */ - ipToString: function(ip) { - return ((ip >> 0) & 0xFF) + "." + - ((ip >> 8) & 0xFF) + "." + - ((ip >> 16) & 0xFF) + "." + - ((ip >> 24) & 0xFF); - }, - - /** - * Convert string representation of an IP address to the integer - * representation (network byte order). - * - * @param string - * String containing the IP address. - */ - stringToIP: function(string) { - if (!string) { - return null; - } - let ip = 0; - let start, end = -1; - for (let i = 0; i < 4; i++) { - start = end + 1; - end = string.indexOf(".", start); - if (end == -1) { - end = string.length; - } - let num = parseInt(string.slice(start, end), 10); - if (isNaN(num)) { - return null; - } - ip |= num << (i * 8); - } - return ip; - }, - - /** - * Make a subnet mask. - */ - makeMask: function(len) { - let mask = 0; - for (let i = 0; i < len; ++i) { - mask |= (0x80000000 >> i); - } - return this.ntohl(mask); - }, - - /** - * Get Mask length from given mask address - */ - getMaskLength: function(mask) { - let len = 0; - let netmask = this.ntohl(mask); - while (netmask & 0x80000000) { - len++; - netmask = netmask << 1; - } - return len; - } -}; diff --git a/dom/system/gonk/tests/header_helpers.js b/dom/system/gonk/tests/header_helpers.js deleted file mode 100644 index 8d1144f75..000000000 --- a/dom/system/gonk/tests/header_helpers.js +++ /dev/null @@ -1,217 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -"use strict"; - -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - - -var subscriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"] - .getService(Ci.mozIJSSubScriptLoader); - -/** - * Start a new RIL worker. - * - * @param custom_ns - * Namespace with symbols to be injected into the new worker - * namespace. - * - * @return an object that represents the worker's namespace. - * - * @note that this does not start an actual worker thread. The worker - * is executed on the main thread, within a separate namespace object. - */ -function newWorker(custom_ns) { - let worker_ns = { - importScripts: function() { - Array.slice(arguments).forEach(function(script) { - if (!script.startsWith("resource:")) { - script = "resource://gre/modules/" + script; - } - subscriptLoader.loadSubScript(script, this); - }, this); - }, - - postRILMessage: function(message) { - }, - - postMessage: function(message) { - }, - - // Define these variables inside the worker scope so ES5 strict mode - // doesn't flip out. - onmessage: undefined, - onerror: undefined, - - DEBUG: true - }; - // The 'self' variable in a worker points to the worker's own namespace. - worker_ns.self = worker_ns; - - // Copy the custom definitions over. - for (let key in custom_ns) { - worker_ns[key] = custom_ns[key]; - } - - // fake require() for toolkit/components/workerloader/require.js - let require = (function() { - return function require(script) { - worker_ns.module = {}; - worker_ns.importScripts(script); - return worker_ns; - } - })(); - - Object.freeze(require); - Object.defineProperty(worker_ns, "require", { - value: require, - enumerable: true, - configurable: false - }); - - // Load the RIL worker itself. - worker_ns.importScripts("ril_worker.js"); - - // Register at least one client. - worker_ns.ContextPool.registerClient({ clientId: 0 }); - - return worker_ns; -} - -/** - * Create a buffered RIL worker. - * - * @return A worker object that stores sending octets in a internal buffer. - */ -function newUint8Worker() { - let worker = newWorker(); - let index = 0; // index for read - let buf = []; - - let context = worker.ContextPool._contexts[0]; - context.Buf.writeUint8 = function(value) { - buf.push(value); - }; - - context.Buf.readUint8 = function() { - return buf[index++]; - }; - - context.Buf.seekIncoming = function(offset) { - index += offset; - }; - - context.Buf.getReadAvailable = function() { - return buf.length - index; - }; - - worker.debug = do_print; - - return worker; -} - -/** - * Create a worker that keeps posted chrome message. - */ -function newInterceptWorker() { - let postedMessage; - let worker = newWorker({ - postRILMessage: function(data) { - }, - postMessage: function(message) { - postedMessage = message; - } - }); - return { - get postedMessage() { - return postedMessage; - }, - get worker() { - return worker; - } - }; -} - -/** - * Create a parcel suitable for postRILMessage(). - * - * @param fakeParcelSize - * Value to be written to parcel size field for testing - * incorrect/incomplete parcel reading. Replaced with correct - * one determined length of data if negative. - * @param response - * Response code of the incoming parcel. - * @param request - * Request code of the incoming parcel. - * @param data - * Extra data to be appended. - * - * @return an Uint8Array carrying all parcel data. - */ -function newIncomingParcel(fakeParcelSize, response, request, data) { - const UINT32_SIZE = 4; - const PARCEL_SIZE_SIZE = 4; - - let realParcelSize = data.length + 2 * UINT32_SIZE; - let buffer = new ArrayBuffer(realParcelSize + PARCEL_SIZE_SIZE); - let bytes = new Uint8Array(buffer); - - let writeIndex = 0; - function writeUint8(value) { - bytes[writeIndex] = value; - ++writeIndex; - } - - function writeInt32(value) { - writeUint8(value & 0xff); - writeUint8((value >> 8) & 0xff); - writeUint8((value >> 16) & 0xff); - writeUint8((value >> 24) & 0xff); - } - - function writeParcelSize(value) { - writeUint8((value >> 24) & 0xff); - writeUint8((value >> 16) & 0xff); - writeUint8((value >> 8) & 0xff); - writeUint8(value & 0xff); - } - - if (fakeParcelSize < 0) { - fakeParcelSize = realParcelSize; - } - writeParcelSize(fakeParcelSize); - - writeInt32(response); - writeInt32(request); - - // write parcel data - for (let ii = 0; ii < data.length; ++ii) { - writeUint8(data[ii]); - } - - return bytes; -} - -/** - * Create a parcel buffer which represents the hex string. - * - * @param hexString - * The HEX string to be converted. - * - * @return an Uint8Array carrying all parcel data. - */ -function hexStringToParcelByteArrayData(hexString) { - let length = Math.ceil((hexString.length / 2)); - let bytes = new Uint8Array(4 + length); - - bytes[0] = length & 0xFF; - bytes[1] = (length >> 8) & 0xFF; - bytes[2] = (length >> 16) & 0xFF; - bytes[3] = (length >> 24) & 0xFF; - - for (let i = 0; i < length; i ++) { - bytes[i + 4] = Number.parseInt(hexString.substr(i * 2, 2), 16); - } - - return bytes; -} diff --git a/dom/system/gonk/tests/marionette/head.js b/dom/system/gonk/tests/marionette/head.js deleted file mode 100644 index 5a6ee1272..000000000 --- a/dom/system/gonk/tests/marionette/head.js +++ /dev/null @@ -1,345 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_CONTEXT = "chrome"; - -const SETTINGS_KEY_DATA_ENABLED = "ril.data.enabled"; -const SETTINGS_KEY_DATA_APN_SETTINGS = "ril.data.apnSettings"; -const SETTINGS_KEY_WIFI_ENABLED = "wifi.enabled"; - -const TOPIC_CONNECTION_STATE_CHANGED = "network-connection-state-changed"; -const TOPIC_NETWORK_ACTIVE_CHANGED = "network-active-changed"; - -const NETWORK_STATE_UNKNOWN = Ci.nsINetworkInfo.NETWORK_STATE_UNKNOWN; -const NETWORK_STATE_CONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTING; -const NETWORK_STATE_CONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED; -const NETWORK_STATE_DISCONNECTING = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTING; -const NETWORK_STATE_DISCONNECTED = Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED; - -const NETWORK_TYPE_MOBILE = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE; -const NETWORK_TYPE_MOBILE_MMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_MMS; -const NETWORK_TYPE_MOBILE_SUPL = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_SUPL; -const NETWORK_TYPE_MOBILE_IMS = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_IMS; -const NETWORK_TYPE_MOBILE_DUN = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_DUN; -const NETWORK_TYPE_MOBILE_FOTA = Ci.nsINetworkInfo.NETWORK_TYPE_MOBILE_FOTA; - -const networkTypes = [ - NETWORK_TYPE_MOBILE, - NETWORK_TYPE_MOBILE_MMS, - NETWORK_TYPE_MOBILE_SUPL, - NETWORK_TYPE_MOBILE_IMS, - NETWORK_TYPE_MOBILE_DUN, - NETWORK_TYPE_MOBILE_FOTA -]; - -var Promise = Cu.import("resource://gre/modules/Promise.jsm").Promise; - -var ril = Cc["@mozilla.org/ril;1"].getService(Ci.nsIRadioInterfaceLayer); -ok(ril, "ril.constructor is " + ril.constructor); - -var radioInterface = ril.getRadioInterface(0); -ok(radioInterface, "radioInterface.constructor is " + radioInterface.constrctor); - -var _pendingEmulatorShellCmdCount = 0; -var _pendingEmulatorCmdCount = 0; - -/** - * Send emulator shell command with safe guard. - * - * We should only call |finish()| after all emulator shell command transactions - * end, so here comes with the pending counter. Resolve when the emulator - * shell gives response. Never reject. - * - * Fulfill params: - * result -- an array of emulator shell response lines. - * - * @param aCommands - * A string array commands to be passed to emulator through adb shell. - * - * @return A deferred promise. - */ -function runEmulatorShellCmdSafe(aCommands) { - return new Promise(function(aResolve, aReject) { - ++_pendingEmulatorShellCmdCount; - runEmulatorShell(aCommands, function(aResult) { - --_pendingEmulatorShellCmdCount; - - log("Emulator shell response: " + JSON.stringify(aResult)); - aResolve(aResult); - }); - }); -} - -/** - * Send emulator command with safe guard. - * - * We should only call |finish()| after all emulator command transactions - * end, so here comes with the pending counter. Resolve when the emulator - * gives positive response, and reject otherwise. - * - * Fulfill params: - * result -- an array of emulator response lines. - * Reject params: - * result -- an array of emulator response lines. - * - * @param aCommand - * A string command to be passed to emulator through its telnet console. - * - * @return A deferred promise. - */ -function runEmulatorCmdSafe(aCommand) { - log(aCommand); - return new Promise(function(aResolve, aReject) { - ++_pendingEmulatorCmdCount; - runEmulatorCmd(aCommand, function(aResult) { - --_pendingEmulatorCmdCount; - - log("Emulator console response: " + JSON.stringify(aResult)); - if (Array.isArray(aResult) && - aResult[aResult.length - 1] === "OK") { - aResolve(aResult); - } else { - aReject(aResult); - } - }); - }); -} - -/** - * Get mozSettings value specified by @aKey. - * - * Resolve if that mozSettings value is retrieved successfully, reject - * otherwise. - * - * Fulfill params: The corresponding mozSettings value of the key. - * Reject params: (none) - * - * @param aKey - * A string. - * @param aAllowError [optional] - * A boolean value. If set to true, an error response won't be treated - * as test failure. Default: false. - * - * @return A deferred promise. - */ -function getSettings(aKey, aAllowError) { - let request = window.navigator.mozSettings.createLock().get(aKey); - return request.then(function resolve(aValue) { - log("getSettings(" + aKey + ") - success"); - return aValue[aKey]; - }, function reject(aError) { - ok(aAllowError, "getSettings(" + aKey + ") - error"); - }); -} - -/** - * Set mozSettings values. - * - * Resolve if that mozSettings value is set successfully, reject otherwise. - * - * Fulfill params: (none) - * Reject params: (none) - * - * @param aKey - * A string key. - * @param aValue - * An object value. - * @param aAllowError [optional] - * A boolean value. If set to true, an error response won't be treated - * as test failure. Default: false. - * - * @return A deferred promise. - */ -function setSettings(aKey, aValue, aAllowError) { - let settings = {}; - settings[aKey] = aValue; - let lock = window.navigator.mozSettings.createLock(); - let request = lock.set(settings); - let deferred = Promise.defer(); - lock.onsettingstransactionsuccess = function () { - log("setSettings(" + JSON.stringify(settings) + ") - success"); - deferred.resolve(); - }; - lock.onsettingstransactionfailure = function () { - ok(aAllowError, "setSettings(" + JSON.stringify(settings) + ") - error"); - // We resolve even though we've thrown an error, since the ok() - // will do that. - deferred.resolve(); - }; - return deferred.promise; -} - -/** - * Wait for observer event. - * - * Resolve if that topic event occurs. Never reject. - * - * Fulfill params: the subject passed. - * - * @param aTopic - * A string topic name. - * - * @return A deferred promise. - */ -function waitForObserverEvent(aTopic) { - let obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService); - let deferred = Promise.defer(); - - obs.addObserver(function observer(subject, topic, data) { - if (topic === aTopic) { - obs.removeObserver(observer, aTopic); - deferred.resolve(subject); - } - }, aTopic, false); - - return deferred.promise; -} - -/** - * Wait for one named event. - * - * Resolve if that named event occurs. Never reject. - * - * Fulfill params: the DOMEvent passed. - * - * @param aEventTarget - * An EventTarget object. - * @param aEventName - * A string event name. - * @param aMatchFun [optional] - * A matching function returns true or false to filter the event. - * - * @return A deferred promise. - */ -function waitForTargetEvent(aEventTarget, aEventName, aMatchFun) { - return new Promise(function(aResolve, aReject) { - aEventTarget.addEventListener(aEventName, function onevent(aEvent) { - if (!aMatchFun || aMatchFun(aEvent)) { - aEventTarget.removeEventListener(aEventName, onevent); - ok(true, "Event '" + aEventName + "' got."); - aResolve(aEvent); - } - }); - }); -} - -/** - * Set the default data connection enabling state, wait for - * "network-connection-state-changed" event and verify state. - * - * Fulfill params: instance of nsIRilNetworkInfo of the network connected. - * - * @param aEnabled - * A boolean state. - * - * @return A deferred promise. - */ -function setDataEnabledAndWait(aEnabled) { - let promises = []; - promises.push(waitForObserverEvent(TOPIC_CONNECTION_STATE_CHANGED) - .then(function(aSubject) { - ok(aSubject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(aSubject.type, NETWORK_TYPE_MOBILE, - "subject.type should be " + NETWORK_TYPE_MOBILE); - is(aSubject.state, - aEnabled ? Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED - : Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED, - "subject.state should be " + aEnabled ? "CONNECTED" : "DISCONNECTED"); - - return aSubject; - })); - promises.push(setSettings(SETTINGS_KEY_DATA_ENABLED, aEnabled)); - - return Promise.all(promises).then(aValues => aValues[0]); -} - -/** - * Setup a certain type of data connection, wait for - * "network-connection-state-changed" event and verify state. - * - * Fulfill params: instance of nsIRilNetworkInfo of the network connected. - * - * @param aNetworkType - * The mobile network type to setup. - * - * @return A deferred promise. - */ -function setupDataCallAndWait(aNetworkType) { - log("setupDataCallAndWait: " + aNetworkType); - - let promises = []; - promises.push(waitForObserverEvent(TOPIC_CONNECTION_STATE_CHANGED) - .then(function(aSubject) { - ok(aSubject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(aSubject.type, aNetworkType, - "subject.type should be " + aNetworkType); - is(aSubject.state, Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED, - "subject.state should be CONNECTED"); - - return aSubject; - })); - promises.push(radioInterface.setupDataCallByType(aNetworkType)); - - return Promise.all(promises).then(aValues => aValues[0]); -} - -/** - * Deactivate a certain type of data connection, wait for - * "network-connection-state-changed" event and verify state. - * - * Fulfill params: (none) - * - * @param aNetworkType - * The mobile network type to deactivate. - * - * @return A deferred promise. - */ -function deactivateDataCallAndWait(aNetworkType) { - log("deactivateDataCallAndWait: " + aNetworkType); - - let promises = []; - promises.push(waitForObserverEvent(TOPIC_CONNECTION_STATE_CHANGED) - .then(function(aSubject) { - ok(aSubject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(aSubject.type, aNetworkType, - "subject.type should be " + aNetworkType); - is(aSubject.state, Ci.nsINetworkInfo.NETWORK_STATE_DISCONNECTED, - "subject.state should be DISCONNECTED"); - })); - promises.push(radioInterface.deactivateDataCallByType(aNetworkType)); - - return Promise.all(promises); -} - -/** - * Wait for pending emulator transactions and call |finish()|. - */ -function cleanUp() { - // Use ok here so that we have at least one test run. - ok(true, ":: CLEANING UP ::"); - - waitFor(finish, function() { - return _pendingEmulatorShellCmdCount === 0 && - _pendingEmulatorCmdCount === 0; - }); -} - -/** - * Basic test routine helper. - * - * This helper does nothing but clean-ups. - * - * @param aTestCaseMain - * A function that takes no parameter. - */ -function startTestBase(aTestCaseMain) { - Promise.resolve() - .then(aTestCaseMain) - .then(cleanUp, function(aException) { - ok(false, "promise rejects during test: " + aException); - cleanUp(); - }); -} diff --git a/dom/system/gonk/tests/marionette/manifest.ini b/dom/system/gonk/tests/marionette/manifest.ini deleted file mode 100644 index 528fe3baf..000000000 --- a/dom/system/gonk/tests/marionette/manifest.ini +++ /dev/null @@ -1,19 +0,0 @@ -[DEFAULT] -run-if = buildapp == 'b2g' - -[test_geolocation.js] -skip-if = true # Bug 808783 -[test_fakevolume.js] -[test_ril_code_quality.py] -[test_screen_state.js] -[test_dsds_numRadioInterfaces.js] -[test_data_connection.js] -[test_network_active_changed.js] -[test_multiple_data_connection.js] -[test_data_connection_proxy.js] -[test_network_interface_list_service.js] -[test_all_network_info.js] -[test_network_interface_mtu.js] -skip-if = android_version < '19' -[test_timezone_changes.js] -skip-if = android_version < '19' diff --git a/dom/system/gonk/tests/marionette/ril_jshint/README.md b/dom/system/gonk/tests/marionette/ril_jshint/README.md deleted file mode 100644 index a63967d63..000000000 --- a/dom/system/gonk/tests/marionette/ril_jshint/README.md +++ /dev/null @@ -1,9 +0,0 @@ -Test RIL Code Quality -===================== - -For more information, please refer to - -* Bug 880643 - B2G RIL: Add a code quality test on try server for RIL javascript code in gecko -* Slide: https://speakerdeck.com/aknow/improve-code-quality-of-ril-code-by-jshint -* Document: https://hackpad.com/Code-Quality-Test-For-RIL-Javascript-Code-In-Gecko-cz5j7YIGiw8 - diff --git a/dom/system/gonk/tests/marionette/ril_jshint/jshint.js b/dom/system/gonk/tests/marionette/ril_jshint/jshint.js deleted file mode 100644 index ec5263a5b..000000000 --- a/dom/system/gonk/tests/marionette/ril_jshint/jshint.js +++ /dev/null @@ -1,11096 +0,0 @@ -//2.1.3 -var JSHINT; -(function () { -var require; -require=(function(e,t,n){function i(n,s){if(!t[n]){if(!e[n]){var o=typeof require=="function"&&require;if(!s&&o)return o(n,!0);if(r)return r(n,!0);throw new Error("Cannot find module '"+n+"'")}var u=t[n]={exports:{}};e[n][0].call(u.exports,function(t){var r=e[n][1][t];return i(r?r:t)},u,u.exports)}return t[n].exports}var r=typeof require=="function"&&require;for(var s=0;s 0) { - var fn = queue.shift(); - fn(); - } - } - }, true); - - return function nextTick(fn) { - queue.push(fn); - window.postMessage('process-tick', '*'); - }; - } - - return function nextTick(fn) { - setTimeout(fn, 0); - }; -})(); - -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -} - -// TODO(shtylman) -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; - -},{}],2:[function(require,module,exports){ -(function(process){if (!process.EventEmitter) process.EventEmitter = function () {}; - -var EventEmitter = exports.EventEmitter = process.EventEmitter; -var isArray = typeof Array.isArray === 'function' - ? Array.isArray - : function (xs) { - return Object.prototype.toString.call(xs) === '[object Array]' - } -; -function indexOf (xs, x) { - if (xs.indexOf) return xs.indexOf(x); - for (var i = 0; i < xs.length; i++) { - if (x === xs[i]) return i; - } - return -1; -} - -// By default EventEmitters will print a warning if more than -// 10 listeners are added to it. This is a useful default which -// helps finding memory leaks. -// -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -var defaultMaxListeners = 10; -EventEmitter.prototype.setMaxListeners = function(n) { - if (!this._events) this._events = {}; - this._events.maxListeners = n; -}; - - -EventEmitter.prototype.emit = function(type) { - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events || !this._events.error || - (isArray(this._events.error) && !this._events.error.length)) - { - if (arguments[1] instanceof Error) { - throw arguments[1]; // Unhandled 'error' event - } else { - throw new Error("Uncaught, unspecified 'error' event."); - } - return false; - } - } - - if (!this._events) return false; - var handler = this._events[type]; - if (!handler) return false; - - if (typeof handler == 'function') { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - var args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); - } - return true; - - } else if (isArray(handler)) { - var args = Array.prototype.slice.call(arguments, 1); - - var listeners = handler.slice(); - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - return true; - - } else { - return false; - } -}; - -// EventEmitter is defined in src/node_events.cc -// EventEmitter.prototype.emit() is also defined there. -EventEmitter.prototype.addListener = function(type, listener) { - if ('function' !== typeof listener) { - throw new Error('addListener only takes instances of Function'); - } - - if (!this._events) this._events = {}; - - // To avoid recursion in the case that type == "newListeners"! Before - // adding it to the listeners, first emit "newListeners". - this.emit('newListener', type, listener); - - if (!this._events[type]) { - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - } else if (isArray(this._events[type])) { - - // Check for listener leak - if (!this._events[type].warned) { - var m; - if (this._events.maxListeners !== undefined) { - m = this._events.maxListeners; - } else { - m = defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - console.trace(); - } - } - - // If we've already got an array, just append. - this._events[type].push(listener); - } else { - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - var self = this; - self.on(type, function g() { - self.removeListener(type, g); - listener.apply(this, arguments); - }); - - return this; -}; - -EventEmitter.prototype.removeListener = function(type, listener) { - if ('function' !== typeof listener) { - throw new Error('removeListener only takes instances of Function'); - } - - // does not use listeners(), so no side effect of creating _events[type] - if (!this._events || !this._events[type]) return this; - - var list = this._events[type]; - - if (isArray(list)) { - var i = indexOf(list, listener); - if (i < 0) return this; - list.splice(i, 1); - if (list.length == 0) - delete this._events[type]; - } else if (this._events[type] === listener) { - delete this._events[type]; - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - if (arguments.length === 0) { - this._events = {}; - return this; - } - - // does not use listeners(), so no side effect of creating _events[type] - if (type && this._events && this._events[type]) this._events[type] = null; - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - if (!this._events) this._events = {}; - if (!this._events[type]) this._events[type] = []; - if (!isArray(this._events[type])) { - this._events[type] = [this._events[type]]; - } - return this._events[type]; -}; - -})(require("__browserify_process")) -},{"__browserify_process":1}],3:[function(require,module,exports){ -(function(){// jshint -W001 - -"use strict"; - -// Identifiers provided by the ECMAScript standard. - -exports.reservedVars = { - arguments : false, - NaN : false -}; - -exports.ecmaIdentifiers = { - Array : false, - Boolean : false, - Date : false, - decodeURI : false, - decodeURIComponent : false, - encodeURI : false, - encodeURIComponent : false, - Error : false, - "eval" : false, - EvalError : false, - Function : false, - hasOwnProperty : false, - isFinite : false, - isNaN : false, - JSON : false, - Math : false, - Map : false, - Number : false, - Object : false, - parseInt : false, - parseFloat : false, - RangeError : false, - ReferenceError : false, - RegExp : false, - Set : false, - String : false, - SyntaxError : false, - TypeError : false, - URIError : false, - WeakMap : false -}; - -// Global variables commonly provided by a web browser environment. - -exports.browser = { - ArrayBuffer : false, - ArrayBufferView : false, - Audio : false, - Blob : false, - addEventListener : false, - applicationCache : false, - atob : false, - blur : false, - btoa : false, - clearInterval : false, - clearTimeout : false, - close : false, - closed : false, - DataView : false, - DOMParser : false, - defaultStatus : false, - document : false, - Element : false, - ElementTimeControl : false, - event : false, - FileReader : false, - Float32Array : false, - Float64Array : false, - FormData : false, - focus : false, - frames : false, - getComputedStyle : false, - HTMLElement : false, - HTMLAnchorElement : false, - HTMLBaseElement : false, - HTMLBlockquoteElement: false, - HTMLBodyElement : false, - HTMLBRElement : false, - HTMLButtonElement : false, - HTMLCanvasElement : false, - HTMLDirectoryElement : false, - HTMLDivElement : false, - HTMLDListElement : false, - HTMLFieldSetElement : false, - HTMLFontElement : false, - HTMLFormElement : false, - HTMLFrameElement : false, - HTMLFrameSetElement : false, - HTMLHeadElement : false, - HTMLHeadingElement : false, - HTMLHRElement : false, - HTMLHtmlElement : false, - HTMLIFrameElement : false, - HTMLImageElement : false, - HTMLInputElement : false, - HTMLIsIndexElement : false, - HTMLLabelElement : false, - HTMLLayerElement : false, - HTMLLegendElement : false, - HTMLLIElement : false, - HTMLLinkElement : false, - HTMLMapElement : false, - HTMLMenuElement : false, - HTMLMetaElement : false, - HTMLModElement : false, - HTMLObjectElement : false, - HTMLOListElement : false, - HTMLOptGroupElement : false, - HTMLOptionElement : false, - HTMLParagraphElement : false, - HTMLParamElement : false, - HTMLPreElement : false, - HTMLQuoteElement : false, - HTMLScriptElement : false, - HTMLSelectElement : false, - HTMLStyleElement : false, - HTMLTableCaptionElement: false, - HTMLTableCellElement : false, - HTMLTableColElement : false, - HTMLTableElement : false, - HTMLTableRowElement : false, - HTMLTableSectionElement: false, - HTMLTextAreaElement : false, - HTMLTitleElement : false, - HTMLUListElement : false, - HTMLVideoElement : false, - history : false, - Int16Array : false, - Int32Array : false, - Int8Array : false, - Image : false, - length : false, - localStorage : false, - location : false, - MessageChannel : false, - MessageEvent : false, - MessagePort : false, - moveBy : false, - moveTo : false, - MutationObserver : false, - name : false, - Node : false, - NodeFilter : false, - navigator : false, - onbeforeunload : true, - onblur : true, - onerror : true, - onfocus : true, - onload : true, - onresize : true, - onunload : true, - open : false, - openDatabase : false, - opener : false, - Option : false, - parent : false, - print : false, - removeEventListener : false, - resizeBy : false, - resizeTo : false, - screen : false, - scroll : false, - scrollBy : false, - scrollTo : false, - sessionStorage : false, - setInterval : false, - setTimeout : false, - SharedWorker : false, - status : false, - SVGAElement : false, - SVGAltGlyphDefElement: false, - SVGAltGlyphElement : false, - SVGAltGlyphItemElement: false, - SVGAngle : false, - SVGAnimateColorElement: false, - SVGAnimateElement : false, - SVGAnimateMotionElement: false, - SVGAnimateTransformElement: false, - SVGAnimatedAngle : false, - SVGAnimatedBoolean : false, - SVGAnimatedEnumeration: false, - SVGAnimatedInteger : false, - SVGAnimatedLength : false, - SVGAnimatedLengthList: false, - SVGAnimatedNumber : false, - SVGAnimatedNumberList: false, - SVGAnimatedPathData : false, - SVGAnimatedPoints : false, - SVGAnimatedPreserveAspectRatio: false, - SVGAnimatedRect : false, - SVGAnimatedString : false, - SVGAnimatedTransformList: false, - SVGAnimationElement : false, - SVGCSSRule : false, - SVGCircleElement : false, - SVGClipPathElement : false, - SVGColor : false, - SVGColorProfileElement: false, - SVGColorProfileRule : false, - SVGComponentTransferFunctionElement: false, - SVGCursorElement : false, - SVGDefsElement : false, - SVGDescElement : false, - SVGDocument : false, - SVGElement : false, - SVGElementInstance : false, - SVGElementInstanceList: false, - SVGEllipseElement : false, - SVGExternalResourcesRequired: false, - SVGFEBlendElement : false, - SVGFEColorMatrixElement: false, - SVGFEComponentTransferElement: false, - SVGFECompositeElement: false, - SVGFEConvolveMatrixElement: false, - SVGFEDiffuseLightingElement: false, - SVGFEDisplacementMapElement: false, - SVGFEDistantLightElement: false, - SVGFEDropShadowElement: false, - SVGFEFloodElement : false, - SVGFEFuncAElement : false, - SVGFEFuncBElement : false, - SVGFEFuncGElement : false, - SVGFEFuncRElement : false, - SVGFEGaussianBlurElement: false, - SVGFEImageElement : false, - SVGFEMergeElement : false, - SVGFEMergeNodeElement: false, - SVGFEMorphologyElement: false, - SVGFEOffsetElement : false, - SVGFEPointLightElement: false, - SVGFESpecularLightingElement: false, - SVGFESpotLightElement: false, - SVGFETileElement : false, - SVGFETurbulenceElement: false, - SVGFilterElement : false, - SVGFilterPrimitiveStandardAttributes: false, - SVGFitToViewBox : false, - SVGFontElement : false, - SVGFontFaceElement : false, - SVGFontFaceFormatElement: false, - SVGFontFaceNameElement: false, - SVGFontFaceSrcElement: false, - SVGFontFaceUriElement: false, - SVGForeignObjectElement: false, - SVGGElement : false, - SVGGlyphElement : false, - SVGGlyphRefElement : false, - SVGGradientElement : false, - SVGHKernElement : false, - SVGICCColor : false, - SVGImageElement : false, - SVGLangSpace : false, - SVGLength : false, - SVGLengthList : false, - SVGLineElement : false, - SVGLinearGradientElement: false, - SVGLocatable : false, - SVGMPathElement : false, - SVGMarkerElement : false, - SVGMaskElement : false, - SVGMatrix : false, - SVGMetadataElement : false, - SVGMissingGlyphElement: false, - SVGNumber : false, - SVGNumberList : false, - SVGPaint : false, - SVGPathElement : false, - SVGPathSeg : false, - SVGPathSegArcAbs : false, - SVGPathSegArcRel : false, - SVGPathSegClosePath : false, - SVGPathSegCurvetoCubicAbs: false, - SVGPathSegCurvetoCubicRel: false, - SVGPathSegCurvetoCubicSmoothAbs: false, - SVGPathSegCurvetoCubicSmoothRel: false, - SVGPathSegCurvetoQuadraticAbs: false, - SVGPathSegCurvetoQuadraticRel: false, - SVGPathSegCurvetoQuadraticSmoothAbs: false, - SVGPathSegCurvetoQuadraticSmoothRel: false, - SVGPathSegLinetoAbs : false, - SVGPathSegLinetoHorizontalAbs: false, - SVGPathSegLinetoHorizontalRel: false, - SVGPathSegLinetoRel : false, - SVGPathSegLinetoVerticalAbs: false, - SVGPathSegLinetoVerticalRel: false, - SVGPathSegList : false, - SVGPathSegMovetoAbs : false, - SVGPathSegMovetoRel : false, - SVGPatternElement : false, - SVGPoint : false, - SVGPointList : false, - SVGPolygonElement : false, - SVGPolylineElement : false, - SVGPreserveAspectRatio: false, - SVGRadialGradientElement: false, - SVGRect : false, - SVGRectElement : false, - SVGRenderingIntent : false, - SVGSVGElement : false, - SVGScriptElement : false, - SVGSetElement : false, - SVGStopElement : false, - SVGStringList : false, - SVGStylable : false, - SVGStyleElement : false, - SVGSwitchElement : false, - SVGSymbolElement : false, - SVGTRefElement : false, - SVGTSpanElement : false, - SVGTests : false, - SVGTextContentElement: false, - SVGTextElement : false, - SVGTextPathElement : false, - SVGTextPositioningElement: false, - SVGTitleElement : false, - SVGTransform : false, - SVGTransformList : false, - SVGTransformable : false, - SVGURIReference : false, - SVGUnitTypes : false, - SVGUseElement : false, - SVGVKernElement : false, - SVGViewElement : false, - SVGViewSpec : false, - SVGZoomAndPan : false, - TimeEvent : false, - top : false, - Uint16Array : false, - Uint32Array : false, - Uint8Array : false, - Uint8ClampedArray : false, - WebSocket : false, - window : false, - Worker : false, - XMLHttpRequest : false, - XMLSerializer : false, - XPathEvaluator : false, - XPathException : false, - XPathExpression : false, - XPathNSResolver : false, - XPathResult : false -}; - -exports.devel = { - alert : false, - confirm: false, - console: false, - Debug : false, - opera : false, - prompt : false -}; - -exports.worker = { - importScripts: true, - postMessage : true, - self : true -}; - -// Widely adopted global names that are not part of ECMAScript standard -exports.nonstandard = { - escape : false, - unescape: false -}; - -// Globals provided by popular JavaScript environments. - -exports.couch = { - "require" : false, - respond : false, - getRow : false, - emit : false, - send : false, - start : false, - sum : false, - log : false, - exports : false, - module : false, - provides : false -}; - -exports.node = { - __filename : false, - __dirname : false, - Buffer : false, - DataView : false, - console : false, - exports : true, // In Node it is ok to exports = module.exports = foo(); - GLOBAL : false, - global : false, - module : false, - process : false, - require : false, - setTimeout : false, - clearTimeout : false, - setInterval : false, - clearInterval : false, - setImmediate : false, // v0.9.1+ - clearImmediate: false // v0.9.1+ -}; - -exports.phantom = { - phantom : true, - require : true, - WebPage : true -}; - -exports.rhino = { - defineClass : false, - deserialize : false, - gc : false, - help : false, - importPackage: false, - "java" : false, - load : false, - loadClass : false, - print : false, - quit : false, - readFile : false, - readUrl : false, - runCommand : false, - seal : false, - serialize : false, - spawn : false, - sync : false, - toint32 : false, - version : false -}; - -exports.wsh = { - ActiveXObject : true, - Enumerator : true, - GetObject : true, - ScriptEngine : true, - ScriptEngineBuildVersion : true, - ScriptEngineMajorVersion : true, - ScriptEngineMinorVersion : true, - VBArray : true, - WSH : true, - WScript : true, - XDomainRequest : true -}; - -// Globals provided by popular JavaScript libraries. - -exports.dojo = { - dojo : false, - dijit : false, - dojox : false, - define : false, - "require": false -}; - -exports.jquery = { - "$" : false, - jQuery : false -}; - -exports.mootools = { - "$" : false, - "$$" : false, - Asset : false, - Browser : false, - Chain : false, - Class : false, - Color : false, - Cookie : false, - Core : false, - Document : false, - DomReady : false, - DOMEvent : false, - DOMReady : false, - Drag : false, - Element : false, - Elements : false, - Event : false, - Events : false, - Fx : false, - Group : false, - Hash : false, - HtmlTable : false, - Iframe : false, - IframeShim : false, - InputValidator: false, - instanceOf : false, - Keyboard : false, - Locale : false, - Mask : false, - MooTools : false, - Native : false, - Options : false, - OverText : false, - Request : false, - Scroller : false, - Slick : false, - Slider : false, - Sortables : false, - Spinner : false, - Swiff : false, - Tips : false, - Type : false, - typeOf : false, - URI : false, - Window : false -}; - -exports.prototypejs = { - "$" : false, - "$$" : false, - "$A" : false, - "$F" : false, - "$H" : false, - "$R" : false, - "$break" : false, - "$continue" : false, - "$w" : false, - Abstract : false, - Ajax : false, - Class : false, - Enumerable : false, - Element : false, - Event : false, - Field : false, - Form : false, - Hash : false, - Insertion : false, - ObjectRange : false, - PeriodicalExecuter: false, - Position : false, - Prototype : false, - Selector : false, - Template : false, - Toggle : false, - Try : false, - Autocompleter : false, - Builder : false, - Control : false, - Draggable : false, - Draggables : false, - Droppables : false, - Effect : false, - Sortable : false, - SortableObserver : false, - Sound : false, - Scriptaculous : false -}; - -exports.yui = { - YUI : false, - Y : false, - YUI_config: false -}; - - -})() -},{}],4:[function(require,module,exports){ -"use strict"; - -var state = { - syntax: {}, - - reset: function () { - this.tokens = { - prev: null, - next: null, - curr: null - }; - - this.option = {}; - this.ignored = {}; - this.directive = {}; - this.jsonMode = false; - this.jsonWarnings = []; - this.lines = []; - this.tab = ""; - this.cache = {}; // Node.JS doesn't have Map. Sniff. - } -}; - -exports.state = state; - -},{}],5:[function(require,module,exports){ -(function(){"use strict"; - -exports.register = function (linter) { - // Check for properties named __proto__. This special property was - // deprecated and then re-introduced for ES6. - - linter.on("Identifier", function style_scanProto(data) { - if (linter.getOption("proto")) { - return; - } - - if (data.name === "__proto__") { - linter.warn("W103", { - line: data.line, - char: data.char, - data: [ data.name ] - }); - } - }); - - // Check for properties named __iterator__. This is a special property - // available only in browsers with JavaScript 1.7 implementation. - - linter.on("Identifier", function style_scanIterator(data) { - if (linter.getOption("iterator")) { - return; - } - - if (data.name === "__iterator__") { - linter.warn("W104", { - line: data.line, - char: data.char, - data: [ data.name ] - }); - } - }); - - // Check for dangling underscores. - - linter.on("Identifier", function style_scanDangling(data) { - if (!linter.getOption("nomen")) { - return; - } - - // Underscore.js - if (data.name === "_") { - return; - } - - // In Node, __dirname and __filename should be ignored. - if (linter.getOption("node")) { - if (/^(__dirname|__filename)$/.test(data.name) && !data.isProperty) { - return; - } - } - - if (/^(_+.*|.*_+)$/.test(data.name)) { - linter.warn("W105", { - line: data.line, - char: data.from, - data: [ "dangling '_'", data.name ] - }); - } - }); - - // Check that all identifiers are using camelCase notation. - // Exceptions: names like MY_VAR and _myVar. - - linter.on("Identifier", function style_scanCamelCase(data) { - if (!linter.getOption("camelcase")) { - return; - } - - if (data.name.replace(/^_+/, "").indexOf("_") > -1 && !data.name.match(/^[A-Z0-9_]*$/)) { - linter.warn("W106", { - line: data.line, - char: data.from, - data: [ data.name ] - }); - } - }); - - // Enforce consistency in style of quoting. - - linter.on("String", function style_scanQuotes(data) { - var quotmark = linter.getOption("quotmark"); - var code; - - if (!quotmark) { - return; - } - - // If quotmark is set to 'single' warn about all double-quotes. - - if (quotmark === "single" && data.quote !== "'") { - code = "W109"; - } - - // If quotmark is set to 'double' warn about all single-quotes. - - if (quotmark === "double" && data.quote !== "\"") { - code = "W108"; - } - - // If quotmark is set to true, remember the first quotation style - // and then warn about all others. - - if (quotmark === true) { - if (!linter.getCache("quotmark")) { - linter.setCache("quotmark", data.quote); - } - - if (linter.getCache("quotmark") !== data.quote) { - code = "W110"; - } - } - - if (code) { - linter.warn(code, { - line: data.line, - char: data.char, - }); - } - }); - - linter.on("Number", function style_scanNumbers(data) { - if (data.value.charAt(0) === ".") { - // Warn about a leading decimal point. - linter.warn("W008", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } - - if (data.value.substr(data.value.length - 1) === ".") { - // Warn about a trailing decimal point. - linter.warn("W047", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } - - if (/^00+/.test(data.value)) { - // Multiple leading zeroes. - linter.warn("W046", { - line: data.line, - char: data.char, - data: [ data.value ] - }); - } - }); - - // Warn about script URLs. - - linter.on("String", function style_scanJavaScriptURLs(data) { - var re = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; - - if (linter.getOption("scripturl")) { - return; - } - - if (re.test(data.value)) { - linter.warn("W107", { - line: data.line, - char: data.char - }); - } - }); -}; -})() -},{}],6:[function(require,module,exports){ -/* - * Regular expressions. Some of these are stupidly long. - */ - -/*jshint maxlen:1000 */ - -"use string"; - -// Unsafe comment or string (ax) -exports.unsafeString = - /@cc|<\/?|script|\]\s*\]|<\s*!|</i; - -// Unsafe characters that are silently deleted by one or more browsers (cx) -exports.unsafeChars = - /[\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - -// Characters in strings that need escaping (nx and nxg) -exports.needEsc = - /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/; - -exports.needEscGlobal = - /[\u0000-\u001f&<"\/\\\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; - -// Star slash (lx) -exports.starSlash = /\*\//; - -// Identifier (ix) -exports.identifier = /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/; - -// JavaScript URL (jx) -exports.javascriptURL = /^(?:javascript|jscript|ecmascript|vbscript|mocha|livescript)\s*:/i; - -// Catches /* falls through */ comments (ft) -//exports.fallsThrough = /^\s*\/\*\s*falls?\sthrough\s*\*\/\s*$/; -exports.fallsThrough = /^\s*\/\/\s*Falls?\sthrough.*\s*$/; - -},{}],7:[function(require,module,exports){ -(function(global){/*global window, global*/ -var util = require("util") -var assert = require("assert") - -var slice = Array.prototype.slice -var console -var times = {} - -if (typeof global !== "undefined" && global.console) { - console = global.console -} else if (typeof window !== "undefined" && window.console) { - console = window.console -} else { - console = window.console = {} -} - -var functions = [ - [log, "log"] - , [info, "info"] - , [warn, "warn"] - , [error, "error"] - , [time, "time"] - , [timeEnd, "timeEnd"] - , [trace, "trace"] - , [dir, "dir"] - , [assert, "assert"] -] - -for (var i = 0; i < functions.length; i++) { - var tuple = functions[i] - var f = tuple[0] - var name = tuple[1] - - if (!console[name]) { - console[name] = f - } -} - -module.exports = console - -function log() {} - -function info() { - console.log.apply(console, arguments) -} - -function warn() { - console.log.apply(console, arguments) -} - -function error() { - console.warn.apply(console, arguments) -} - -function time(label) { - times[label] = Date.now() -} - -function timeEnd(label) { - var time = times[label] - if (!time) { - throw new Error("No such label: " + label) - } - - var duration = Date.now() - time - console.log(label + ": " + duration + "ms") -} - -function trace() { - var err = new Error() - err.name = "Trace" - err.message = util.format.apply(null, arguments) - console.error(err.stack) -} - -function dir(object) { - console.log(util.inspect(object) + "\n") -} - -function assert(expression) { - if (!expression) { - var arr = slice.call(arguments, 1) - assert.ok(false, util.format.apply(null, arr)) - } -} - -})(window) -},{"util":8,"assert":9}],10:[function(require,module,exports){ -(function(){/* - * Lexical analysis and token construction. - */ - -"use strict"; - -var _ = require("underscore"); -var events = require("events"); -var reg = require("./reg.js"); -var state = require("./state.js").state; - -// Some of these token types are from JavaScript Parser API -// while others are specific to JSHint parser. -// JS Parser API: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API - -var Token = { - Identifier: 1, - Punctuator: 2, - NumericLiteral: 3, - StringLiteral: 4, - Comment: 5, - Keyword: 6, - NullLiteral: 7, - BooleanLiteral: 8, - RegExp: 9 -}; - -// This is auto generated from the unicode tables. -// The tables are at: -// http://www.fileformat.info/info/unicode/category/Lu/list.htm -// http://www.fileformat.info/info/unicode/category/Ll/list.htm -// http://www.fileformat.info/info/unicode/category/Lt/list.htm -// http://www.fileformat.info/info/unicode/category/Lm/list.htm -// http://www.fileformat.info/info/unicode/category/Lo/list.htm -// http://www.fileformat.info/info/unicode/category/Nl/list.htm - -var unicodeLetterTable = [ - 170, 170, 181, 181, 186, 186, 192, 214, - 216, 246, 248, 705, 710, 721, 736, 740, 748, 748, 750, 750, - 880, 884, 886, 887, 890, 893, 902, 902, 904, 906, 908, 908, - 910, 929, 931, 1013, 1015, 1153, 1162, 1319, 1329, 1366, - 1369, 1369, 1377, 1415, 1488, 1514, 1520, 1522, 1568, 1610, - 1646, 1647, 1649, 1747, 1749, 1749, 1765, 1766, 1774, 1775, - 1786, 1788, 1791, 1791, 1808, 1808, 1810, 1839, 1869, 1957, - 1969, 1969, 1994, 2026, 2036, 2037, 2042, 2042, 2048, 2069, - 2074, 2074, 2084, 2084, 2088, 2088, 2112, 2136, 2308, 2361, - 2365, 2365, 2384, 2384, 2392, 2401, 2417, 2423, 2425, 2431, - 2437, 2444, 2447, 2448, 2451, 2472, 2474, 2480, 2482, 2482, - 2486, 2489, 2493, 2493, 2510, 2510, 2524, 2525, 2527, 2529, - 2544, 2545, 2565, 2570, 2575, 2576, 2579, 2600, 2602, 2608, - 2610, 2611, 2613, 2614, 2616, 2617, 2649, 2652, 2654, 2654, - 2674, 2676, 2693, 2701, 2703, 2705, 2707, 2728, 2730, 2736, - 2738, 2739, 2741, 2745, 2749, 2749, 2768, 2768, 2784, 2785, - 2821, 2828, 2831, 2832, 2835, 2856, 2858, 2864, 2866, 2867, - 2869, 2873, 2877, 2877, 2908, 2909, 2911, 2913, 2929, 2929, - 2947, 2947, 2949, 2954, 2958, 2960, 2962, 2965, 2969, 2970, - 2972, 2972, 2974, 2975, 2979, 2980, 2984, 2986, 2990, 3001, - 3024, 3024, 3077, 3084, 3086, 3088, 3090, 3112, 3114, 3123, - 3125, 3129, 3133, 3133, 3160, 3161, 3168, 3169, 3205, 3212, - 3214, 3216, 3218, 3240, 3242, 3251, 3253, 3257, 3261, 3261, - 3294, 3294, 3296, 3297, 3313, 3314, 3333, 3340, 3342, 3344, - 3346, 3386, 3389, 3389, 3406, 3406, 3424, 3425, 3450, 3455, - 3461, 3478, 3482, 3505, 3507, 3515, 3517, 3517, 3520, 3526, - 3585, 3632, 3634, 3635, 3648, 3654, 3713, 3714, 3716, 3716, - 3719, 3720, 3722, 3722, 3725, 3725, 3732, 3735, 3737, 3743, - 3745, 3747, 3749, 3749, 3751, 3751, 3754, 3755, 3757, 3760, - 3762, 3763, 3773, 3773, 3776, 3780, 3782, 3782, 3804, 3805, - 3840, 3840, 3904, 3911, 3913, 3948, 3976, 3980, 4096, 4138, - 4159, 4159, 4176, 4181, 4186, 4189, 4193, 4193, 4197, 4198, - 4206, 4208, 4213, 4225, 4238, 4238, 4256, 4293, 4304, 4346, - 4348, 4348, 4352, 4680, 4682, 4685, 4688, 4694, 4696, 4696, - 4698, 4701, 4704, 4744, 4746, 4749, 4752, 4784, 4786, 4789, - 4792, 4798, 4800, 4800, 4802, 4805, 4808, 4822, 4824, 4880, - 4882, 4885, 4888, 4954, 4992, 5007, 5024, 5108, 5121, 5740, - 5743, 5759, 5761, 5786, 5792, 5866, 5870, 5872, 5888, 5900, - 5902, 5905, 5920, 5937, 5952, 5969, 5984, 5996, 5998, 6000, - 6016, 6067, 6103, 6103, 6108, 6108, 6176, 6263, 6272, 6312, - 6314, 6314, 6320, 6389, 6400, 6428, 6480, 6509, 6512, 6516, - 6528, 6571, 6593, 6599, 6656, 6678, 6688, 6740, 6823, 6823, - 6917, 6963, 6981, 6987, 7043, 7072, 7086, 7087, 7104, 7141, - 7168, 7203, 7245, 7247, 7258, 7293, 7401, 7404, 7406, 7409, - 7424, 7615, 7680, 7957, 7960, 7965, 7968, 8005, 8008, 8013, - 8016, 8023, 8025, 8025, 8027, 8027, 8029, 8029, 8031, 8061, - 8064, 8116, 8118, 8124, 8126, 8126, 8130, 8132, 8134, 8140, - 8144, 8147, 8150, 8155, 8160, 8172, 8178, 8180, 8182, 8188, - 8305, 8305, 8319, 8319, 8336, 8348, 8450, 8450, 8455, 8455, - 8458, 8467, 8469, 8469, 8473, 8477, 8484, 8484, 8486, 8486, - 8488, 8488, 8490, 8493, 8495, 8505, 8508, 8511, 8517, 8521, - 8526, 8526, 8544, 8584, 11264, 11310, 11312, 11358, - 11360, 11492, 11499, 11502, 11520, 11557, 11568, 11621, - 11631, 11631, 11648, 11670, 11680, 11686, 11688, 11694, - 11696, 11702, 11704, 11710, 11712, 11718, 11720, 11726, - 11728, 11734, 11736, 11742, 11823, 11823, 12293, 12295, - 12321, 12329, 12337, 12341, 12344, 12348, 12353, 12438, - 12445, 12447, 12449, 12538, 12540, 12543, 12549, 12589, - 12593, 12686, 12704, 12730, 12784, 12799, 13312, 13312, - 19893, 19893, 19968, 19968, 40907, 40907, 40960, 42124, - 42192, 42237, 42240, 42508, 42512, 42527, 42538, 42539, - 42560, 42606, 42623, 42647, 42656, 42735, 42775, 42783, - 42786, 42888, 42891, 42894, 42896, 42897, 42912, 42921, - 43002, 43009, 43011, 43013, 43015, 43018, 43020, 43042, - 43072, 43123, 43138, 43187, 43250, 43255, 43259, 43259, - 43274, 43301, 43312, 43334, 43360, 43388, 43396, 43442, - 43471, 43471, 43520, 43560, 43584, 43586, 43588, 43595, - 43616, 43638, 43642, 43642, 43648, 43695, 43697, 43697, - 43701, 43702, 43705, 43709, 43712, 43712, 43714, 43714, - 43739, 43741, 43777, 43782, 43785, 43790, 43793, 43798, - 43808, 43814, 43816, 43822, 43968, 44002, 44032, 44032, - 55203, 55203, 55216, 55238, 55243, 55291, 63744, 64045, - 64048, 64109, 64112, 64217, 64256, 64262, 64275, 64279, - 64285, 64285, 64287, 64296, 64298, 64310, 64312, 64316, - 64318, 64318, 64320, 64321, 64323, 64324, 64326, 64433, - 64467, 64829, 64848, 64911, 64914, 64967, 65008, 65019, - 65136, 65140, 65142, 65276, 65313, 65338, 65345, 65370, - 65382, 65470, 65474, 65479, 65482, 65487, 65490, 65495, - 65498, 65500, 65536, 65547, 65549, 65574, 65576, 65594, - 65596, 65597, 65599, 65613, 65616, 65629, 65664, 65786, - 65856, 65908, 66176, 66204, 66208, 66256, 66304, 66334, - 66352, 66378, 66432, 66461, 66464, 66499, 66504, 66511, - 66513, 66517, 66560, 66717, 67584, 67589, 67592, 67592, - 67594, 67637, 67639, 67640, 67644, 67644, 67647, 67669, - 67840, 67861, 67872, 67897, 68096, 68096, 68112, 68115, - 68117, 68119, 68121, 68147, 68192, 68220, 68352, 68405, - 68416, 68437, 68448, 68466, 68608, 68680, 69635, 69687, - 69763, 69807, 73728, 74606, 74752, 74850, 77824, 78894, - 92160, 92728, 110592, 110593, 119808, 119892, 119894, 119964, - 119966, 119967, 119970, 119970, 119973, 119974, 119977, 119980, - 119982, 119993, 119995, 119995, 119997, 120003, 120005, 120069, - 120071, 120074, 120077, 120084, 120086, 120092, 120094, 120121, - 120123, 120126, 120128, 120132, 120134, 120134, 120138, 120144, - 120146, 120485, 120488, 120512, 120514, 120538, 120540, 120570, - 120572, 120596, 120598, 120628, 120630, 120654, 120656, 120686, - 120688, 120712, 120714, 120744, 120746, 120770, 120772, 120779, - 131072, 131072, 173782, 173782, 173824, 173824, 177972, 177972, - 177984, 177984, 178205, 178205, 194560, 195101 -]; - -var identifierStartTable = []; - -for (var i = 0; i < 128; i++) { - identifierStartTable[i] = - i === 36 || // $ - i >= 65 && i <= 90 || // A-Z - i === 95 || // _ - i >= 97 && i <= 122; // a-z -} - -var identifierPartTable = []; - -for (var i = 0; i < 128; i++) { - identifierPartTable[i] = - identifierStartTable[i] || // $, _, A-Z, a-z - i >= 48 && i <= 57; // 0-9 -} - -// Object that handles postponed lexing verifications that checks the parsed -// environment state. - -function asyncTrigger() { - var _checks = []; - - return { - push: function (fn) { - _checks.push(fn); - }, - - check: function () { - for (var check in _checks) { - _checks[check](); - } - - _checks.splice(0, _checks.length); - } - }; -} - -/* - * Lexer for JSHint. - * - * This object does a char-by-char scan of the provided source code - * and produces a sequence of tokens. - * - * var lex = new Lexer("var i = 0;"); - * lex.start(); - * lex.token(); // returns the next token - * - * You have to use the token() method to move the lexer forward - * but you don't have to use its return value to get tokens. In addition - * to token() method returning the next token, the Lexer object also - * emits events. - * - * lex.on("Identifier", function (data) { - * if (data.name.indexOf("_") >= 0) { - * // Produce a warning. - * } - * }); - * - * Note that the token() method returns tokens in a JSLint-compatible - * format while the event emitter uses a slightly modified version of - * Mozilla's JavaScript Parser API. Eventually, we will move away from - * JSLint format. - */ -function Lexer(source) { - var lines = source; - - if (typeof lines === "string") { - lines = lines - .replace(/\r\n/g, "\n") - .replace(/\r/g, "\n") - .split("\n"); - } - - // If the first line is a shebang (#!), make it a blank and move on. - // Shebangs are used by Node scripts. - - if (lines[0] && lines[0].substr(0, 2) === "#!") { - lines[0] = ""; - } - - this.emitter = new events.EventEmitter(); - this.source = source; - this.lines = lines; - this.prereg = true; - - this.line = 0; - this.char = 1; - this.from = 1; - this.input = ""; - - for (var i = 0; i < state.option.indent; i += 1) { - state.tab += " "; - } -} - -Lexer.prototype = { - _lines: [], - - get lines() { - this._lines = state.lines; - return this._lines; - }, - - set lines(val) { - this._lines = val; - state.lines = this._lines; - }, - - /* - * Return the next i character without actually moving the - * char pointer. - */ - peek: function (i) { - return this.input.charAt(i || 0); - }, - - /* - * Move the char pointer forward i times. - */ - skip: function (i) { - i = i || 1; - this.char += i; - this.input = this.input.slice(i); - }, - - /* - * Subscribe to a token event. The API for this method is similar - * Underscore.js i.e. you can subscribe to multiple events with - * one call: - * - * lex.on("Identifier Number", function (data) { - * // ... - * }); - */ - on: function (names, listener) { - names.split(" ").forEach(function (name) { - this.emitter.on(name, listener); - }.bind(this)); - }, - - /* - * Trigger a token event. All arguments will be passed to each - * listener. - */ - trigger: function () { - this.emitter.emit.apply(this.emitter, Array.prototype.slice.call(arguments)); - }, - - /* - * Postpone a token event. the checking condition is set as - * last parameter, and the trigger function is called in a - * stored callback. To be later called using the check() function - * by the parser. This avoids parser's peek() to give the lexer - * a false context. - */ - triggerAsync: function (type, args, checks, fn) { - checks.push(function () { - if (fn()) { - this.trigger(type, args); - } - }.bind(this)); - }, - - /* - * Extract a punctuator out of the next sequence of characters - * or return 'null' if its not possible. - * - * This method's implementation was heavily influenced by the - * scanPunctuator function in the Esprima parser's source code. - */ - scanPunctuator: function () { - var ch1 = this.peek(); - var ch2, ch3, ch4; - - switch (ch1) { - // Most common single-character punctuators - case ".": - if ((/^[0-9]$/).test(this.peek(1))) { - return null; - } - if (this.peek(1) === "." && this.peek(2) === ".") { - return { - type: Token.Punctuator, - value: "..." - }; - } - /* falls through */ - case "(": - case ")": - case ";": - case ",": - case "{": - case "}": - case "[": - case "]": - case ":": - case "~": - case "?": - return { - type: Token.Punctuator, - value: ch1 - }; - - // A pound sign (for Node shebangs) - case "#": - return { - type: Token.Punctuator, - value: ch1 - }; - - // We're at the end of input - case "": - return null; - } - - // Peek more characters - - ch2 = this.peek(1); - ch3 = this.peek(2); - ch4 = this.peek(3); - - // 4-character punctuator: >>>= - - if (ch1 === ">" && ch2 === ">" && ch3 === ">" && ch4 === "=") { - return { - type: Token.Punctuator, - value: ">>>=" - }; - } - - // 3-character punctuators: === !== >>> <<= >>= - - if (ch1 === "=" && ch2 === "=" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "===" - }; - } - - if (ch1 === "!" && ch2 === "=" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "!==" - }; - } - - if (ch1 === ">" && ch2 === ">" && ch3 === ">") { - return { - type: Token.Punctuator, - value: ">>>" - }; - } - - if (ch1 === "<" && ch2 === "<" && ch3 === "=") { - return { - type: Token.Punctuator, - value: "<<=" - }; - } - - if (ch1 === ">" && ch2 === ">" && ch3 === "=") { - return { - type: Token.Punctuator, - value: ">>=" - }; - } - - // Fat arrow punctuator - if (ch1 === "=" && ch2 === ">") { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } - - // 2-character punctuators: <= >= == != ++ -- << >> && || - // += -= *= %= &= |= ^= (but not /=, see below) - if (ch1 === ch2 && ("+-<>&|".indexOf(ch1) >= 0)) { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } - - if ("<>=!+-*%&|^".indexOf(ch1) >= 0) { - if (ch2 === "=") { - return { - type: Token.Punctuator, - value: ch1 + ch2 - }; - } - - return { - type: Token.Punctuator, - value: ch1 - }; - } - - // Special case: /=. We need to make sure that this is an - // operator and not a regular expression. - - if (ch1 === "/") { - if (ch2 === "=" && /\/=(?!(\S*\/[gim]?))/.test(this.input)) { - // /= is not a part of a regular expression, return it as a - // punctuator. - return { - type: Token.Punctuator, - value: "/=" - }; - } - - return { - type: Token.Punctuator, - value: "/" - }; - } - - return null; - }, - - /* - * Extract a comment out of the next sequence of characters and/or - * lines or return 'null' if its not possible. Since comments can - * span across multiple lines this method has to move the char - * pointer. - * - * In addition to normal JavaScript comments (// and /*) this method - * also recognizes JSHint- and JSLint-specific comments such as - * /*jshint, /*jslint, /*globals and so on. - */ - scanComments: function () { - var ch1 = this.peek(); - var ch2 = this.peek(1); - var rest = this.input.substr(2); - var startLine = this.line; - var startChar = this.char; - - // Create a comment token object and make sure it - // has all the data JSHint needs to work with special - // comments. - - function commentToken(label, body, opt) { - var special = ["jshint", "jslint", "members", "member", "globals", "global", "exported"]; - var isSpecial = false; - var value = label + body; - var commentType = "plain"; - opt = opt || {}; - - if (opt.isMultiline) { - value += "*/"; - } - - special.forEach(function (str) { - if (isSpecial) { - return; - } - - // Don't recognize any special comments other than jshint for single-line - // comments. This introduced many problems with legit comments. - if (label === "//" && str !== "jshint") { - return; - } - - if (body.substr(0, str.length) === str) { - isSpecial = true; - label = label + str; - body = body.substr(str.length); - } - - if (!isSpecial && body.charAt(0) === " " && body.substr(1, str.length) === str) { - isSpecial = true; - label = label + " " + str; - body = body.substr(str.length + 1); - } - - if (!isSpecial) { - return; - } - - switch (str) { - case "member": - commentType = "members"; - break; - case "global": - commentType = "globals"; - break; - default: - commentType = str; - } - }); - - return { - type: Token.Comment, - commentType: commentType, - value: value, - body: body, - isSpecial: isSpecial, - isMultiline: opt.isMultiline || false, - isMalformed: opt.isMalformed || false - }; - } - - // End of unbegun comment. Raise an error and skip that input. - if (ch1 === "*" && ch2 === "/") { - this.trigger("error", { - code: "E018", - line: startLine, - character: startChar - }); - - this.skip(2); - return null; - } - - // Comments must start either with // or /* - if (ch1 !== "/" || (ch2 !== "*" && ch2 !== "/")) { - return null; - } - - // One-line comment - if (ch2 === "/") { - this.skip(this.input.length); // Skip to the EOL. - return commentToken("//", rest); - } - - var body = ""; - - /* Multi-line comment */ - if (ch2 === "*") { - this.skip(2); - - while (this.peek() !== "*" || this.peek(1) !== "/") { - if (this.peek() === "") { // End of Line - body += "\n"; - - // If we hit EOF and our comment is still unclosed, - // trigger an error and end the comment implicitly. - if (!this.nextLine()) { - this.trigger("error", { - code: "E017", - line: startLine, - character: startChar - }); - - return commentToken("/*", body, { - isMultiline: true, - isMalformed: true - }); - } - } else { - body += this.peek(); - this.skip(); - } - } - - this.skip(2); - return commentToken("/*", body, { isMultiline: true }); - } - }, - - /* - * Extract a keyword out of the next sequence of characters or - * return 'null' if its not possible. - */ - scanKeyword: function () { - var result = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(this.input); - var keywords = [ - "if", "in", "do", "var", "for", "new", - "try", "let", "this", "else", "case", - "void", "with", "enum", "while", "break", - "catch", "throw", "const", "yield", "class", - "super", "return", "typeof", "delete", - "switch", "export", "import", "default", - "finally", "extends", "function", "continue", - "debugger", "instanceof" - ]; - - if (result && keywords.indexOf(result[0]) >= 0) { - return { - type: Token.Keyword, - value: result[0] - }; - } - - return null; - }, - - /* - * Extract a JavaScript identifier out of the next sequence of - * characters or return 'null' if its not possible. In addition, - * to Identifier this method can also produce BooleanLiteral - * (true/false) and NullLiteral (null). - */ - scanIdentifier: function () { - var id = ""; - var index = 0; - var type, char; - - // Detects any character in the Unicode categories "Uppercase - // letter (Lu)", "Lowercase letter (Ll)", "Titlecase letter - // (Lt)", "Modifier letter (Lm)", "Other letter (Lo)", or - // "Letter number (Nl)". - // - // Both approach and unicodeLetterTable were borrowed from - // Google's Traceur. - - function isUnicodeLetter(code) { - for (var i = 0; i < unicodeLetterTable.length;) { - if (code < unicodeLetterTable[i++]) { - return false; - } - - if (code <= unicodeLetterTable[i++]) { - return true; - } - } - - return false; - } - - function isHexDigit(str) { - return (/^[0-9a-fA-F]$/).test(str); - } - - var readUnicodeEscapeSequence = function () { - /*jshint validthis:true */ - index += 1; - - if (this.peek(index) !== "u") { - return null; - } - - var ch1 = this.peek(index + 1); - var ch2 = this.peek(index + 2); - var ch3 = this.peek(index + 3); - var ch4 = this.peek(index + 4); - var code; - - if (isHexDigit(ch1) && isHexDigit(ch2) && isHexDigit(ch3) && isHexDigit(ch4)) { - code = parseInt(ch1 + ch2 + ch3 + ch4, 16); - - if (isUnicodeLetter(code)) { - index += 5; - return "\\u" + ch1 + ch2 + ch3 + ch4; - } - - return null; - } - - return null; - }.bind(this); - - var getIdentifierStart = function () { - /*jshint validthis:true */ - var chr = this.peek(index); - var code = chr.charCodeAt(0); - - if (code === 92) { - return readUnicodeEscapeSequence(); - } - - if (code < 128) { - if (identifierStartTable[code]) { - index += 1; - return chr; - } - - return null; - } - - if (isUnicodeLetter(code)) { - index += 1; - return chr; - } - - return null; - }.bind(this); - - var getIdentifierPart = function () { - /*jshint validthis:true */ - var chr = this.peek(index); - var code = chr.charCodeAt(0); - - if (code === 92) { - return readUnicodeEscapeSequence(); - } - - if (code < 128) { - if (identifierPartTable[code]) { - index += 1; - return chr; - } - - return null; - } - - if (isUnicodeLetter(code)) { - index += 1; - return chr; - } - - return null; - }.bind(this); - - char = getIdentifierStart(); - if (char === null) { - return null; - } - - id = char; - for (;;) { - char = getIdentifierPart(); - - if (char === null) { - break; - } - - id += char; - } - - switch (id) { - case "true": - case "false": - type = Token.BooleanLiteral; - break; - case "null": - type = Token.NullLiteral; - break; - default: - type = Token.Identifier; - } - - return { - type: type, - value: id - }; - }, - - /* - * Extract a numeric literal out of the next sequence of - * characters or return 'null' if its not possible. This method - * supports all numeric literals described in section 7.8.3 - * of the EcmaScript 5 specification. - * - * This method's implementation was heavily influenced by the - * scanNumericLiteral function in the Esprima parser's source code. - */ - scanNumericLiteral: function () { - var index = 0; - var value = ""; - var length = this.input.length; - var char = this.peek(index); - var bad; - - function isDecimalDigit(str) { - return (/^[0-9]$/).test(str); - } - - function isOctalDigit(str) { - return (/^[0-7]$/).test(str); - } - - function isHexDigit(str) { - return (/^[0-9a-fA-F]$/).test(str); - } - - function isIdentifierStart(ch) { - return (ch === "$") || (ch === "_") || (ch === "\\") || - (ch >= "a" && ch <= "z") || (ch >= "A" && ch <= "Z"); - } - - // Numbers must start either with a decimal digit or a point. - - if (char !== "." && !isDecimalDigit(char)) { - return null; - } - - if (char !== ".") { - value = this.peek(index); - index += 1; - char = this.peek(index); - - if (value === "0") { - // Base-16 numbers. - if (char === "x" || char === "X") { - index += 1; - value += char; - - while (index < length) { - char = this.peek(index); - if (!isHexDigit(char)) { - break; - } - value += char; - index += 1; - } - - if (value.length <= 2) { // 0x - return { - type: Token.NumericLiteral, - value: value, - isMalformed: true - }; - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 16, - isMalformed: false - }; - } - - // Base-8 numbers. - if (isOctalDigit(char)) { - index += 1; - value += char; - bad = false; - - while (index < length) { - char = this.peek(index); - - // Numbers like '019' (note the 9) are not valid octals - // but we still parse them and mark as malformed. - - if (isDecimalDigit(char)) { - bad = true; - } else if (!isOctalDigit(char)) { - break; - } - value += char; - index += 1; - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 8, - isMalformed: false - }; - } - - // Decimal numbers that start with '0' such as '09' are illegal - // but we still parse them and return as malformed. - - if (isDecimalDigit(char)) { - index += 1; - value += char; - } - } - - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } - - // Decimal digits. - - if (char === ".") { - value += char; - index += 1; - - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } - - // Exponent part. - - if (char === "e" || char === "E") { - value += char; - index += 1; - char = this.peek(index); - - if (char === "+" || char === "-") { - value += this.peek(index); - index += 1; - } - - char = this.peek(index); - if (isDecimalDigit(char)) { - value += char; - index += 1; - - while (index < length) { - char = this.peek(index); - if (!isDecimalDigit(char)) { - break; - } - value += char; - index += 1; - } - } else { - return null; - } - } - - if (index < length) { - char = this.peek(index); - if (isIdentifierStart(char)) { - return null; - } - } - - return { - type: Token.NumericLiteral, - value: value, - base: 10, - isMalformed: !isFinite(value) - }; - }, - - /* - * Extract a string out of the next sequence of characters and/or - * lines or return 'null' if its not possible. Since strings can - * span across multiple lines this method has to move the char - * pointer. - * - * This method recognizes pseudo-multiline JavaScript strings: - * - * var str = "hello\ - * world"; - */ - scanStringLiteral: function (checks) { - /*jshint loopfunc:true */ - var quote = this.peek(); - - // String must start with a quote. - if (quote !== "\"" && quote !== "'") { - return null; - } - - // In JSON strings must always use double quotes. - this.triggerAsync("warning", { - code: "W108", - line: this.line, - character: this.char // +1? - }, checks, function () { return state.jsonMode && quote !== "\""; }); - - var value = ""; - var startLine = this.line; - var startChar = this.char; - var allowNewLine = false; - - this.skip(); - - while (this.peek() !== quote) { - while (this.peek() === "") { // End Of Line - - // If an EOL is not preceded by a backslash, show a warning - // and proceed like it was a legit multi-line string where - // author simply forgot to escape the newline symbol. - // - // Another approach is to implicitly close a string on EOL - // but it generates too many false positives. - - if (!allowNewLine) { - this.trigger("warning", { - code: "W112", - line: this.line, - character: this.char - }); - } else { - allowNewLine = false; - - // Otherwise show a warning if multistr option was not set. - // For JSON, show warning no matter what. - - this.triggerAsync("warning", { - code: "W043", - line: this.line, - character: this.char - }, checks, function () { return !state.option.multistr; }); - - this.triggerAsync("warning", { - code: "W042", - line: this.line, - character: this.char - }, checks, function () { return state.jsonMode && state.option.multistr; }); - } - - // If we get an EOF inside of an unclosed string, show an - // error and implicitly close it at the EOF point. - - if (!this.nextLine()) { - this.trigger("error", { - code: "E029", - line: startLine, - character: startChar - }); - - return { - type: Token.StringLiteral, - value: value, - isUnclosed: true, - quote: quote - }; - } - } - - allowNewLine = false; - var char = this.peek(); - var jump = 1; // A length of a jump, after we're done - // parsing this character. - - if (char < " ") { - // Warn about a control character in a string. - this.trigger("warning", { - code: "W113", - line: this.line, - character: this.char, - data: [ "" ] - }); - } - - // Special treatment for some escaped characters. - - if (char === "\\") { - this.skip(); - char = this.peek(); - - switch (char) { - case "'": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\'" ] - }, checks, function () {return state.jsonMode; }); - break; - case "b": - char = "\b"; - break; - case "f": - char = "\f"; - break; - case "n": - char = "\n"; - break; - case "r": - char = "\r"; - break; - case "t": - char = "\t"; - break; - case "0": - char = "\0"; - - // Octal literals fail in strict mode. - // Check if the number is between 00 and 07. - var n = parseInt(this.peek(1), 10); - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, - function () { return n >= 0 && n <= 7 && state.directive["use strict"]; }); - break; - case "u": - char = String.fromCharCode(parseInt(this.input.substr(1, 4), 16)); - jump = 5; - break; - case "v": - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\v" ] - }, checks, function () { return state.jsonMode; }); - - char = "\v"; - break; - case "x": - var x = parseInt(this.input.substr(1, 2), 16); - - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "\\x-" ] - }, checks, function () { return state.jsonMode; }); - - char = String.fromCharCode(x); - jump = 3; - break; - case "\\": - case "\"": - case "/": - break; - case "": - allowNewLine = true; - char = ""; - break; - case "!": - if (value.slice(value.length - 2) === "<") { - break; - } - - /*falls through */ - default: - // Weird escaping. - this.trigger("warning", { - code: "W044", - line: this.line, - character: this.char - }); - } - } - - value += char; - this.skip(jump); - } - - this.skip(); - return { - type: Token.StringLiteral, - value: value, - isUnclosed: false, - quote: quote - }; - }, - - /* - * Extract a regular expression out of the next sequence of - * characters and/or lines or return 'null' if its not possible. - * - * This method is platform dependent: it accepts almost any - * regular expression values but then tries to compile and run - * them using system's RegExp object. This means that there are - * rare edge cases where one JavaScript engine complains about - * your regular expression while others don't. - */ - scanRegExp: function () { - var index = 0; - var length = this.input.length; - var char = this.peek(); - var value = char; - var body = ""; - var flags = []; - var malformed = false; - var isCharSet = false; - var terminated; - - var scanUnexpectedChars = function () { - // Unexpected control character - if (char < " ") { - malformed = true; - this.trigger("warning", { - code: "W048", - line: this.line, - character: this.char - }); - } - - // Unexpected escaped character - if (char === "<") { - malformed = true; - this.trigger("warning", { - code: "W049", - line: this.line, - character: this.char, - data: [ char ] - }); - } - }.bind(this); - - // Regular expressions must start with '/' - if (!this.prereg || char !== "/") { - return null; - } - - index += 1; - terminated = false; - - // Try to get everything in between slashes. A couple of - // cases aside (see scanUnexpectedChars) we don't really - // care whether the resulting expression is valid or not. - // We will check that later using the RegExp object. - - while (index < length) { - char = this.peek(index); - value += char; - body += char; - - if (isCharSet) { - if (char === "]") { - if (this.peek(index - 1) !== "\\" || this.peek(index - 2) === "\\") { - isCharSet = false; - } - } - - if (char === "\\") { - index += 1; - char = this.peek(index); - body += char; - value += char; - - scanUnexpectedChars(); - } - - index += 1; - continue; - } - - if (char === "\\") { - index += 1; - char = this.peek(index); - body += char; - value += char; - - scanUnexpectedChars(); - - if (char === "/") { - index += 1; - continue; - } - - if (char === "[") { - index += 1; - continue; - } - } - - if (char === "[") { - isCharSet = true; - index += 1; - continue; - } - - if (char === "/") { - body = body.substr(0, body.length - 1); - terminated = true; - index += 1; - break; - } - - index += 1; - } - - // A regular expression that was never closed is an - // error from which we cannot recover. - - if (!terminated) { - this.trigger("error", { - code: "E015", - line: this.line, - character: this.from - }); - - return void this.trigger("fatal", { - line: this.line, - from: this.from - }); - } - - // Parse flags (if any). - - while (index < length) { - char = this.peek(index); - if (!/[gim]/.test(char)) { - break; - } - flags.push(char); - value += char; - index += 1; - } - - // Check regular expression for correctness. - - try { - new RegExp(body, flags.join("")); - } catch (err) { - malformed = true; - this.trigger("error", { - code: "E016", - line: this.line, - character: this.char, - data: [ err.message ] // Platform dependent! - }); - } - - return { - type: Token.RegExp, - value: value, - flags: flags, - isMalformed: malformed - }; - }, - - /* - * Scan for any occurence of mixed tabs and spaces. If smarttabs option - * is on, ignore tabs followed by spaces. - * - * Tabs followed by one space followed by a block comment are allowed. - */ - scanMixedSpacesAndTabs: function () { - var at, match; - - if (state.option.smarttabs) { - // Negative look-behind for "//" - match = this.input.match(/(\/\/|^\s?\*)? \t/); - at = match && !match[1] ? 0 : -1; - } else { - at = this.input.search(/ \t|\t [^\*]/); - } - - return at; - }, - - /* - * Scan for characters that get silently deleted by one or more browsers. - */ - scanUnsafeChars: function () { - return this.input.search(reg.unsafeChars); - }, - - /* - * Produce the next raw token or return 'null' if no tokens can be matched. - * This method skips over all space characters. - */ - next: function (checks) { - this.from = this.char; - - // Move to the next non-space character. - var start; - if (/\s/.test(this.peek())) { - start = this.char; - - while (/\s/.test(this.peek())) { - this.from += 1; - this.skip(); - } - - if (this.peek() === "") { // EOL - if (!/^\s*$/.test(this.lines[this.line - 1]) && state.option.trailing) { - this.trigger("warning", { code: "W102", line: this.line, character: start }); - } - } - } - - // Methods that work with multi-line structures and move the - // character pointer. - - var match = this.scanComments() || - this.scanStringLiteral(checks); - - if (match) { - return match; - } - - // Methods that don't move the character pointer. - - match = - this.scanRegExp() || - this.scanPunctuator() || - this.scanKeyword() || - this.scanIdentifier() || - this.scanNumericLiteral(); - - if (match) { - this.skip(match.value.length); - return match; - } - - // No token could be matched, give up. - - return null; - }, - - /* - * Switch to the next line and reset all char pointers. Once - * switched, this method also checks for mixed spaces and tabs - * and other minor warnings. - */ - nextLine: function () { - var char; - - if (this.line >= this.lines.length) { - return false; - } - - this.input = this.lines[this.line]; - this.line += 1; - this.char = 1; - this.from = 1; - - char = this.scanMixedSpacesAndTabs(); - if (char >= 0) { - this.trigger("warning", { code: "W099", line: this.line, character: char + 1 }); - } - - this.input = this.input.replace(/\t/g, state.tab); - char = this.scanUnsafeChars(); - - if (char >= 0) { - this.trigger("warning", { code: "W100", line: this.line, character: char }); - } - - // If there is a limit on line length, warn when lines get too - // long. - - if (state.option.maxlen && state.option.maxlen < this.input.length) { - this.trigger("warning", { code: "W101", line: this.line, character: this.input.length }); - } - - return true; - }, - - /* - * This is simply a synonym for nextLine() method with a friendlier - * public name. - */ - start: function () { - this.nextLine(); - }, - - /* - * Produce the next token. This function is called by advance() to get - * the next token. It retuns a token in a JSLint-compatible format. - */ - token: function () { - /*jshint loopfunc:true */ - var checks = asyncTrigger(); - var token; - - - function isReserved(token, isProperty) { - if (!token.reserved) { - return false; - } - - if (token.meta && token.meta.isFutureReservedWord) { - // ES3 FutureReservedWord in an ES5 environment. - if (state.option.inES5(true) && !token.meta.es5) { - return false; - } - - // Some ES5 FutureReservedWord identifiers are active only - // within a strict mode environment. - if (token.meta.strictOnly) { - if (!state.option.strict && !state.directive["use strict"]) { - return false; - } - } - - if (isProperty) { - return false; - } - } - - return true; - } - - // Produce a token object. - var create = function (type, value, isProperty) { - /*jshint validthis:true */ - var obj; - - if (type !== "(endline)" && type !== "(end)") { - this.prereg = false; - } - - if (type === "(punctuator)") { - switch (value) { - case ".": - case ")": - case "~": - case "#": - case "]": - this.prereg = false; - break; - default: - this.prereg = true; - } - - obj = Object.create(state.syntax[value] || state.syntax["(error)"]); - } - - if (type === "(identifier)") { - if (value === "return" || value === "case" || value === "typeof") { - this.prereg = true; - } - - if (_.has(state.syntax, value)) { - obj = Object.create(state.syntax[value] || state.syntax["(error)"]); - - // If this can't be a reserved keyword, reset the object. - if (!isReserved(obj, isProperty && type === "(identifier)")) { - obj = null; - } - } - } - - if (!obj) { - obj = Object.create(state.syntax[type]); - } - - obj.identifier = (type === "(identifier)"); - obj.type = obj.type || type; - obj.value = value; - obj.line = this.line; - obj.character = this.char; - obj.from = this.from; - - if (isProperty && obj.identifier) { - obj.isProperty = isProperty; - } - - obj.check = checks.check; - - return obj; - }.bind(this); - - for (;;) { - if (!this.input.length) { - return create(this.nextLine() ? "(endline)" : "(end)", ""); - } - - token = this.next(checks); - - if (!token) { - if (this.input.length) { - // Unexpected character. - this.trigger("error", { - code: "E024", - line: this.line, - character: this.char, - data: [ this.peek() ] - }); - - this.input = ""; - } - - continue; - } - - switch (token.type) { - case Token.StringLiteral: - this.triggerAsync("String", { - line: this.line, - char: this.char, - from: this.from, - value: token.value, - quote: token.quote - }, checks, function () { return true; }); - - return create("(string)", token.value); - case Token.Identifier: - this.trigger("Identifier", { - line: this.line, - char: this.char, - from: this.form, - name: token.value, - isProperty: state.tokens.curr.id === "." - }); - - /* falls through */ - case Token.Keyword: - case Token.NullLiteral: - case Token.BooleanLiteral: - return create("(identifier)", token.value, state.tokens.curr.id === "."); - - case Token.NumericLiteral: - if (token.isMalformed) { - this.trigger("warning", { - code: "W045", - line: this.line, - character: this.char, - data: [ token.value ] - }); - } - - this.triggerAsync("warning", { - code: "W114", - line: this.line, - character: this.char, - data: [ "0x-" ] - }, checks, function () { return token.base === 16 && state.jsonMode; }); - - this.triggerAsync("warning", { - code: "W115", - line: this.line, - character: this.char - }, checks, function () { - return state.directive["use strict"] && token.base === 8; - }); - - this.trigger("Number", { - line: this.line, - char: this.char, - from: this.from, - value: token.value, - base: token.base, - isMalformed: token.malformed - }); - - return create("(number)", token.value); - - case Token.RegExp: - return create("(regexp)", token.value); - - case Token.Comment: - state.tokens.curr.comment = true; - - if (token.isSpecial) { - return { - value: token.value, - body: token.body, - type: token.commentType, - isSpecial: token.isSpecial, - line: this.line, - character: this.char, - from: this.from - }; - } - - break; - - case "": - break; - - default: - return create("(punctuator)", token.value); - } - } - } -}; - -exports.Lexer = Lexer; - -})() -},{"events":2,"./reg.js":6,"./state.js":4,"underscore":11}],"jshint":[function(require,module,exports){ -module.exports=require('E/GbHF'); -},{}],"E/GbHF":[function(require,module,exports){ -(function(){/*! - * JSHint, by JSHint Community. - * - * This file (and this file only) is licensed under the same slightly modified - * MIT license that JSLint is. It stops evil-doers everywhere: - * - * Copyright (c) 2002 Douglas Crockford (www.JSLint.com) - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, including without limitation - * the rights to use, copy, modify, merge, publish, distribute, sublicense, - * and/or sell copies of the Software, and to permit persons to whom - * the Software is furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included - * in all copies or substantial portions of the Software. - * - * The Software shall be used for Good, not Evil. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - * - */ - -/*jshint quotmark:double */ -/*global console:true */ -/*exported console */ - -var _ = require("underscore"); -var events = require("events"); -var vars = require("../shared/vars.js"); -var messages = require("../shared/messages.js"); -var Lexer = require("./lex.js").Lexer; -var reg = require("./reg.js"); -var state = require("./state.js").state; -var style = require("./style.js"); - -// We need this module here because environments such as IE and Rhino -// don't necessarilly expose the 'console' API and browserify uses -// it to log things. It's a sad state of affair, really. -var console = require("console-browserify"); - -// We build the application inside a function so that we produce only a singleton -// variable. That function will be invoked immediately, and its return value is -// the JSHINT function itself. - -var JSHINT = (function () { - "use strict"; - - var anonname, // The guessed name for anonymous functions. - api, // Extension API - - // These are operators that should not be used with the ! operator. - bang = { - "<" : true, - "<=" : true, - "==" : true, - "===": true, - "!==": true, - "!=" : true, - ">" : true, - ">=" : true, - "+" : true, - "-" : true, - "*" : true, - "/" : true, - "%" : true - }, - - // These are the JSHint boolean options. - boolOptions = { - asi : true, // if automatic semicolon insertion should be tolerated - bitwise : true, // if bitwise operators should not be allowed - boss : true, // if advanced usage of assignments should be allowed - browser : true, // if the standard browser globals should be predefined - camelcase : true, // if identifiers should be required in camel case - couch : true, // if CouchDB globals should be predefined - curly : true, // if curly braces around all blocks should be required - debug : true, // if debugger statements should be allowed - devel : true, // if logging globals should be predefined (console, alert, etc.) - dojo : true, // if Dojo Toolkit globals should be predefined - eqeqeq : true, // if === should be required - eqnull : true, // if == null comparisons should be tolerated - es3 : true, // if ES3 syntax should be allowed - es5 : true, // if ES5 syntax should be allowed (is now set per default) - esnext : true, // if es.next specific syntax should be allowed - moz : true, // if mozilla specific syntax should be allowed - evil : true, // if eval should be allowed - expr : true, // if ExpressionStatement should be allowed as Programs - forin : true, // if for in statements must filter - funcscope : true, // if only function scope should be used for scope tests - gcl : true, // if JSHint should be compatible with Google Closure Linter - globalstrict: true, // if global "use strict"; should be allowed (also enables 'strict') - immed : true, // if immediate invocations must be wrapped in parens - iterator : true, // if the `__iterator__` property should be allowed - jquery : true, // if jQuery globals should be predefined - lastsemic : true, // if semicolons may be ommitted for the trailing - // statements inside of a one-line blocks. - laxbreak : true, // if line breaks should not be checked - laxcomma : true, // if line breaks should not be checked around commas - loopfunc : true, // if functions should be allowed to be defined within - // loops - mootools : true, // if MooTools globals should be predefined - multistr : true, // allow multiline strings - newcap : true, // if constructor names must be capitalized - noarg : true, // if arguments.caller and arguments.callee should be - // disallowed - node : true, // if the Node.js environment globals should be - // predefined - noempty : true, // if empty blocks should be disallowed - nonew : true, // if using `new` for side-effects should be disallowed - nonstandard : true, // if non-standard (but widely adopted) globals should - // be predefined - nomen : true, // if names should be checked - onevar : true, // if only one var statement per function should be - // allowed - passfail : true, // if the scan should stop on first error - phantom : true, // if PhantomJS symbols should be allowed - plusplus : true, // if increment/decrement should not be allowed - proto : true, // if the `__proto__` property should be allowed - prototypejs : true, // if Prototype and Scriptaculous globals should be - // predefined - rhino : true, // if the Rhino environment globals should be predefined - undef : true, // if variables should be declared before used - scripturl : true, // if script-targeted URLs should be tolerated - shadow : true, // if variable shadowing should be tolerated - smarttabs : true, // if smarttabs should be tolerated - // (http://www.emacswiki.org/emacs/SmartTabs) - strict : true, // require the "use strict"; pragma - sub : true, // if all forms of subscript notation are tolerated - supernew : true, // if `new function () { ... };` and `new Object;` - // should be tolerated - trailing : true, // if trailing whitespace rules apply - validthis : true, // if 'this' inside a non-constructor function is valid. - // This is a function scoped option only. - withstmt : true, // if with statements should be allowed - white : true, // if strict whitespace rules apply - worker : true, // if Web Worker script symbols should be allowed - wsh : true, // if the Windows Scripting Host environment globals - // should be predefined - yui : true, // YUI variables should be predefined - - // Obsolete options - onecase : true, // if one case switch statements should be allowed - regexp : true, // if the . should not be allowed in regexp literals - regexdash : true // if unescaped first/last dash (-) inside brackets - // should be tolerated - }, - - // These are the JSHint options that can take any value - // (we use this object to detect invalid options) - valOptions = { - maxlen : false, - indent : false, - maxerr : false, - predef : false, - quotmark : false, //'single'|'double'|true - scope : false, - maxstatements: false, // {int} max statements per function - maxdepth : false, // {int} max nested block depth per function - maxparams : false, // {int} max params per function - maxcomplexity: false, // {int} max cyclomatic complexity per function - unused : true, // warn if variables are unused. Available options: - // false - don't check for unused variables - // true - "vars" + check last function param - // "vars" - skip checking unused function params - // "strict" - "vars" + check all function params - latedef : false // warn if the variable is used before its definition - // false - don't emit any warnings - // true - warn if any variable is used before its definition - // "nofunc" - warn for any variable but function declarations - }, - - // These are JSHint boolean options which are shared with JSLint - // where the definition in JSHint is opposite JSLint - invertedOptions = { - bitwise : true, - forin : true, - newcap : true, - nomen : true, - plusplus: true, - regexp : true, - undef : true, - white : true, - - // Inverted and renamed, use JSHint name here - eqeqeq : true, - onevar : true, - strict : true - }, - - // These are JSHint boolean options which are shared with JSLint - // where the name has been changed but the effect is unchanged - renamedOptions = { - eqeq : "eqeqeq", - vars : "onevar", - windows: "wsh", - sloppy : "strict" - }, - - declared, // Globals that were declared using /*global ... */ syntax. - exported, // Variables that are used outside of the current file. - - functionicity = [ - "closure", "exception", "global", "label", - "outer", "unused", "var" - ], - - funct, // The current function - functions, // All of the functions - - global, // The global scope - implied, // Implied globals - inblock, - indent, - lookahead, - lex, - member, - membersOnly, - noreach, - predefined, // Global variables defined by option - - scope, // The current scope - stack, - unuseds, - urls, - warnings, - - extraModules = [], - emitter = new events.EventEmitter(); - - function checkOption(name, t) { - name = name.trim(); - - if (/^[+-]W\d{3}$/g.test(name)) { - return true; - } - - if (valOptions[name] === undefined && boolOptions[name] === undefined) { - if (t.type !== "jslint") { - error("E001", t, name); - return false; - } - } - - return true; - } - - function isString(obj) { - return Object.prototype.toString.call(obj) === "[object String]"; - } - - function isIdentifier(tkn, value) { - if (!tkn) - return false; - - if (!tkn.identifier || tkn.value !== value) - return false; - - return true; - } - - function isReserved(token) { - if (!token.reserved) { - return false; - } - - if (token.meta && token.meta.isFutureReservedWord) { - // ES3 FutureReservedWord in an ES5 environment. - if (state.option.inES5(true) && !token.meta.es5) { - return false; - } - - // Some ES5 FutureReservedWord identifiers are active only - // within a strict mode environment. - if (token.meta.strictOnly) { - if (!state.option.strict && !state.directive["use strict"]) { - return false; - } - } - - if (token.isProperty) { - return false; - } - } - - return true; - } - - function supplant(str, data) { - return str.replace(/\{([^{}]*)\}/g, function (a, b) { - var r = data[b]; - return typeof r === "string" || typeof r === "number" ? r : a; - }); - } - - function combine(t, o) { - var n; - for (n in o) { - if (_.has(o, n) && !_.has(JSHINT.blacklist, n)) { - t[n] = o[n]; - } - } - } - - function updatePredefined() { - Object.keys(JSHINT.blacklist).forEach(function (key) { - delete predefined[key]; - }); - } - - function assume() { - if (state.option.es5) { - warning("I003"); - } - if (state.option.couch) { - combine(predefined, vars.couch); - } - - if (state.option.rhino) { - combine(predefined, vars.rhino); - } - - if (state.option.phantom) { - combine(predefined, vars.phantom); - } - - if (state.option.prototypejs) { - combine(predefined, vars.prototypejs); - } - - if (state.option.node) { - combine(predefined, vars.node); - } - - if (state.option.devel) { - combine(predefined, vars.devel); - } - - if (state.option.dojo) { - combine(predefined, vars.dojo); - } - - if (state.option.browser) { - combine(predefined, vars.browser); - } - - if (state.option.nonstandard) { - combine(predefined, vars.nonstandard); - } - - if (state.option.jquery) { - combine(predefined, vars.jquery); - } - - if (state.option.mootools) { - combine(predefined, vars.mootools); - } - - if (state.option.worker) { - combine(predefined, vars.worker); - } - - if (state.option.wsh) { - combine(predefined, vars.wsh); - } - - if (state.option.globalstrict && state.option.strict !== false) { - state.option.strict = true; - } - - if (state.option.yui) { - combine(predefined, vars.yui); - } - - // Let's assume that chronologically ES3 < ES5 < ES6/ESNext < Moz - - state.option.inMoz = function (strict) { - if (strict) { - return state.option.moz && !state.option.esnext; - } - return state.option.moz; - }; - - state.option.inESNext = function (strict) { - if (strict) { - return !state.option.moz && state.option.esnext; - } - return state.option.moz || state.option.esnext; - }; - - state.option.inES5 = function (/* strict */) { - return !state.option.es3; - }; - - state.option.inES3 = function (strict) { - if (strict) { - return !state.option.moz && !state.option.esnext && state.option.es3; - } - return state.option.es3; - }; - } - - // Produce an error warning. - function quit(code, line, chr) { - var percentage = Math.floor((line / state.lines.length) * 100); - var message = messages.errors[code].desc; - - throw { - name: "JSHintError", - line: line, - character: chr, - message: message + " (" + percentage + "% scanned).", - raw: message - }; - } - - function isundef(scope, code, token, a) { - return JSHINT.undefs.push([scope, code, token, a]); - } - - function warning(code, t, a, b, c, d) { - var ch, l, w, msg; - - if (/^W\d{3}$/.test(code)) { - if (state.ignored[code]) - return; - - msg = messages.warnings[code]; - } else if (/E\d{3}/.test(code)) { - msg = messages.errors[code]; - } else if (/I\d{3}/.test(code)) { - msg = messages.info[code]; - } - - t = t || state.tokens.next; - if (t.id === "(end)") { // `~ - t = state.tokens.curr; - } - - l = t.line || 0; - ch = t.from || 0; - - w = { - id: "(error)", - raw: msg.desc, - code: msg.code, - evidence: state.lines[l - 1] || "", - line: l, - character: ch, - scope: JSHINT.scope, - a: a, - b: b, - c: c, - d: d - }; - - w.reason = supplant(msg.desc, w); - JSHINT.errors.push(w); - - if (state.option.passfail) { - quit("E042", l, ch); - } - - warnings += 1; - if (warnings >= state.option.maxerr) { - quit("E043", l, ch); - } - - return w; - } - - function warningAt(m, l, ch, a, b, c, d) { - return warning(m, { - line: l, - from: ch - }, a, b, c, d); - } - - function error(m, t, a, b, c, d) { - warning(m, t, a, b, c, d); - } - - function errorAt(m, l, ch, a, b, c, d) { - return error(m, { - line: l, - from: ch - }, a, b, c, d); - } - - // Tracking of "internal" scripts, like eval containing a static string - function addInternalSrc(elem, src) { - var i; - i = { - id: "(internal)", - elem: elem, - value: src - }; - JSHINT.internals.push(i); - return i; - } - - function addlabel(t, type, tkn, islet) { - // Define t in the current function in the current scope. - if (type === "exception") { - if (_.has(funct["(context)"], t)) { - if (funct[t] !== true && !state.option.node) { - warning("W002", state.tokens.next, t); - } - } - } - - if (_.has(funct, t) && !funct["(global)"]) { - if (funct[t] === true) { - if (state.option.latedef) { - if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || - !_.contains([funct[t], type], "unction")) { - warning("W003", state.tokens.next, t); - } - } - } else { - if (!state.option.shadow && type !== "exception" || - (funct["(blockscope)"].getlabel(t))) { - warning("W004", state.tokens.next, t); - } - } - } - - // a double definition of a let variable in same block throws a TypeError - //if (funct["(blockscope)"] && funct["(blockscope)"].current.has(t)) { - // error("E044", state.tokens.next, t); - //} - - // if the identifier is from a let, adds it only to the current blockscope - if (islet) { - funct["(blockscope)"].current.add(t, type, state.tokens.curr); - } else { - - funct[t] = type; - - if (tkn) { - funct["(tokens)"][t] = tkn; - } - - if (funct["(global)"]) { - global[t] = funct; - if (_.has(implied, t)) { - if (state.option.latedef) { - if ((state.option.latedef === true && _.contains([funct[t], type], "unction")) || - !_.contains([funct[t], type], "unction")) { - warning("W003", state.tokens.next, t); - } - } - - delete implied[t]; - } - } else { - scope[t] = funct; - } - } - } - - function doOption() { - var nt = state.tokens.next; - var body = nt.body.split(",").map(function (s) { return s.trim(); }); - var predef = {}; - - if (nt.type === "globals") { - body.forEach(function (g) { - g = g.split(":"); - var key = g[0]; - var val = g[1]; - - if (key.charAt(0) === "-") { - key = key.slice(1); - val = false; - - JSHINT.blacklist[key] = key; - updatePredefined(); - } else { - predef[key] = (val === "true"); - } - }); - - combine(predefined, predef); - - for (var key in predef) { - if (_.has(predef, key)) { - declared[key] = nt; - } - } - } - - if (nt.type === "exported") { - body.forEach(function (e) { - exported[e] = true; - }); - } - - if (nt.type === "members") { - membersOnly = membersOnly || {}; - - body.forEach(function (m) { - var ch1 = m.charAt(0); - var ch2 = m.charAt(m.length - 1); - - if (ch1 === ch2 && (ch1 === "\"" || ch1 === "'")) { - m = m - .substr(1, m.length - 2) - .replace("\\b", "\b") - .replace("\\t", "\t") - .replace("\\n", "\n") - .replace("\\v", "\v") - .replace("\\f", "\f") - .replace("\\r", "\r") - .replace("\\\\", "\\") - .replace("\\\"", "\""); - } - - membersOnly[m] = false; - }); - } - - var numvals = [ - "maxstatements", - "maxparams", - "maxdepth", - "maxcomplexity", - "maxerr", - "maxlen", - "indent" - ]; - - if (nt.type === "jshint" || nt.type === "jslint") { - body.forEach(function (g) { - g = g.split(":"); - var key = (g[0] || "").trim(); - var val = (g[1] || "").trim(); - - if (!checkOption(key, nt)) { - return; - } - - if (numvals.indexOf(key) >= 0) { - - // GH988 - numeric options can be disabled by setting them to `false` - if (val !== "false") { - val = +val; - - if (typeof val !== "number" || !isFinite(val) || val <= 0 || Math.floor(val) !== val) { - error("E032", nt, g[1].trim()); - return; - } - - if (key === "indent") { - state.option["(explicitIndent)"] = true; - } - state.option[key] = val; - } else { - if (key === "indent") { - state.option["(explicitIndent)"] = false; - } else { - state.option[key] = false; - } - } - - return; - } - - if (key === "validthis") { - // `validthis` is valid only within a function scope. - if (funct["(global)"]) { - error("E009"); - } else { - if (val === "true" || val === "false") { - state.option.validthis = (val === "true"); - } else { - error("E002", nt); - } - } - return; - } - - if (key === "quotmark") { - switch (val) { - case "true": - case "false": - state.option.quotmark = (val === "true"); - break; - case "double": - case "single": - state.option.quotmark = val; - break; - default: - error("E002", nt); - } - return; - } - - if (key === "unused") { - switch (val) { - case "true": - state.option.unused = true; - break; - case "false": - state.option.unused = false; - break; - case "vars": - case "strict": - state.option.unused = val; - break; - default: - error("E002", nt); - } - return; - } - - if (key === "latedef") { - switch (val) { - case "true": - state.option.latedef = true; - break; - case "false": - state.option.latedef = false; - break; - case "nofunc": - state.option.latedef = "nofunc"; - break; - default: - error("E002", nt); - } - return; - } - - var match = /^([+-])(W\d{3})$/g.exec(key); - if (match) { - // ignore for -W..., unignore for +W... - state.ignored[match[2]] = (match[1] === "-"); - return; - } - - var tn; - if (val === "true" || val === "false") { - if (nt.type === "jslint") { - tn = renamedOptions[key] || key; - state.option[tn] = (val === "true"); - - if (invertedOptions[tn] !== undefined) { - state.option[tn] = !state.option[tn]; - } - } else { - state.option[key] = (val === "true"); - } - - if (key === "newcap") { - state.option["(explicitNewcap)"] = true; - } - return; - } - - error("E002", nt); - }); - - assume(); - } - } - - // We need a peek function. If it has an argument, it peeks that much farther - // ahead. It is used to distinguish - // for ( var i in ... - // from - // for ( var i = ... - - function peek(p) { - var i = p || 0, j = 0, t; - - while (j <= i) { - t = lookahead[j]; - if (!t) { - t = lookahead[j] = lex.token(); - } - j += 1; - } - return t; - } - - // Produce the next token. It looks for programming errors. - - function advance(id, t) { - switch (state.tokens.curr.id) { - case "(number)": - if (state.tokens.next.id === ".") { - warning("W005", state.tokens.curr); - } - break; - case "-": - if (state.tokens.next.id === "-" || state.tokens.next.id === "--") { - warning("W006"); - } - break; - case "+": - if (state.tokens.next.id === "+" || state.tokens.next.id === "++") { - warning("W007"); - } - break; - } - - if (state.tokens.curr.type === "(string)" || state.tokens.curr.identifier) { - anonname = state.tokens.curr.value; - } - - if (id && state.tokens.next.id !== id) { - if (t) { - if (state.tokens.next.id === "(end)") { - error("E019", t, t.id); - } else { - error("E020", state.tokens.next, id, t.id, t.line, state.tokens.next.value); - } - } else if (state.tokens.next.type !== "(identifier)" || state.tokens.next.value !== id) { - warning("W116", state.tokens.next, id, state.tokens.next.value); - } - } - - state.tokens.prev = state.tokens.curr; - state.tokens.curr = state.tokens.next; - for (;;) { - state.tokens.next = lookahead.shift() || lex.token(); - - if (!state.tokens.next) { // No more tokens left, give up - quit("E041", state.tokens.curr.line); - } - - if (state.tokens.next.id === "(end)" || state.tokens.next.id === "(error)") { - return; - } - - if (state.tokens.next.check) { - state.tokens.next.check(); - } - - if (state.tokens.next.isSpecial) { - doOption(); - } else { - if (state.tokens.next.id !== "(endline)") { - break; - } - } - } - } - - // This is the heart of JSHINT, the Pratt parser. In addition to parsing, it - // is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is - // like .nud except that it is only used on the first token of a statement. - // Having .fud makes it much easier to define statement-oriented languages like - // JavaScript. I retained Pratt's nomenclature. - - // .nud Null denotation - // .fud First null denotation - // .led Left denotation - // lbp Left binding power - // rbp Right binding power - - // They are elements of the parsing method called Top Down Operator Precedence. - - function expression(rbp, initial) { - var left, isArray = false, isObject = false, isLetExpr = false; - - // if current expression is a let expression - if (!initial && state.tokens.next.value === "let" && peek(0).value === "(") { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.next, "let expressions"); - } - isLetExpr = true; - // create a new block scope we use only for the current expression - funct["(blockscope)"].stack(); - advance("let"); - advance("("); - state.syntax["let"].fud.call(state.syntax["let"].fud, false); - advance(")"); - } - - if (state.tokens.next.id === "(end)") - error("E006", state.tokens.curr); - - advance(); - - if (initial) { - anonname = "anonymous"; - funct["(verb)"] = state.tokens.curr.value; - } - - if (initial === true && state.tokens.curr.fud) { - left = state.tokens.curr.fud(); - } else { - if (state.tokens.curr.nud) { - left = state.tokens.curr.nud(); - } else { - error("E030", state.tokens.curr, state.tokens.curr.id); - } - - var end_of_expr = state.tokens.next.identifier && - !state.tokens.curr.led && - state.tokens.curr.line !== state.tokens.next.line; - while (rbp < state.tokens.next.lbp && !end_of_expr) { - isArray = state.tokens.curr.value === "Array"; - isObject = state.tokens.curr.value === "Object"; - - // #527, new Foo.Array(), Foo.Array(), new Foo.Object(), Foo.Object() - // Line breaks in IfStatement heads exist to satisfy the checkJSHint - // "Line too long." error. - if (left && (left.value || (left.first && left.first.value))) { - // If the left.value is not "new", or the left.first.value is a "." - // then safely assume that this is not "new Array()" and possibly - // not "new Object()"... - if (left.value !== "new" || - (left.first && left.first.value && left.first.value === ".")) { - isArray = false; - // ...In the case of Object, if the left.value and state.tokens.curr.value - // are not equal, then safely assume that this not "new Object()" - if (left.value !== state.tokens.curr.value) { - isObject = false; - } - } - } - - advance(); - - if (isArray && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { - warning("W009", state.tokens.curr); - } - - if (isObject && state.tokens.curr.id === "(" && state.tokens.next.id === ")") { - warning("W010", state.tokens.curr); - } - - if (left && state.tokens.curr.led) { - left = state.tokens.curr.led(left); - } else { - error("E033", state.tokens.curr, state.tokens.curr.id); - } - } - } - if (isLetExpr) { - funct["(blockscope)"].unstack(); - } - return left; - } - - -// Functions for conformance of style. - - function adjacent(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (state.option.white) { - if (left.character !== right.from && left.line === right.line) { - left.from += (left.character - left.from); - warning("W011", left, left.value); - } - } - } - - function nobreak(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (state.option.white && (left.character !== right.from || left.line !== right.line)) { - warning("W012", right, right.value); - } - } - - function nospace(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (state.option.white && !left.comment) { - if (left.line === right.line) { - adjacent(left, right); - } - } - } - - function nonadjacent(left, right) { - if (state.option.white) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - - if (left.value === ";" && right.value === ";") { - return; - } - - if (left.line === right.line && left.character === right.from) { - left.from += (left.character - left.from); - warning("W013", left, left.value); - } - } - } - - function nobreaknonadjacent(left, right) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (!state.option.laxbreak && left.line !== right.line) { - warning("W014", right, right.id); - } else if (state.option.white) { - left = left || state.tokens.curr; - right = right || state.tokens.next; - if (left.character === right.from) { - left.from += (left.character - left.from); - warning("W013", left, left.value); - } - } - } - - function indentation(bias) { - if (!state.option.white && !state.option["(explicitIndent)"]) { - return; - } - - if (state.tokens.next.id === "(end)") { - return; - } - - var i = indent + (bias || 0); - if (state.tokens.next.from !== i) { - warning("W015", state.tokens.next, state.tokens.next.value, i, state.tokens.next.from); - } - } - - function nolinebreak(t) { - t = t || state.tokens.curr; - if (t.line !== state.tokens.next.line) { - warning("E022", t, t.value); - } - } - - - function comma(opts) { - opts = opts || {}; - - if (!opts.peek) { - if (state.tokens.curr.line !== state.tokens.next.line) { - if (!state.option.laxcomma) { - if (comma.first) { - warning("I001"); - comma.first = false; - } - warning("W014", state.tokens.curr, state.tokens.next.value); - } - } else if (!state.tokens.curr.comment && - state.tokens.curr.character !== state.tokens.next.from && state.option.white) { - state.tokens.curr.from += (state.tokens.curr.character - state.tokens.curr.from); - warning("W011", state.tokens.curr, state.tokens.curr.value); - } - - advance(","); - } - - // TODO: This is a temporary solution to fight against false-positives in - // arrays and objects with trailing commas (see GH-363). The best solution - // would be to extract all whitespace rules out of parser. - - if (state.tokens.next.value !== "]" && state.tokens.next.value !== "}") { - nonadjacent(state.tokens.curr, state.tokens.next); - } - - if (state.tokens.next.identifier && !(opts.property && state.option.inES5())) { - // Keywords that cannot follow a comma operator. - switch (state.tokens.next.value) { - case "break": - case "case": - case "catch": - case "continue": - case "default": - case "do": - case "else": - case "finally": - case "for": - case "if": - case "in": - case "instanceof": - case "return": - case "yield": - case "switch": - case "throw": - case "try": - case "var": - case "let": - case "while": - case "with": - error("E024", state.tokens.next, state.tokens.next.value); - return false; - } - } - - if (state.tokens.next.type === "(punctuator)") { - switch (state.tokens.next.value) { - case "}": - case "]": - case ",": - if (opts.allowTrailing) { - return true; - } - - /* falls through */ - case ")": - error("E024", state.tokens.next, state.tokens.next.value); - return false; - } - } - return true; - } - - // Functional constructors for making the symbols that will be inherited by - // tokens. - - function symbol(s, p) { - var x = state.syntax[s]; - if (!x || typeof x !== "object") { - state.syntax[s] = x = { - id: s, - lbp: p, - value: s - }; - } - return x; - } - - function delim(s) { - return symbol(s, 0); - } - - function stmt(s, f) { - var x = delim(s); - x.identifier = x.reserved = true; - x.fud = f; - return x; - } - - function blockstmt(s, f) { - var x = stmt(s, f); - x.block = true; - return x; - } - - function reserveName(x) { - var c = x.id.charAt(0); - if ((c >= "a" && c <= "z") || (c >= "A" && c <= "Z")) { - x.identifier = x.reserved = true; - } - return x; - } - - function prefix(s, f) { - var x = symbol(s, 150); - reserveName(x); - x.nud = (typeof f === "function") ? f : function () { - this.right = expression(150); - this.arity = "unary"; - if (this.id === "++" || this.id === "--") { - if (state.option.plusplus) { - warning("W016", this, this.id); - } else if ((!this.right.identifier || isReserved(this.right)) && - this.right.id !== "." && this.right.id !== "[") { - warning("W017", this); - } - } - return this; - }; - return x; - } - - function type(s, f) { - var x = delim(s); - x.type = s; - x.nud = f; - return x; - } - - function reserve(name, func) { - var x = type(name, func); - x.identifier = true; - x.reserved = true; - return x; - } - - function FutureReservedWord(name, meta) { - var x = type(name, (meta && meta.nud) || function () { - return this; - }); - - meta = meta || {}; - meta.isFutureReservedWord = true; - - x.value = name; - x.identifier = true; - x.reserved = true; - x.meta = meta; - - return x; - } - - function reservevar(s, v) { - return reserve(s, function () { - if (typeof v === "function") { - v(this); - } - return this; - }); - } - - function infix(s, f, p, w) { - var x = symbol(s, p); - reserveName(x); - x.led = function (left) { - if (!w) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - } - if (s === "in" && left.id === "!") { - warning("W018", left, "!"); - } - if (typeof f === "function") { - return f(left, this); - } else { - this.left = left; - this.right = expression(p); - return this; - } - }; - return x; - } - - - function application(s) { - var x = symbol(s, 42); - - x.led = function (left) { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "arrow function syntax (=>)"); - } - - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - - this.left = left; - this.right = doFunction(undefined, undefined, false, left); - return this; - }; - return x; - } - - function relation(s, f) { - var x = symbol(s, 100); - - x.led = function (left) { - nobreaknonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - var right = expression(100); - - if (isIdentifier(left, "NaN") || isIdentifier(right, "NaN")) { - warning("W019", this); - } else if (f) { - f.apply(this, [left, right]); - } - - if (!left || !right) { - quit("E041", state.tokens.curr.line); - } - - if (left.id === "!") { - warning("W018", left, "!"); - } - - if (right.id === "!") { - warning("W018", right, "!"); - } - - this.left = left; - this.right = right; - return this; - }; - return x; - } - - function isPoorRelation(node) { - return node && - ((node.type === "(number)" && +node.value === 0) || - (node.type === "(string)" && node.value === "") || - (node.type === "null" && !state.option.eqnull) || - node.type === "true" || - node.type === "false" || - node.type === "undefined"); - } - - function assignop(s) { - symbol(s, 20).exps = true; - - return infix(s, function (left, that) { - that.left = left; - - if (left) { - if (predefined[left.value] === false && - scope[left.value]["(global)"] === true) { - warning("W020", left); - } else if (left["function"]) { - warning("W021", left, left.value); - } - - if (funct[left.value] === "const") { - error("E013", left, left.value); - } - - if (left.id === ".") { - if (!left.left) { - warning("E031", that); - } else if (left.left.value === "arguments" && !state.directive["use strict"]) { - warning("E031", that); - } - - that.right = expression(19); - return that; - } else if (left.id === "[") { - if (state.tokens.curr.left.first) { - state.tokens.curr.left.first.forEach(function (t) { - if (funct[t.value] === "const") { - error("E013", t, t.value); - } - }); - } else if (!left.left) { - warning("E031", that); - } else if (left.left.value === "arguments" && !state.directive["use strict"]) { - warning("E031", that); - } - that.right = expression(19); - return that; - } else if (left.identifier && !isReserved(left)) { - if (funct[left.value] === "exception") { - warning("W022", left); - } - that.right = expression(19); - return that; - } - - if (left === state.syntax["function"]) { - warning("W023", state.tokens.curr); - } - } - - error("E031", that); - }, 20); - } - - - function bitwise(s, f, p) { - var x = symbol(s, p); - reserveName(x); - x.led = (typeof f === "function") ? f : function (left) { - if (state.option.bitwise) { - warning("W016", this, this.id); - } - this.left = left; - this.right = expression(p); - return this; - }; - return x; - } - - - function bitwiseassignop(s) { - symbol(s, 20).exps = true; - return infix(s, function (left, that) { - if (state.option.bitwise) { - warning("W016", that, that.id); - } - nonadjacent(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - if (left) { - if (left.id === "." || left.id === "[" || - (left.identifier && !isReserved(left))) { - expression(19); - return that; - } - if (left === state.syntax["function"]) { - warning("W023", state.tokens.curr); - } - return that; - } - error("E031", that); - }, 20); - } - - - function suffix(s) { - var x = symbol(s, 150); - - x.led = function (left) { - if (state.option.plusplus) { - warning("W016", this, this.id); - } else if ((!left.identifier || isReserved(left)) && left.id !== "." && left.id !== "[") { - warning("W017", this); - } - - this.left = left; - return this; - }; - return x; - } - - // fnparam means that this identifier is being defined as a function - // argument (see identifier()) - // prop means that this identifier is that of an object property - - function optionalidentifier(fnparam, prop) { - if (!state.tokens.next.identifier) { - return; - } - - advance(); - - var curr = state.tokens.curr; - var meta = curr.meta || {}; - var val = state.tokens.curr.value; - - if (!isReserved(curr)) { - return val; - } - - if (prop) { - if (state.option.inES5() || meta.isFutureReservedWord) { - return val; - } - } - - if (fnparam && val === "undefined") { - return val; - } - - // Display an info message about reserved words as properties - // and ES5 but do it only once. - if (prop && !api.getCache("displayed:I002")) { - api.setCache("displayed:I002", true); - warning("I002"); - } - - warning("W024", state.tokens.curr, state.tokens.curr.id); - return val; - } - - // fnparam means that this identifier is being defined as a function - // argument - // prop means that this identifier is that of an object property - function identifier(fnparam, prop) { - var i = optionalidentifier(fnparam, prop); - if (i) { - return i; - } - if (state.tokens.curr.id === "function" && state.tokens.next.id === "(") { - warning("W025"); - } else { - error("E030", state.tokens.next, state.tokens.next.value); - } - } - - - function reachable(s) { - var i = 0, t; - if (state.tokens.next.id !== ";" || noreach) { - return; - } - for (;;) { - t = peek(i); - if (t.reach) { - return; - } - if (t.id !== "(endline)") { - if (t.id === "function") { - if (!state.option.latedef) { - break; - } - - warning("W026", t); - break; - } - - warning("W027", t, t.value, s); - break; - } - i += 1; - } - } - - - function statement(noindent) { - var values; - var i = indent, r, s = scope, t = state.tokens.next; - - if (t.id === ";") { - advance(";"); - return; - } - - // Is this a labelled statement? - var res = isReserved(t); - - // We're being more tolerant here: if someone uses - // a FutureReservedWord as a label, we warn but proceed - // anyway. - - if (res && t.meta && t.meta.isFutureReservedWord && peek().id === ":") { - warning("W024", t, t.id); - res = false; - } - - // detect a destructuring assignment - if (_.has(["[", "{"], t.value)) { - if (lookupBlockType().isDestAssign) { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "destructuring expression"); - } - values = destructuringExpression(); - values.forEach(function (tok) { - isundef(funct, "W117", tok.token, tok.id); - }); - advance("="); - destructuringExpressionMatch(values, expression(5, true)); - advance(";"); - return; - } - } - if (t.identifier && !res && peek().id === ":") { - advance(); - advance(":"); - scope = Object.create(s); - addlabel(t.value, "label"); - - if (!state.tokens.next.labelled && state.tokens.next.value !== "{") { - warning("W028", state.tokens.next, t.value, state.tokens.next.value); - } - - state.tokens.next.label = t.value; - t = state.tokens.next; - } - - // Is it a lonely block? - - if (t.id === "{") { - // Is it a switch case block? - // - // switch (foo) { - // case bar: { <= here. - // ... - // } - // } - var iscase = (funct["(verb)"] === "case" && state.tokens.curr.value === ":"); - block(true, true, false, false, iscase); - return; - } - - // Parse the statement. - - if (!noindent) { - indentation(); - } - r = expression(0, true); - - // Look for the final semicolon. - - if (!t.block) { - if (!state.option.expr && (!r || !r.exps)) { - warning("W030", state.tokens.curr); - } else if (state.option.nonew && r && r.left && r.id === "(" && r.left.id === "new") { - warning("W031", t); - } - - if (state.tokens.next.id !== ";") { - if (!state.option.asi) { - // If this is the last statement in a block that ends on - // the same line *and* option lastsemic is on, ignore the warning. - // Otherwise, complain about missing semicolon. - if (!state.option.lastsemic || state.tokens.next.id !== "}" || - state.tokens.next.line !== state.tokens.curr.line) { - warningAt("W033", state.tokens.curr.line, state.tokens.curr.character); - } - } - } else { - adjacent(state.tokens.curr, state.tokens.next); - advance(";"); - nonadjacent(state.tokens.curr, state.tokens.next); - } - } - - // Restore the indentation. - - indent = i; - scope = s; - return r; - } - - - function statements(startLine) { - var a = [], p; - - while (!state.tokens.next.reach && state.tokens.next.id !== "(end)") { - if (state.tokens.next.id === ";") { - p = peek(); - - if (!p || (p.id !== "(" && p.id !== "[")) { - warning("W032"); - } - - advance(";"); - } else { - a.push(statement(startLine === state.tokens.next.line)); - } - } - return a; - } - - - /* - * read all directives - * recognizes a simple form of asi, but always - * warns, if it is used - */ - function directives() { - var i, p, pn; - - for (;;) { - if (state.tokens.next.id === "(string)") { - p = peek(0); - if (p.id === "(endline)") { - i = 1; - do { - pn = peek(i); - i = i + 1; - } while (pn.id === "(endline)"); - - if (pn.id !== ";") { - if (pn.id !== "(string)" && pn.id !== "(number)" && - pn.id !== "(regexp)" && pn.identifier !== true && - pn.id !== "}") { - break; - } - warning("W033", state.tokens.next); - } else { - p = pn; - } - } else if (p.id === "}") { - // Directive with no other statements, warn about missing semicolon - warning("W033", p); - } else if (p.id !== ";") { - break; - } - - indentation(); - advance(); - if (state.directive[state.tokens.curr.value]) { - warning("W034", state.tokens.curr, state.tokens.curr.value); - } - - if (state.tokens.curr.value === "use strict") { - if (!state.option["(explicitNewcap)"]) - state.option.newcap = true; - state.option.undef = true; - } - - // there's no directive negation, so always set to true - state.directive[state.tokens.curr.value] = true; - - if (p.id === ";") { - advance(";"); - } - continue; - } - break; - } - } - - - /* - * Parses a single block. A block is a sequence of statements wrapped in - * braces. - * - * ordinary - true for everything but function bodies and try blocks. - * stmt - true if block can be a single statement (e.g. in if/for/while). - * isfunc - true if block is a function body - * isfatarrow - - * iscase - true if block is a switch case block - */ - function block(ordinary, stmt, isfunc, isfatarrow, iscase) { - var a, - b = inblock, - old_indent = indent, - m, - s = scope, - t, - line, - d; - - inblock = ordinary; - - if (!ordinary || !state.option.funcscope) - scope = Object.create(scope); - - nonadjacent(state.tokens.curr, state.tokens.next); - t = state.tokens.next; - - var metrics = funct["(metrics)"]; - metrics.nestedBlockDepth += 1; - metrics.verifyMaxNestedBlockDepthPerFunction(); - - if (state.tokens.next.id === "{") { - advance("{"); - - // create a new block scope - funct["(blockscope)"].stack(); - - line = state.tokens.curr.line; - if (state.tokens.next.id !== "}") { - indent += state.option.indent; - while (!ordinary && state.tokens.next.from > indent) { - indent += state.option.indent; - } - - if (isfunc) { - m = {}; - for (d in state.directive) { - if (_.has(state.directive, d)) { - m[d] = state.directive[d]; - } - } - directives(); - - if (state.option.strict && funct["(context)"]["(global)"]) { - if (!m["use strict"] && !state.directive["use strict"]) { - warning("E007"); - } - } - } - - a = statements(line); - - metrics.statementCount += a.length; - - if (isfunc) { - state.directive = m; - } - - indent -= state.option.indent; - if (line !== state.tokens.next.line) { - indentation(); - } - } else if (line !== state.tokens.next.line) { - indentation(); - } - advance("}", t); - - funct["(blockscope)"].unstack(); - - indent = old_indent; - } else if (!ordinary) { - if (isfunc) { - m = {}; - if (stmt && !isfatarrow && !state.option.inMoz(true)) { - error("W118", state.tokens.curr, "function closure expressions"); - } - - if (!stmt) { - for (d in state.directive) { - if (_.has(state.directive, d)) { - m[d] = state.directive[d]; - } - } - } - expression(5); - - if (state.option.strict && funct["(context)"]["(global)"]) { - if (!m["use strict"] && !state.directive["use strict"]) { - warning("E007"); - } - } - } else { - error("E021", state.tokens.next, "{", state.tokens.next.value); - } - } else { - - // check to avoid let declaration not within a block - funct["(nolet)"] = true; - - if (!stmt || state.option.curly) { - warning("W116", state.tokens.next, "{", state.tokens.next.value); - } - - noreach = true; - indent += state.option.indent; - // test indentation only if statement is in new line - a = [statement(state.tokens.next.line === state.tokens.curr.line)]; - indent -= state.option.indent; - noreach = false; - - delete funct["(nolet)"]; - } - // If it is a "break" in switch case, don't clear and let it propagate out. - if (!(iscase && funct["(verb)"] === "break")) funct["(verb)"] = null; - - if (!ordinary || !state.option.funcscope) scope = s; - inblock = b; - if (ordinary && state.option.noempty && (!a || a.length === 0)) { - warning("W035"); - } - metrics.nestedBlockDepth -= 1; - return a; - } - - - function countMember(m) { - if (membersOnly && typeof membersOnly[m] !== "boolean") { - warning("W036", state.tokens.curr, m); - } - if (typeof member[m] === "number") { - member[m] += 1; - } else { - member[m] = 1; - } - } - - - function note_implied(tkn) { - var name = tkn.value, line = tkn.line, a = implied[name]; - if (typeof a === "function") { - a = false; - } - - if (!a) { - a = [line]; - implied[name] = a; - } else if (a[a.length - 1] !== line) { - a.push(line); - } - } - - - // Build the syntax table by declaring the syntactic elements of the language. - - type("(number)", function () { - return this; - }); - - type("(string)", function () { - return this; - }); - - state.syntax["(identifier)"] = { - type: "(identifier)", - lbp: 0, - identifier: true, - nud: function () { - var v = this.value, - s = scope[v], - f; - - if (typeof s === "function") { - // Protection against accidental inheritance. - s = undefined; - } else if (typeof s === "boolean") { - f = funct; - funct = functions[0]; - addlabel(v, "var"); - s = funct; - funct = f; - } - var block; - if (_.has(funct, "(blockscope)")) { - block = funct["(blockscope)"].getlabel(v); - } - - // The name is in scope and defined in the current function. - if (funct === s || block) { - // Change 'unused' to 'var', and reject labels. - // the name is in a block scope - switch (block ? block[v]["(type)"] : funct[v]) { - case "unused": - if (block) block[v]["(type)"] = "var"; - else funct[v] = "var"; - break; - case "unction": - if (block) block[v]["(type)"] = "function"; - else funct[v] = "function"; - this["function"] = true; - break; - case "function": - this["function"] = true; - break; - case "label": - warning("W037", state.tokens.curr, v); - break; - } - } else if (funct["(global)"]) { - // The name is not defined in the function. If we are in the global - // scope, then we have an undefined variable. - // - // Operators typeof and delete do not raise runtime errors even if - // the base object of a reference is null so no need to display warning - // if we're inside of typeof or delete. - - if (typeof predefined[v] !== "boolean") { - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === "typeof" || anonname === "delete") || - (state.tokens.next && (state.tokens.next.value === "." || - state.tokens.next.value === "["))) { - - // if we're in a list comprehension, variables are declared - // locally and used before being defined. So we check - // the presence of the given variable in the comp array - // before declaring it undefined. - - if (!funct["(comparray)"].check(v)) { - isundef(funct, "W117", state.tokens.curr, v); - } - } - } - - note_implied(state.tokens.curr); - } else { - // If the name is already defined in the current - // function, but not as outer, then there is a scope error. - - switch (funct[v]) { - case "closure": - case "function": - case "var": - case "unused": - warning("W038", state.tokens.curr, v); - break; - case "label": - warning("W037", state.tokens.curr, v); - break; - case "outer": - case "global": - break; - default: - // If the name is defined in an outer function, make an outer entry, - // and if it was unused, make it var. - if (s === true) { - funct[v] = true; - } else if (s === null) { - warning("W039", state.tokens.curr, v); - note_implied(state.tokens.curr); - } else if (typeof s !== "object") { - // Operators typeof and delete do not raise runtime errors even - // if the base object of a reference is null so no need to - // - // display warning if we're inside of typeof or delete. - // Attempting to subscript a null reference will throw an - // error, even within the typeof and delete operators - if (!(anonname === "typeof" || anonname === "delete") || - (state.tokens.next && - (state.tokens.next.value === "." || state.tokens.next.value === "["))) { - - isundef(funct, "W117", state.tokens.curr, v); - } - funct[v] = true; - note_implied(state.tokens.curr); - } else { - switch (s[v]) { - case "function": - case "unction": - this["function"] = true; - s[v] = "closure"; - funct[v] = s["(global)"] ? "global" : "outer"; - break; - case "var": - case "unused": - s[v] = "closure"; - funct[v] = s["(global)"] ? "global" : "outer"; - break; - case "closure": - funct[v] = s["(global)"] ? "global" : "outer"; - break; - case "label": - warning("W037", state.tokens.curr, v); - } - } - } - } - return this; - }, - led: function () { - error("E033", state.tokens.next, state.tokens.next.value); - } - }; - - type("(regexp)", function () { - return this; - }); - - // ECMAScript parser - - delim("(endline)"); - delim("(begin)"); - delim("(end)").reach = true; - delim("(error)").reach = true; - delim("}").reach = true; - delim(")"); - delim("]"); - delim("\"").reach = true; - delim("'").reach = true; - delim(";"); - delim(":").reach = true; - delim("#"); - - reserve("else"); - reserve("case").reach = true; - reserve("catch"); - reserve("default").reach = true; - reserve("finally"); - reservevar("arguments", function (x) { - if (state.directive["use strict"] && funct["(global)"]) { - warning("E008", x); - } - }); - reservevar("eval"); - reservevar("false"); - reservevar("Infinity"); - reservevar("null"); - reservevar("this", function (x) { - if (state.directive["use strict"] && !state.option.validthis && ((funct["(statement)"] && - funct["(name)"].charAt(0) > "Z") || funct["(global)"])) { - warning("W040", x); - } - }); - reservevar("true"); - reservevar("undefined"); - - assignop("=", "assign", 20); - assignop("+=", "assignadd", 20); - assignop("-=", "assignsub", 20); - assignop("*=", "assignmult", 20); - assignop("/=", "assigndiv", 20).nud = function () { - error("E014"); - }; - assignop("%=", "assignmod", 20); - - bitwiseassignop("&=", "assignbitand", 20); - bitwiseassignop("|=", "assignbitor", 20); - bitwiseassignop("^=", "assignbitxor", 20); - bitwiseassignop("<<=", "assignshiftleft", 20); - bitwiseassignop(">>=", "assignshiftright", 20); - bitwiseassignop(">>>=", "assignshiftrightunsigned", 20); - infix(",", function (left, that) { - var expr; - that.exprs = [left]; - if (!comma({peek: true})) { - return that; - } - while (true) { - if (!(expr = expression(5))) { - break; - } - that.exprs.push(expr); - if (state.tokens.next.value !== "," || !comma()) { - break; - } - } - return that; - }, 5, true); - infix("?", function (left, that) { - that.left = left; - that.right = expression(10); - advance(":"); - that["else"] = expression(10); - return that; - }, 30); - - infix("||", "or", 40); - infix("&&", "and", 50); - bitwise("|", "bitor", 70); - bitwise("^", "bitxor", 80); - bitwise("&", "bitand", 90); - relation("==", function (left, right) { - var eqnull = state.option.eqnull && (left.value === "null" || right.value === "null"); - - if (!eqnull && state.option.eqeqeq) - warning("W116", this, "===", "=="); - else if (isPoorRelation(left)) - warning("W041", this, "===", left.value); - else if (isPoorRelation(right)) - warning("W041", this, "===", right.value); - - return this; - }); - relation("==="); - relation("!=", function (left, right) { - var eqnull = state.option.eqnull && - (left.value === "null" || right.value === "null"); - - if (!eqnull && state.option.eqeqeq) { - warning("W116", this, "!==", "!="); - } else if (isPoorRelation(left)) { - warning("W041", this, "!==", left.value); - } else if (isPoorRelation(right)) { - warning("W041", this, "!==", right.value); - } - return this; - }); - relation("!=="); - relation("<"); - relation(">"); - relation("<="); - relation(">="); - bitwise("<<", "shiftleft", 120); - bitwise(">>", "shiftright", 120); - bitwise(">>>", "shiftrightunsigned", 120); - infix("in", "in", 120); - infix("instanceof", "instanceof", 120); - infix("+", function (left, that) { - var right = expression(130); - if (left && right && left.id === "(string)" && right.id === "(string)") { - left.value += right.value; - left.character = right.character; - if (!state.option.scripturl && reg.javascriptURL.test(left.value)) { - warning("W050", left); - } - return left; - } - that.left = left; - that.right = right; - return that; - }, 130); - prefix("+", "num"); - prefix("+++", function () { - warning("W007"); - this.right = expression(150); - this.arity = "unary"; - return this; - }); - infix("+++", function (left) { - warning("W007"); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix("-", "sub", 130); - prefix("-", "neg"); - prefix("---", function () { - warning("W006"); - this.right = expression(150); - this.arity = "unary"; - return this; - }); - infix("---", function (left) { - warning("W006"); - this.left = left; - this.right = expression(130); - return this; - }, 130); - infix("*", "mult", 140); - infix("/", "div", 140); - infix("%", "mod", 140); - - suffix("++", "postinc"); - prefix("++", "preinc"); - state.syntax["++"].exps = true; - - suffix("--", "postdec"); - prefix("--", "predec"); - state.syntax["--"].exps = true; - prefix("delete", function () { - var p = expression(5); - if (!p || (p.id !== "." && p.id !== "[")) { - warning("W051"); - } - this.first = p; - return this; - }).exps = true; - - prefix("~", function () { - if (state.option.bitwise) { - warning("W052", this, "~"); - } - expression(150); - return this; - }); - - prefix("...", function () { - if (!state.option.inESNext()) { - warning("W104", this, "spread/rest operator"); - } - if (!state.tokens.next.identifier) { - error("E030", state.tokens.next, state.tokens.next.value); - } - expression(150); - return this; - }); - - prefix("!", function () { - this.right = expression(150); - this.arity = "unary"; - - if (!this.right) { // '!' followed by nothing? Give up. - quit("E041", this.line || 0); - } - - if (bang[this.right.id] === true) { - warning("W018", this, "!"); - } - return this; - }); - - prefix("typeof", "typeof"); - prefix("new", function () { - var c = expression(155), i; - if (c && c.id !== "function") { - if (c.identifier) { - c["new"] = true; - switch (c.value) { - case "Number": - case "String": - case "Boolean": - case "Math": - case "JSON": - warning("W053", state.tokens.prev, c.value); - break; - case "Function": - if (!state.option.evil) { - warning("W054"); - } - break; - case "Date": - case "RegExp": - break; - default: - if (c.id !== "function") { - i = c.value.substr(0, 1); - if (state.option.newcap && (i < "A" || i > "Z") && !_.has(global, c.value)) { - warning("W055", state.tokens.curr); - } - } - } - } else { - if (c.id !== "." && c.id !== "[" && c.id !== "(") { - warning("W056", state.tokens.curr); - } - } - } else { - if (!state.option.supernew) - warning("W057", this); - } - adjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id !== "(" && !state.option.supernew) { - warning("W058", state.tokens.curr, state.tokens.curr.value); - } - this.first = c; - return this; - }); - state.syntax["new"].exps = true; - - prefix("void").exps = true; - - infix(".", function (left, that) { - adjacent(state.tokens.prev, state.tokens.curr); - nobreak(); - var m = identifier(false, true); - - if (typeof m === "string") { - countMember(m); - } - - that.left = left; - that.right = m; - - if (m && m === "hasOwnProperty" && state.tokens.next.value === "=") { - warning("W001"); - } - - if (left && left.value === "arguments" && (m === "callee" || m === "caller")) { - if (state.option.noarg) - warning("W059", left, m); - else if (state.directive["use strict"]) - error("E008"); - } else if (!state.option.evil && left && left.value === "document" && - (m === "write" || m === "writeln")) { - warning("W060", left); - } - - if (!state.option.evil && (m === "eval" || m === "execScript")) { - warning("W061"); - } - - return that; - }, 160, true); - - infix("(", function (left, that) { - if (state.tokens.prev.id !== "}" && state.tokens.prev.id !== ")") { - nobreak(state.tokens.prev, state.tokens.curr); - } - - nospace(); - if (state.option.immed && left && !left.immed && left.id === "function") { - warning("W062"); - } - - var n = 0; - var p = []; - - if (left) { - if (left.type === "(identifier)") { - if (left.value.match(/^[A-Z]([A-Z0-9_$]*[a-z][A-Za-z0-9_$]*)?$/)) { - if ("Number String Boolean Date Object".indexOf(left.value) === -1) { - if (left.value === "Math") { - warning("W063", left); - } else if (state.option.newcap) { - warning("W064", left); - } - } - } - } - } - - if (state.tokens.next.id !== ")") { - for (;;) { - p[p.length] = expression(10); - n += 1; - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - - advance(")"); - nospace(state.tokens.prev, state.tokens.curr); - - if (typeof left === "object") { - if (left.value === "parseInt" && n === 1) { - warning("W065", state.tokens.curr); - } - if (!state.option.evil) { - if (left.value === "eval" || left.value === "Function" || - left.value === "execScript") { - warning("W061", left); - - if (p[0] && [0].id === "(string)") { - addInternalSrc(left, p[0].value); - } - } else if (p[0] && p[0].id === "(string)" && - (left.value === "setTimeout" || - left.value === "setInterval")) { - warning("W066", left); - addInternalSrc(left, p[0].value); - - // window.setTimeout/setInterval - } else if (p[0] && p[0].id === "(string)" && - left.value === "." && - left.left.value === "window" && - (left.right === "setTimeout" || - left.right === "setInterval")) { - warning("W066", left); - addInternalSrc(left, p[0].value); - } - } - if (!left.identifier && left.id !== "." && left.id !== "[" && - left.id !== "(" && left.id !== "&&" && left.id !== "||" && - left.id !== "?") { - warning("W067", left); - } - } - - that.left = left; - return that; - }, 155, true).exps = true; - - prefix("(", function () { - nospace(); - var bracket, brackets = []; - var pn, pn1, i = 0; - - do { - pn = peek(i); - i += 1; - pn1 = peek(i); - i += 1; - } while (pn.value !== ")" && pn1.value !== "=>" && pn1.value !== ";" && pn1.type !== "(end)"); - - if (state.tokens.next.id === "function") { - state.tokens.next.immed = true; - } - - var exprs = []; - - if (state.tokens.next.id !== ")") { - for (;;) { - if (pn1.value === "=>" && state.tokens.next.value === "{") { - bracket = state.tokens.next; - bracket.left = destructuringExpression(); - brackets.push(bracket); - for (var t in bracket.left) { - exprs.push(bracket.left[t].token); - } - } else { - exprs.push(expression(5)); - } - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - - advance(")", this); - nospace(state.tokens.prev, state.tokens.curr); - if (state.option.immed && exprs[0] && exprs[0].id === "function") { - if (state.tokens.next.id !== "(" && - (state.tokens.next.id !== "." || (peek().value !== "call" && peek().value !== "apply"))) { - warning("W068", this); - } - } - - if (state.tokens.next.value === "=>") { - return exprs; - } - if (!exprs.length) { - return; - } - exprs[exprs.length - 1].paren = true; - if (exprs.length > 1) { - return Object.create(state.syntax[","], { exprs: { value: exprs } }); - } - return exprs[0]; - }); - - application("=>"); - - infix("[", function (left, that) { - nobreak(state.tokens.prev, state.tokens.curr); - nospace(); - var e = expression(5), s; - if (e && e.type === "(string)") { - if (!state.option.evil && (e.value === "eval" || e.value === "execScript")) { - warning("W061", that); - } - - countMember(e.value); - if (!state.option.sub && reg.identifier.test(e.value)) { - s = state.syntax[e.value]; - if (!s || !isReserved(s)) { - warning("W069", state.tokens.prev, e.value); - } - } - } - advance("]", that); - - if (e && e.value === "hasOwnProperty" && state.tokens.next.value === "=") { - warning("W001"); - } - - nospace(state.tokens.prev, state.tokens.curr); - that.left = left; - that.right = e; - return that; - }, 160, true); - - function comprehensiveArrayExpression() { - var res = {}; - res.exps = true; - funct["(comparray)"].stack(); - - res.right = expression(5); - advance("for"); - if (state.tokens.next.value === "each") { - advance("each"); - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "for each"); - } - } - advance("("); - funct["(comparray)"].setState("define"); - res.left = expression(5); - advance(")"); - if (state.tokens.next.value === "if") { - advance("if"); - advance("("); - funct["(comparray)"].setState("filter"); - res.filter = expression(5); - advance(")"); - } - advance("]"); - funct["(comparray)"].unstack(); - return res; - } - - prefix("[", function () { - var blocktype = lookupBlockType(true); - if (blocktype.isCompArray) { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "array comprehension"); - } - return comprehensiveArrayExpression(); - } else if (blocktype.isDestAssign && !state.option.inESNext()) { - warning("W104", state.tokens.curr, "destructuring assignment"); - } - var b = state.tokens.curr.line !== state.tokens.next.line; - this.first = []; - if (b) { - indent += state.option.indent; - if (state.tokens.next.from === indent + state.option.indent) { - indent += state.option.indent; - } - } - while (state.tokens.next.id !== "(end)") { - while (state.tokens.next.id === ",") { - if (!state.option.inES5()) - warning("W070"); - advance(","); - } - if (state.tokens.next.id === "]") { - break; - } - if (b && state.tokens.curr.line !== state.tokens.next.line) { - indentation(); - } - this.first.push(expression(10)); - if (state.tokens.next.id === ",") { - comma({ allowTrailing: true }); - if (state.tokens.next.id === "]" && !state.option.inES5(true)) { - warning("W070", state.tokens.curr); - break; - } - } else { - break; - } - } - if (b) { - indent -= state.option.indent; - indentation(); - } - advance("]", this); - return this; - }, 160); - - - function property_name() { - var id = optionalidentifier(false, true); - - if (!id) { - if (state.tokens.next.id === "(string)") { - id = state.tokens.next.value; - advance(); - } else if (state.tokens.next.id === "(number)") { - id = state.tokens.next.value.toString(); - advance(); - } - } - - if (id === "hasOwnProperty") { - warning("W001"); - } - - return id; - } - - - function functionparams(parsed) { - var curr, next; - var params = []; - var ident; - var tokens = []; - var t; - - if (parsed) { - if (parsed instanceof Array) { - for (var i in parsed) { - curr = parsed[i]; - if (_.contains(["{", "["], curr.id)) { - for (t in curr.left) { - t = tokens[t]; - if (t.id) { - params.push(t.id); - addlabel(t.id, "unused", t.token); - } - } - } else if (curr.value === "...") { - if (!state.option.inESNext()) { - warning("W104", curr, "spread/rest operator"); - } - continue; - } else { - addlabel(curr.value, "unused", curr); - } - } - return params; - } else { - if (parsed.identifier === true) { - addlabel(parsed.value, "unused", parsed); - return [parsed]; - } - } - } - - next = state.tokens.next; - - advance("("); - nospace(); - - if (state.tokens.next.id === ")") { - advance(")"); - return; - } - - for (;;) { - if (_.contains(["{", "["], state.tokens.next.id)) { - tokens = destructuringExpression(); - for (t in tokens) { - t = tokens[t]; - if (t.id) { - params.push(t.id); - addlabel(t.id, "unused", t.token); - } - } - } else if (state.tokens.next.value === "...") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.next, "spread/rest operator"); - } - advance("..."); - nospace(); - ident = identifier(true); - params.push(ident); - addlabel(ident, "unused", state.tokens.curr); - } else { - ident = identifier(true); - params.push(ident); - addlabel(ident, "unused", state.tokens.curr); - } - if (state.tokens.next.id === ",") { - comma(); - } else { - advance(")", next); - nospace(state.tokens.prev, state.tokens.curr); - return params; - } - } - } - - - function doFunction(name, statement, generator, fatarrowparams) { - var f; - var oldOption = state.option; - var oldIgnored = state.ignored; - var oldScope = scope; - - state.option = Object.create(state.option); - state.ignored = Object.create(state.ignored); - scope = Object.create(scope); - - funct = { - "(name)" : name || "\"" + anonname + "\"", - "(line)" : state.tokens.next.line, - "(character)" : state.tokens.next.character, - "(context)" : funct, - "(breakage)" : 0, - "(loopage)" : 0, - "(metrics)" : createMetrics(state.tokens.next), - "(scope)" : scope, - "(statement)" : statement, - "(tokens)" : {}, - "(blockscope)": funct["(blockscope)"], - "(comparray)" : funct["(comparray)"] - }; - - if (generator) { - funct["(generator)"] = true; - } - - f = funct; - state.tokens.curr.funct = funct; - - functions.push(funct); - - if (name) { - addlabel(name, "function"); - } - - funct["(params)"] = functionparams(fatarrowparams); - - funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]); - - block(false, true, true, fatarrowparams ? true:false); - - if (generator && funct["(generator)"] !== "yielded") { - error("E047", state.tokens.curr); - } - - funct["(metrics)"].verifyMaxStatementsPerFunction(); - funct["(metrics)"].verifyMaxComplexityPerFunction(); - funct["(unusedOption)"] = state.option.unused; - - scope = oldScope; - state.option = oldOption; - state.ignored = oldIgnored; - funct["(last)"] = state.tokens.curr.line; - funct["(lastcharacter)"] = state.tokens.curr.character; - funct = funct["(context)"]; - - return f; - } - - function createMetrics(functionStartToken) { - return { - statementCount: 0, - nestedBlockDepth: -1, - ComplexityCount: 1, - verifyMaxStatementsPerFunction: function () { - if (state.option.maxstatements && - this.statementCount > state.option.maxstatements) { - warning("W071", functionStartToken, this.statementCount); - } - }, - - verifyMaxParametersPerFunction: function (params) { - params = params || []; - - if (state.option.maxparams && params.length > state.option.maxparams) { - warning("W072", functionStartToken, params.length); - } - }, - - verifyMaxNestedBlockDepthPerFunction: function () { - if (state.option.maxdepth && - this.nestedBlockDepth > 0 && - this.nestedBlockDepth === state.option.maxdepth + 1) { - warning("W073", null, this.nestedBlockDepth); - } - }, - - verifyMaxComplexityPerFunction: function () { - var max = state.option.maxcomplexity; - var cc = this.ComplexityCount; - if (max && cc > max) { - warning("W074", functionStartToken, cc); - } - } - }; - } - - function increaseComplexityCount() { - funct["(metrics)"].ComplexityCount += 1; - } - - // Parse assignments that were found instead of conditionals. - // For example: if (a = 1) { ... } - - function checkCondAssignment(expr) { - var id = expr.id; - if (id === ",") { - expr = expr.exprs[expr.exprs.length - 1]; - id = expr.id; - } - switch (id) { - case "=": - case "+=": - case "-=": - case "*=": - case "%=": - case "&=": - case "|=": - case "^=": - case "/=": - if (!expr.paren && !state.option.boss) { - warning("W084"); - } - } - } - - - (function (x) { - x.nud = function (isclassdef) { - var b, f, i, p, t, g; - var props = {}; // All properties, including accessors - var tag = ""; - - function saveProperty(name, tkn) { - if (props[name] && _.has(props, name)) - warning("W075", state.tokens.next, i); - else - props[name] = {}; - - props[name].basic = true; - props[name].basictkn = tkn; - } - - function saveSetter(name, tkn) { - if (props[name] && _.has(props, name)) { - if (props[name].basic || props[name].setter) - warning("W075", state.tokens.next, i); - } else { - props[name] = {}; - } - - props[name].setter = true; - props[name].setterToken = tkn; - } - - function saveGetter(name) { - if (props[name] && _.has(props, name)) { - if (props[name].basic || props[name].getter) - warning("W075", state.tokens.next, i); - } else { - props[name] = {}; - } - - props[name].getter = true; - props[name].getterToken = state.tokens.curr; - } - - b = state.tokens.curr.line !== state.tokens.next.line; - if (b) { - indent += state.option.indent; - if (state.tokens.next.from === indent + state.option.indent) { - indent += state.option.indent; - } - } - - for (;;) { - if (state.tokens.next.id === "}") { - break; - } - - if (b) { - indentation(); - } - - if (isclassdef && state.tokens.next.value === "static") { - advance("static"); - tag = "static "; - } - - if (state.tokens.next.value === "get" && peek().id !== ":") { - advance("get"); - - if (!state.option.inES5(!isclassdef)) { - error("E034"); - } - - i = property_name(); - if (!i) { - error("E035"); - } - - // It is a Syntax Error if PropName of MethodDefinition is - // "constructor" and SpecialMethod of MethodDefinition is true. - if (isclassdef && i === "constructor") { - error("E049", state.tokens.next, "class getter method", i); - } - - saveGetter(tag + i); - t = state.tokens.next; - adjacent(state.tokens.curr, state.tokens.next); - f = doFunction(); - p = f["(params)"]; - - if (p) { - warning("W076", t, p[0], i); - } - - adjacent(state.tokens.curr, state.tokens.next); - } else if (state.tokens.next.value === "set" && peek().id !== ":") { - advance("set"); - - if (!state.option.inES5(!isclassdef)) { - error("E034"); - } - - i = property_name(); - if (!i) { - error("E035"); - } - - // It is a Syntax Error if PropName of MethodDefinition is - // "constructor" and SpecialMethod of MethodDefinition is true. - if (isclassdef && i === "constructor") { - error("E049", state.tokens.next, "class setter method", i); - } - - saveSetter(tag + i, state.tokens.next); - t = state.tokens.next; - adjacent(state.tokens.curr, state.tokens.next); - f = doFunction(); - p = f["(params)"]; - - if (!p || p.length !== 1) { - warning("W077", t, i); - } - } else { - g = false; - if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.next, "generator functions"); - } - advance("*"); - g = true; - } - i = property_name(); - saveProperty(tag + i, state.tokens.next); - - if (typeof i !== "string") { - break; - } - - if (state.tokens.next.value === "(") { - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "concise methods"); - } - doFunction(i, undefined, g); - } else if (!isclassdef) { - advance(":"); - nonadjacent(state.tokens.curr, state.tokens.next); - expression(10); - } - } - // It is a Syntax Error if PropName of MethodDefinition is "prototype". - if (isclassdef && i === "prototype") { - error("E049", state.tokens.next, "class method", i); - } - - countMember(i); - if (isclassdef) { - tag = ""; - continue; - } - if (state.tokens.next.id === ",") { - comma({ allowTrailing: true, property: true }); - if (state.tokens.next.id === ",") { - warning("W070", state.tokens.curr); - } else if (state.tokens.next.id === "}" && !state.option.inES5(true)) { - warning("W070", state.tokens.curr); - } - } else { - break; - } - } - if (b) { - indent -= state.option.indent; - indentation(); - } - advance("}", this); - - // Check for lonely setters if in the ES5 mode. - if (state.option.inES5()) { - for (var name in props) { - if (_.has(props, name) && props[name].setter && !props[name].getter) { - warning("W078", props[name].setterToken); - } - } - } - return this; - }; - x.fud = function () { - error("E036", state.tokens.curr); - }; - }(delim("{"))); - - function destructuringExpression() { - var id, ids; - var identifiers = []; - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "destructuring expression"); - } - var nextInnerDE = function () { - var ident; - if (_.contains(["[", "{"], state.tokens.next.value)) { - ids = destructuringExpression(); - for (var id in ids) { - id = ids[id]; - identifiers.push({ id: id.id, token: id.token }); - } - } else if (state.tokens.next.value === ",") { - identifiers.push({ id: null, token: state.tokens.curr }); - } else { - ident = identifier(); - if (ident) - identifiers.push({ id: ident, token: state.tokens.curr }); - } - }; - if (state.tokens.next.value === "[") { - advance("["); - nextInnerDE(); - while (state.tokens.next.value !== "]") { - advance(","); - nextInnerDE(); - } - advance("]"); - } else if (state.tokens.next.value === "{") { - advance("{"); - id = identifier(); - if (state.tokens.next.value === ":") { - advance(":"); - nextInnerDE(); - } else { - identifiers.push({ id: id, token: state.tokens.curr }); - } - while (state.tokens.next.value !== "}") { - advance(","); - id = identifier(); - if (state.tokens.next.value === ":") { - advance(":"); - nextInnerDE(); - } else { - identifiers.push({ id: id, token: state.tokens.curr }); - } - } - advance("}"); - } - return identifiers; - } - function destructuringExpressionMatch(tokens, value) { - if (value.first) { - _.zip(tokens, value.first).forEach(function (val) { - var token = val[0]; - var value = val[1]; - if (token && value) { - token.first = value; - } else if (token && token.first && !value) { - warning("W080", token.first, token.first.value); - } /* else { - XXX value is discarded: wouldn't it need a warning ? - } */ - }); - } - } - - var conststatement = stmt("const", function (prefix) { - var tokens, value; - // state variable to know if it is a lone identifier, or a destructuring statement. - var lone; - - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "const"); - } - - this.first = []; - for (;;) { - var names = []; - nonadjacent(state.tokens.curr, state.tokens.next); - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringExpression(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr } ]; - lone = true; - } - for (var t in tokens) { - t = tokens[t]; - if (funct[t.id] === "const") { - warning("E011", null, t.id); - } - if (funct["(global)"] && predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - if (t.id) { - addlabel(t.id, "const"); - names.push(t.token); - } - } - if (prefix) { - break; - } - - this.first = this.first.concat(names); - - if (state.tokens.next.id !== "=") { - warning("E012", state.tokens.curr, state.tokens.curr.value); - } - - if (state.tokens.next.id === "=") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("="); - nonadjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - error("E037", state.tokens.next, state.tokens.next.value); - } - value = expression(5); - if (lone) { - tokens[0].first = value; - } else { - destructuringExpressionMatch(names, value); - } - } - - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - return this; - }); - conststatement.exps = true; - var varstatement = stmt("var", function (prefix) { - // JavaScript does not have block scope. It only has function scope. So, - // declaring a variable in a block can have unexpected consequences. - var tokens, lone, value; - - if (funct["(onevar)"] && state.option.onevar) { - warning("W081"); - } else if (!funct["(global)"]) { - funct["(onevar)"] = true; - } - - this.first = []; - for (;;) { - var names = []; - nonadjacent(state.tokens.curr, state.tokens.next); - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringExpression(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr } ]; - lone = true; - } - for (var t in tokens) { - t = tokens[t]; - if (state.option.inESNext() && funct[t.id] === "const") { - warning("E011", null, t.id); - } - if (funct["(global)"] && predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - if (t.id) { - addlabel(t.id, "unused", t.token); - names.push(t.token); - } - } - if (prefix) { - break; - } - - this.first = this.first.concat(names); - - if (state.tokens.next.id === "=") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("="); - nonadjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - error("E038", state.tokens.next, state.tokens.next.value); - } - value = expression(5); - if (lone) { - tokens[0].first = value; - } else { - destructuringExpressionMatch(names, value); - } - } - - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - return this; - }); - varstatement.exps = true; - var letstatement = stmt("let", function (prefix) { - var tokens, lone, value, letblock; - - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "let"); - } - - if (state.tokens.next.value === "(") { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.next, "let block"); - } - advance("("); - funct["(blockscope)"].stack(); - letblock = true; - } else if (funct["(nolet)"]) { - error("E048", state.tokens.curr); - } - - if (funct["(onevar)"] && state.option.onevar) { - warning("W081"); - } else if (!funct["(global)"]) { - funct["(onevar)"] = true; - } - - this.first = []; - for (;;) { - var names = []; - nonadjacent(state.tokens.curr, state.tokens.next); - if (_.contains(["{", "["], state.tokens.next.value)) { - tokens = destructuringExpression(); - lone = false; - } else { - tokens = [ { id: identifier(), token: state.tokens.curr.value } ]; - lone = true; - } - for (var t in tokens) { - t = tokens[t]; - if (state.option.inESNext() && funct[t.id] === "const") { - warning("E011", null, t.id); - } - if (funct["(global)"] && predefined[t.id] === false) { - warning("W079", t.token, t.id); - } - if (t.id && !funct["(nolet)"]) { - addlabel(t.id, "unused", t.token, true); - names.push(t.token); - } - } - if (prefix) { - break; - } - - this.first = this.first.concat(names); - - if (state.tokens.next.id === "=") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("="); - nonadjacent(state.tokens.curr, state.tokens.next); - if (state.tokens.next.id === "undefined") { - warning("W080", state.tokens.prev, state.tokens.prev.value); - } - if (peek(0).id === "=" && state.tokens.next.identifier) { - error("E037", state.tokens.next, state.tokens.next.value); - } - value = expression(5); - if (lone) { - tokens[0].first = value; - } else { - destructuringExpressionMatch(names, value); - } - } - - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - if (letblock) { - advance(")"); - block(true, true); - this.block = true; - funct["(blockscope)"].unstack(); - } - - return this; - }); - letstatement.exps = true; - - blockstmt("class", function () { - return classdef.call(this, true); - }); - - function classdef(stmt) { - /*jshint validthis:true */ - if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "class"); - } - if (stmt) { - // BindingIdentifier - this.name = identifier(); - addlabel(this.name, "unused", state.tokens.curr); - } else if (state.tokens.next.identifier && state.tokens.next.value !== "extends") { - // BindingIdentifier(opt) - this.name = identifier(); - } - classtail(this); - return this; - } - - function classtail(c) { - var strictness = state.directive["use strict"]; - - // ClassHeritage(opt) - if (state.tokens.next.value === "extends") { - advance("extends"); - c.heritage = expression(10); - } - - // A ClassBody is always strict code. - state.directive["use strict"] = true; - advance("{"); - // ClassBody(opt) - c.body = state.syntax["{"].nud(true); - state.directive["use strict"] = strictness; - } - - blockstmt("function", function () { - var generator = false; - if (state.tokens.next.value === "*") { - advance("*"); - if (state.option.inESNext(true)) { - generator = true; - } else { - warning("W119", state.tokens.curr, "function*"); - } - } - if (inblock) { - warning("W082", state.tokens.curr); - - } - var i = identifier(); - if (funct[i] === "const") { - warning("E011", null, i); - } - adjacent(state.tokens.curr, state.tokens.next); - addlabel(i, "unction", state.tokens.curr); - - doFunction(i, { statement: true }, generator); - if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) { - error("E039"); - } - return this; - }); - - prefix("function", function () { - var generator = false; - if (state.tokens.next.value === "*") { - if (!state.option.inESNext()) { - warning("W119", state.tokens.curr, "function*"); - } - advance("*"); - generator = true; - } - var i = optionalidentifier(); - if (i || state.option.gcl) { - adjacent(state.tokens.curr, state.tokens.next); - } else { - nonadjacent(state.tokens.curr, state.tokens.next); - } - doFunction(i, undefined, generator); - if (!state.option.loopfunc && funct["(loopage)"]) { - warning("W083"); - } - return this; - }); - - blockstmt("if", function () { - var t = state.tokens.next; - increaseComplexityCount(); - state.condition = true; - advance("("); - nonadjacent(this, t); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - state.condition = false; - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - if (state.tokens.next.id === "else") { - nonadjacent(state.tokens.curr, state.tokens.next); - advance("else"); - if (state.tokens.next.id === "if" || state.tokens.next.id === "switch") { - statement(true); - } else { - block(true, true); - } - } - return this; - }); - - blockstmt("try", function () { - var b; - - function doCatch() { - var oldScope = scope; - var e; - - advance("catch"); - nonadjacent(state.tokens.curr, state.tokens.next); - advance("("); - - scope = Object.create(oldScope); - - e = state.tokens.next.value; - if (state.tokens.next.type !== "(identifier)") { - e = null; - warning("E030", state.tokens.next, e); - } - - advance(); - - funct = { - "(name)" : "(catch)", - "(line)" : state.tokens.next.line, - "(character)": state.tokens.next.character, - "(context)" : funct, - "(breakage)" : funct["(breakage)"], - "(loopage)" : funct["(loopage)"], - "(scope)" : scope, - "(statement)": false, - "(metrics)" : createMetrics(state.tokens.next), - "(catch)" : true, - "(tokens)" : {}, - "(blockscope)": funct["(blockscope)"], - "(comparray)": funct["(comparray)"] - }; - - if (e) { - addlabel(e, "exception"); - } - - if (state.tokens.next.value === "if") { - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "catch filter"); - } - advance("if"); - expression(0); - } - - advance(")"); - - state.tokens.curr.funct = funct; - functions.push(funct); - - block(false); - - scope = oldScope; - - funct["(last)"] = state.tokens.curr.line; - funct["(lastcharacter)"] = state.tokens.curr.character; - funct = funct["(context)"]; - } - - block(false); - - while (state.tokens.next.id === "catch") { - increaseComplexityCount(); - if (b && (!state.option.inMoz(true))) { - warning("W118", state.tokens.next, "multiple catch blocks"); - } - doCatch(); - b = true; - } - - if (state.tokens.next.id === "finally") { - advance("finally"); - block(false); - return; - } - - if (!b) { - error("E021", state.tokens.next, "catch", state.tokens.next.value); - } - - return this; - }); - - blockstmt("while", function () { - var t = state.tokens.next; - funct["(breakage)"] += 1; - funct["(loopage)"] += 1; - increaseComplexityCount(); - advance("("); - nonadjacent(this, t); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - return this; - }).labelled = true; - - blockstmt("with", function () { - var t = state.tokens.next; - if (state.directive["use strict"]) { - error("E010", state.tokens.curr); - } else if (!state.option.withstmt) { - warning("W085", state.tokens.curr); - } - - advance("("); - nonadjacent(this, t); - nospace(); - expression(0); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - - return this; - }); - - blockstmt("switch", function () { - var t = state.tokens.next, - g = false; - funct["(breakage)"] += 1; - advance("("); - nonadjacent(this, t); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - nonadjacent(state.tokens.curr, state.tokens.next); - t = state.tokens.next; - advance("{"); - nonadjacent(state.tokens.curr, state.tokens.next); - indent += state.option.indent; - this.cases = []; - - for (;;) { - switch (state.tokens.next.id) { - case "case": - switch (funct["(verb)"]) { - case "yield": - case "break": - case "case": - case "continue": - case "return": - case "switch": - case "throw": - break; - default: - // You can tell JSHint that you don't use break intentionally by - // adding a comment /* falls through */ on a line just before - // the next `case`. - if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { - warning("W086", state.tokens.curr, "case"); - } - } - indentation(-state.option.indent); - advance("case"); - this.cases.push(expression(20)); - increaseComplexityCount(); - g = true; - advance(":"); - funct["(verb)"] = "case"; - break; - case "default": - switch (funct["(verb)"]) { - case "yield": - case "break": - case "continue": - case "return": - case "throw": - break; - default: - // Do not display a warning if 'default' is the first statement or if - // there is a special /* falls through */ comment. - if (this.cases.length) { - if (!reg.fallsThrough.test(state.lines[state.tokens.next.line - 2])) { - warning("W086", state.tokens.curr, "default"); - } - } - } - indentation(-state.option.indent); - advance("default"); - g = true; - advance(":"); - break; - case "}": - indent -= state.option.indent; - indentation(); - advance("}", t); - funct["(breakage)"] -= 1; - funct["(verb)"] = undefined; - return; - case "(end)": - error("E023", state.tokens.next, "}"); - return; - default: - if (g) { - switch (state.tokens.curr.id) { - case ",": - error("E040"); - return; - case ":": - g = false; - statements(); - break; - default: - error("E025", state.tokens.curr); - return; - } - } else { - if (state.tokens.curr.id === ":") { - advance(":"); - error("E024", state.tokens.curr, ":"); - statements(); - } else { - error("E021", state.tokens.next, "case", state.tokens.next.value); - return; - } - } - } - } - }).labelled = true; - - stmt("debugger", function () { - if (!state.option.debug) { - warning("W087"); - } - return this; - }).exps = true; - - (function () { - var x = stmt("do", function () { - funct["(breakage)"] += 1; - funct["(loopage)"] += 1; - increaseComplexityCount(); - - this.first = block(true, true); - advance("while"); - var t = state.tokens.next; - nonadjacent(state.tokens.curr, t); - advance("("); - nospace(); - checkCondAssignment(expression(0)); - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - return this; - }); - x.labelled = true; - x.exps = true; - }()); - - blockstmt("for", function () { - var s, t = state.tokens.next; - var letscope = false; - var foreachtok = null; - - if (t.value === "each") { - foreachtok = t; - advance("each"); - if (!state.option.inMoz(true)) { - warning("W118", state.tokens.curr, "for each"); - } - } - - funct["(breakage)"] += 1; - funct["(loopage)"] += 1; - increaseComplexityCount(); - advance("("); - nonadjacent(this, t); - nospace(); - - // what kind of for(…) statement it is? for(…of…)? for(…in…)? for(…;…;…)? - var nextop; // contains the token of the "in" or "of" operator - var i = 0; - var inof = ["in", "of"]; - do { - nextop = peek(i); - ++i; - } while (!_.contains(inof, nextop.value) && nextop.value !== ";" && - nextop.type !== "(end)"); - - // if we're in a for (… in|of …) statement - if (_.contains(inof, nextop.value)) { - if (!state.option.inESNext() && nextop.value === "of") { - error("W104", nextop, "for of"); - } - if (state.tokens.next.id === "var") { - advance("var"); - state.syntax["var"].fud.call(state.syntax["var"].fud, true); - } else if (state.tokens.next.id === "let") { - advance("let"); - // create a new block scope - letscope = true; - funct["(blockscope)"].stack(); - state.syntax["let"].fud.call(state.syntax["let"].fud, true); - } else { - switch (funct[state.tokens.next.value]) { - case "unused": - funct[state.tokens.next.value] = "var"; - break; - case "var": - break; - default: - if (!funct["(blockscope)"].getlabel(state.tokens.next.value)) - warning("W088", state.tokens.next, state.tokens.next.value); - } - advance(); - } - advance(nextop.value); - expression(20); - advance(")", t); - s = block(true, true); - if (state.option.forin && s && (s.length > 1 || typeof s[0] !== "object" || - s[0].value !== "if")) { - warning("W089", this); - } - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - } else { - if (foreachtok) { - error("E045", foreachtok); - } - if (state.tokens.next.id !== ";") { - if (state.tokens.next.id === "var") { - advance("var"); - state.syntax["var"].fud.call(state.syntax["var"].fud); - } else if (state.tokens.next.id === "let") { - advance("let"); - // create a new block scope - letscope = true; - funct["(blockscope)"].stack(); - state.syntax["let"].fud.call(state.syntax["let"].fud); - } else { - for (;;) { - expression(0, "for"); - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - } - nolinebreak(state.tokens.curr); - advance(";"); - if (state.tokens.next.id !== ";") { - checkCondAssignment(expression(0)); - } - nolinebreak(state.tokens.curr); - advance(";"); - if (state.tokens.next.id === ";") { - error("E021", state.tokens.next, ")", ";"); - } - if (state.tokens.next.id !== ")") { - for (;;) { - expression(0, "for"); - if (state.tokens.next.id !== ",") { - break; - } - comma(); - } - } - advance(")", t); - nospace(state.tokens.prev, state.tokens.curr); - block(true, true); - funct["(breakage)"] -= 1; - funct["(loopage)"] -= 1; - - } - // unstack loop blockscope - if (letscope) { - funct["(blockscope)"].unstack(); - } - return this; - }).labelled = true; - - - stmt("break", function () { - var v = state.tokens.next.value; - - if (funct["(breakage)"] === 0) - warning("W052", state.tokens.next, this.value); - - if (!state.option.asi) - nolinebreak(this); - - if (state.tokens.next.id !== ";") { - if (state.tokens.curr.line === state.tokens.next.line) { - if (funct[v] !== "label") { - warning("W090", state.tokens.next, v); - } else if (scope[v] !== funct) { - warning("W091", state.tokens.next, v); - } - this.first = state.tokens.next; - advance(); - } - } - reachable("break"); - return this; - }).exps = true; - - - stmt("continue", function () { - var v = state.tokens.next.value; - - if (funct["(breakage)"] === 0) - warning("W052", state.tokens.next, this.value); - - if (!state.option.asi) - nolinebreak(this); - - if (state.tokens.next.id !== ";") { - if (state.tokens.curr.line === state.tokens.next.line) { - if (funct[v] !== "label") { - warning("W090", state.tokens.next, v); - } else if (scope[v] !== funct) { - warning("W091", state.tokens.next, v); - } - this.first = state.tokens.next; - advance(); - } - } else if (!funct["(loopage)"]) { - warning("W052", state.tokens.next, this.value); - } - reachable("continue"); - return this; - }).exps = true; - - - stmt("return", function () { - if (this.line === state.tokens.next.line) { - if (state.tokens.next.id === "(regexp)") - warning("W092"); - - if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { - nonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(0); - - if (this.first && - this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { - warningAt("W093", this.first.line, this.first.character); - } - } - } else { - if (state.tokens.next.type === "(punctuator)" && - ["[", "{", "+", "-"].indexOf(state.tokens.next.value) > -1) { - nolinebreak(this); // always warn (Line breaking error) - } - } - reachable("return"); - return this; - }).exps = true; - - stmt("yield", function () { - if (state.option.inESNext(true) && funct["(generator)"] !== true) { - error("E046", state.tokens.curr, "yield"); - } else if (!state.option.inESNext()) { - warning("W104", state.tokens.curr, "yield"); - } - funct["(generator)"] = "yielded"; - if (this.line === state.tokens.next.line) { - if (state.tokens.next.id === "(regexp)") - warning("W092"); - - if (state.tokens.next.id !== ";" && !state.tokens.next.reach) { - nonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(0); - - if (this.first.type === "(punctuator)" && this.first.value === "=" && !state.option.boss) { - warningAt("W093", this.first.line, this.first.character); - } - } - } else if (!state.option.asi) { - nolinebreak(this); // always warn (Line breaking error) - } - return this; - }).exps = true; - - - stmt("throw", function () { - nolinebreak(this); - nonadjacent(state.tokens.curr, state.tokens.next); - this.first = expression(20); - reachable("throw"); - return this; - }).exps = true; - - // Future Reserved Words - - FutureReservedWord("abstract"); - FutureReservedWord("boolean"); - FutureReservedWord("byte"); - FutureReservedWord("char"); - FutureReservedWord("class", { es5: true, nud: classdef }); - FutureReservedWord("double"); - FutureReservedWord("enum", { es5: true }); - FutureReservedWord("export", { es5: true }); - FutureReservedWord("extends", { es5: true }); - FutureReservedWord("final"); - FutureReservedWord("float"); - FutureReservedWord("goto"); - FutureReservedWord("implements", { es5: true, strictOnly: true }); - FutureReservedWord("import", { es5: true }); - FutureReservedWord("int"); - FutureReservedWord("interface", { es5: true, strictOnly: true }); - FutureReservedWord("long"); - FutureReservedWord("native"); - FutureReservedWord("package", { es5: true, strictOnly: true }); - FutureReservedWord("private", { es5: true, strictOnly: true }); - FutureReservedWord("protected", { es5: true, strictOnly: true }); - FutureReservedWord("public", { es5: true, strictOnly: true }); - FutureReservedWord("short"); - FutureReservedWord("static", { es5: true, strictOnly: true }); - FutureReservedWord("super", { es5: true }); - FutureReservedWord("synchronized"); - FutureReservedWord("throws"); - FutureReservedWord("transient"); - FutureReservedWord("volatile"); - - // this function is used to determine wether a squarebracket or a curlybracket - // expression is a comprehension array, destructuring assignment or a json value. - - var lookupBlockType = function () { - var pn, pn1; - var i = 0; - var bracketStack = 0; - var ret = {}; - if (_.contains(["[", "{"], state.tokens.curr.value)) - bracketStack += 1; - if (_.contains(["[", "{"], state.tokens.next.value)) - bracketStack += 1; - if (_.contains(["]", "}"], state.tokens.next.value)) - bracketStack -= 1; - do { - pn = peek(i); - pn1 = peek(i + 1); - i = i + 1; - if (_.contains(["[", "{"], pn.value)) { - bracketStack += 1; - } else if (_.contains(["]", "}"], pn.value)) { - bracketStack -= 1; - } - if (pn.identifier && pn.value === "for" && bracketStack === 1) { - ret.isCompArray = true; - ret.notJson = true; - break; - } - if (_.contains(["}", "]"], pn.value) && pn1.value === "=") { - ret.isDestAssign = true; - ret.notJson = true; - break; - } - if (pn.value === ";") { - ret.isBlock = true; - ret.notJson = true; - } - } while (bracketStack > 0 && pn.id !== "(end)" && i < 15); - return ret; - }; - - // Check whether this function has been reached for a destructuring assign with undeclared values - function destructuringAssignOrJsonValue() { - // lookup for the assignment (esnext only) - // if it has semicolons, it is a block, so go parse it as a block - // or it's not a block, but there are assignments, check for undeclared variables - - var block = lookupBlockType(); - if (block.notJson) { - if (!state.option.inESNext() && block.isDestAssign) { - warning("W104", state.tokens.curr, "destructuring assignment"); - } - statements(); - // otherwise parse json value - } else { - state.option.laxbreak = true; - state.jsonMode = true; - jsonValue(); - } - } - - // array comprehension parsing function - // parses and defines the three states of the list comprehension in order - // to avoid defining global variables, but keeping them to the list comprehension scope - // only. The order of the states are as follows: - // * "use" which will be the returned iterative part of the list comprehension - // * "define" which will define the variables local to the list comprehension - // * "filter" which will help filter out values - - var arrayComprehension = function () { - var CompArray = function () { - this.mode = "use"; - this.variables = []; - }; - var _carrays = []; - var _current; - function declare(v) { - var l = _current.variables.filter(function (elt) { - // if it has, change its undef state - if (elt.value === v) { - elt.undef = false; - return v; - } - }).length; - return l !== 0; - } - function use(v) { - var l = _current.variables.filter(function (elt) { - // and if it has been defined - if (elt.value === v && !elt.undef) { - if (elt.unused === true) { - elt.unused = false; - } - return v; - } - }).length; - // otherwise we warn about it - return (l === 0); - } - return {stack: function () { - _current = new CompArray(); - _carrays.push(_current); - }, - unstack: function () { - _current.variables.filter(function (v) { - if (v.unused) - warning("W098", v.token, v.value); - if (v.undef) - isundef(v.funct, "W117", v.token, v.value); - }); - _carrays.splice(_carrays[_carrays.length - 1], 1); - _current = _carrays[_carrays.length - 1]; - }, - setState: function (s) { - if (_.contains(["use", "define", "filter"], s)) - _current.mode = s; - }, - check: function (v) { - // When we are in "use" state of the list comp, we enqueue that var - if (_current && _current.mode === "use") { - _current.variables.push({funct: funct, - token: state.tokens.curr, - value: v, - undef: true, - unused: false}); - return true; - // When we are in "define" state of the list comp, - } else if (_current && _current.mode === "define") { - // check if the variable has been used previously - if (!declare(v)) { - _current.variables.push({funct: funct, - token: state.tokens.curr, - value: v, - undef: false, - unused: true}); - } - return true; - // When we are in "filter" state, - } else if (_current && _current.mode === "filter") { - // we check whether current variable has been declared - if (use(v)) { - // if not we warn about it - isundef(funct, "W117", state.tokens.curr, v); - } - return true; - } - return false; - } - }; - }; - - - // Parse JSON - - function jsonValue() { - - function jsonObject() { - var o = {}, t = state.tokens.next; - advance("{"); - if (state.tokens.next.id !== "}") { - for (;;) { - if (state.tokens.next.id === "(end)") { - error("E026", state.tokens.next, t.line); - } else if (state.tokens.next.id === "}") { - warning("W094", state.tokens.curr); - break; - } else if (state.tokens.next.id === ",") { - error("E028", state.tokens.next); - } else if (state.tokens.next.id !== "(string)") { - warning("W095", state.tokens.next, state.tokens.next.value); - } - if (o[state.tokens.next.value] === true) { - warning("W075", state.tokens.next, state.tokens.next.value); - } else if ((state.tokens.next.value === "__proto__" && - !state.option.proto) || (state.tokens.next.value === "__iterator__" && - !state.option.iterator)) { - warning("W096", state.tokens.next, state.tokens.next.value); - } else { - o[state.tokens.next.value] = true; - } - advance(); - advance(":"); - jsonValue(); - if (state.tokens.next.id !== ",") { - break; - } - advance(","); - } - } - advance("}"); - } - - function jsonArray() { - var t = state.tokens.next; - advance("["); - if (state.tokens.next.id !== "]") { - for (;;) { - if (state.tokens.next.id === "(end)") { - error("E027", state.tokens.next, t.line); - } else if (state.tokens.next.id === "]") { - warning("W094", state.tokens.curr); - break; - } else if (state.tokens.next.id === ",") { - error("E028", state.tokens.next); - } - jsonValue(); - if (state.tokens.next.id !== ",") { - break; - } - advance(","); - } - } - advance("]"); - } - - switch (state.tokens.next.id) { - case "{": - jsonObject(); - break; - case "[": - jsonArray(); - break; - case "true": - case "false": - case "null": - case "(number)": - case "(string)": - advance(); - break; - case "-": - advance("-"); - if (state.tokens.curr.character !== state.tokens.next.from) { - warning("W011", state.tokens.curr); - } - adjacent(state.tokens.curr, state.tokens.next); - advance("(number)"); - break; - default: - error("E003", state.tokens.next); - } - } - - var blockScope = function () { - var _current = {}; - var _variables = [_current]; - - function _checkBlockLabels() { - for (var t in _current) { - if (_current[t]["(type)"] === "unused") { - if (state.option.unused) { - var tkn = _current[t]["(token)"]; - var line = tkn.line; - var chr = tkn.character; - warningAt("W098", line, chr, t); - } - } - } - } - - return { - stack: function () { - _current = {}; - _variables.push(_current); - }, - - unstack: function () { - _checkBlockLabels(); - _variables.splice(_variables.length - 1, 1); - _current = _.last(_variables); - }, - - getlabel: function (l) { - for (var i = _variables.length - 1 ; i >= 0; --i) { - if (_.has(_variables[i], l)) { - return _variables[i]; - } - } - }, - - current: { - has: function (t) { - return _.has(_current, t); - }, - add: function (t, type, tok) { - _current[t] = { "(type)" : type, - "(token)": tok }; - } - } - }; - }; - - // The actual JSHINT function itself. - var itself = function (s, o, g) { - var a, i, k, x; - var optionKeys; - var newOptionObj = {}; - var newIgnoredObj = {}; - - state.reset(); - - if (o && o.scope) { - JSHINT.scope = o.scope; - } else { - JSHINT.errors = []; - JSHINT.undefs = []; - JSHINT.internals = []; - JSHINT.blacklist = {}; - JSHINT.scope = "(main)"; - } - - predefined = Object.create(null); - combine(predefined, vars.ecmaIdentifiers); - combine(predefined, vars.reservedVars); - - combine(predefined, g || {}); - - declared = Object.create(null); - exported = Object.create(null); - - if (o) { - a = o.predef; - if (a) { - if (!Array.isArray(a) && typeof a === "object") { - a = Object.keys(a); - } - - a.forEach(function (item) { - var slice, prop; - - if (item[0] === "-") { - slice = item.slice(1); - JSHINT.blacklist[slice] = slice; - } else { - prop = Object.getOwnPropertyDescriptor(o.predef, item); - predefined[item] = prop ? prop.value : false; - } - }); - } - - optionKeys = Object.keys(o); - for (x = 0; x < optionKeys.length; x++) { - if (/^-W\d{3}$/g.test(optionKeys[x])) { - newIgnoredObj[optionKeys[x].slice(1)] = true; - } else { - newOptionObj[optionKeys[x]] = o[optionKeys[x]]; - - if (optionKeys[x] === "newcap" && o[optionKeys[x]] === false) - newOptionObj["(explicitNewcap)"] = true; - - if (optionKeys[x] === "indent") - newOptionObj["(explicitIndent)"] = o[optionKeys[x]] === false ? false : true; - } - } - } - - state.option = newOptionObj; - state.ignored = newIgnoredObj; - - state.option.indent = state.option.indent || 4; - state.option.maxerr = state.option.maxerr || 50; - - indent = 1; - global = Object.create(predefined); - scope = global; - funct = { - "(global)": true, - "(name)": "(global)", - "(scope)": scope, - "(breakage)": 0, - "(loopage)": 0, - "(tokens)": {}, - "(metrics)": createMetrics(state.tokens.next), - "(blockscope)": blockScope(), - "(comparray)": arrayComprehension() - }; - functions = [funct]; - urls = []; - stack = null; - member = {}; - membersOnly = null; - implied = {}; - inblock = false; - lookahead = []; - warnings = 0; - unuseds = []; - - if (!isString(s) && !Array.isArray(s)) { - errorAt("E004", 0); - return false; - } - - api = { - get isJSON() { - return state.jsonMode; - }, - - getOption: function (name) { - return state.option[name] || null; - }, - - getCache: function (name) { - return state.cache[name]; - }, - - setCache: function (name, value) { - state.cache[name] = value; - }, - - warn: function (code, data) { - warningAt.apply(null, [ code, data.line, data.char ].concat(data.data)); - }, - - on: function (names, listener) { - names.split(" ").forEach(function (name) { - emitter.on(name, listener); - }.bind(this)); - } - }; - - emitter.removeAllListeners(); - (extraModules || []).forEach(function (func) { - func(api); - }); - - state.tokens.prev = state.tokens.curr = state.tokens.next = state.syntax["(begin)"]; - - lex = new Lexer(s); - - lex.on("warning", function (ev) { - warningAt.apply(null, [ ev.code, ev.line, ev.character].concat(ev.data)); - }); - - lex.on("error", function (ev) { - errorAt.apply(null, [ ev.code, ev.line, ev.character ].concat(ev.data)); - }); - - lex.on("fatal", function (ev) { - quit("E041", ev.line, ev.from); - }); - - lex.on("Identifier", function (ev) { - emitter.emit("Identifier", ev); - }); - - lex.on("String", function (ev) { - emitter.emit("String", ev); - }); - - lex.on("Number", function (ev) { - emitter.emit("Number", ev); - }); - - lex.start(); - - // Check options - for (var name in o) { - if (_.has(o, name)) { - checkOption(name, state.tokens.curr); - } - } - - assume(); - - // combine the passed globals after we've assumed all our options - combine(predefined, g || {}); - - //reset values - comma.first = true; - - try { - advance(); - switch (state.tokens.next.id) { - case "{": - case "[": - destructuringAssignOrJsonValue(); - break; - default: - directives(); - - if (state.directive["use strict"]) { - if (!state.option.globalstrict && !state.option.node) { - warning("W097", state.tokens.prev); - } - } - - statements(); - } - advance((state.tokens.next && state.tokens.next.value !== ".") ? "(end)" : undefined); - funct["(blockscope)"].unstack(); - - var markDefined = function (name, context) { - do { - if (typeof context[name] === "string") { - // JSHINT marks unused variables as 'unused' and - // unused function declaration as 'unction'. This - // code changes such instances back 'var' and - // 'closure' so that the code in JSHINT.data() - // doesn't think they're unused. - - if (context[name] === "unused") - context[name] = "var"; - else if (context[name] === "unction") - context[name] = "closure"; - - return true; - } - - context = context["(context)"]; - } while (context); - - return false; - }; - - var clearImplied = function (name, line) { - if (!implied[name]) - return; - - var newImplied = []; - for (var i = 0; i < implied[name].length; i += 1) { - if (implied[name][i] !== line) - newImplied.push(implied[name][i]); - } - - if (newImplied.length === 0) - delete implied[name]; - else - implied[name] = newImplied; - }; - - var warnUnused = function (name, tkn, type, unused_opt) { - var line = tkn.line; - var chr = tkn.character; - - if (unused_opt === undefined) { - unused_opt = state.option.unused; - } - - if (unused_opt === true) { - unused_opt = "last-param"; - } - - var warnable_types = { - "vars": ["var"], - "last-param": ["var", "param"], - "strict": ["var", "param", "last-param"] - }; - - if (unused_opt) { - if (warnable_types[unused_opt] && warnable_types[unused_opt].indexOf(type) !== -1) { - warningAt("W098", line, chr, name); - } - } - - unuseds.push({ - name: name, - line: line, - character: chr - }); - }; - - var checkUnused = function (func, key) { - var type = func[key]; - var tkn = func["(tokens)"][key]; - - if (key.charAt(0) === "(") - return; - - if (type !== "unused" && type !== "unction") - return; - - // Params are checked separately from other variables. - if (func["(params)"] && func["(params)"].indexOf(key) !== -1) - return; - - // Variable is in global scope and defined as exported. - if (func["(global)"] && _.has(exported, key)) { - return; - } - - warnUnused(key, tkn, "var"); - }; - - // Check queued 'x is not defined' instances to see if they're still undefined. - for (i = 0; i < JSHINT.undefs.length; i += 1) { - k = JSHINT.undefs[i].slice(0); - - if (markDefined(k[2].value, k[0])) { - clearImplied(k[2].value, k[2].line); - } else if (state.option.undef) { - warning.apply(warning, k.slice(1)); - } - } - - functions.forEach(function (func) { - if (func["(unusedOption)"] === false) { - return; - } - - for (var key in func) { - if (_.has(func, key)) { - checkUnused(func, key); - } - } - - if (!func["(params)"]) - return; - - var params = func["(params)"].slice(); - var param = params.pop(); - var type, unused_opt; - - while (param) { - type = func[param]; - unused_opt = func["(unusedOption)"] || state.option.unused; - unused_opt = unused_opt === true ? "last-param" : unused_opt; - - // 'undefined' is a special case for (function (window, undefined) { ... })(); - // patterns. - - if (param === "undefined") - return; - - if (type === "unused" || type === "unction") { - warnUnused(param, func["(tokens)"][param], "param", func["(unusedOption)"]); - } else if (unused_opt === "last-param") { - return; - } - - param = params.pop(); - } - }); - - for (var key in declared) { - if (_.has(declared, key) && !_.has(global, key)) { - warnUnused(key, declared[key], "var"); - } - } - - } catch (err) { - if (err && err.name === "JSHintError") { - var nt = state.tokens.next || {}; - JSHINT.errors.push({ - scope : "(main)", - raw : err.raw, - reason : err.message, - line : err.line || nt.line, - character : err.character || nt.from - }, null); - } else { - throw err; - } - } - - // Loop over the listed "internals", and check them as well. - - if (JSHINT.scope === "(main)") { - o = o || {}; - - for (i = 0; i < JSHINT.internals.length; i += 1) { - k = JSHINT.internals[i]; - o.scope = k.elem; - itself(k.value, o, g); - } - } - - return JSHINT.errors.length === 0; - }; - - // Modules. - itself.addModule = function (func) { - extraModules.push(func); - }; - - itself.addModule(style.register); - - // Data summary. - itself.data = function () { - var data = { - functions: [], - options: state.option - }; - var implieds = []; - var members = []; - var fu, f, i, j, n, globals; - - if (itself.errors.length) { - data.errors = itself.errors; - } - - if (state.jsonMode) { - data.json = true; - } - - for (n in implied) { - if (_.has(implied, n)) { - implieds.push({ - name: n, - line: implied[n] - }); - } - } - - if (implieds.length > 0) { - data.implieds = implieds; - } - - if (urls.length > 0) { - data.urls = urls; - } - - globals = Object.keys(scope); - if (globals.length > 0) { - data.globals = globals; - } - - for (i = 1; i < functions.length; i += 1) { - f = functions[i]; - fu = {}; - - for (j = 0; j < functionicity.length; j += 1) { - fu[functionicity[j]] = []; - } - - for (j = 0; j < functionicity.length; j += 1) { - if (fu[functionicity[j]].length === 0) { - delete fu[functionicity[j]]; - } - } - - fu.name = f["(name)"]; - fu.param = f["(params)"]; - fu.line = f["(line)"]; - fu.character = f["(character)"]; - fu.last = f["(last)"]; - fu.lastcharacter = f["(lastcharacter)"]; - data.functions.push(fu); - } - - if (unuseds.length > 0) { - data.unused = unuseds; - } - - members = []; - for (n in member) { - if (typeof member[n] === "number") { - data.member = member; - break; - } - } - - return data; - }; - - itself.jshint = itself; - - return itself; -}()); - -// Make JSHINT a Node module, if possible. -if (typeof exports === "object" && exports) { - exports.JSHINT = JSHINT; -} - -})() -},{"events":2,"../shared/vars.js":3,"./lex.js":10,"./reg.js":6,"./state.js":4,"../shared/messages.js":12,"./style.js":5,"console-browserify":7,"underscore":11}],12:[function(require,module,exports){ -(function(){"use strict"; - -var _ = require("underscore"); - -var errors = { - // JSHint options - E001: "Bad option: '{a}'.", - E002: "Bad option value.", - - // JSHint input - E003: "Expected a JSON value.", - E004: "Input is neither a string nor an array of strings.", - E005: "Input is empty.", - E006: "Unexpected early end of program.", - - // Strict mode - E007: "Missing \"use strict\" statement.", - E008: "Strict violation.", - E009: "Option 'validthis' can't be used in a global scope.", - E010: "'with' is not allowed in strict mode.", - - // Constants - E011: "const '{a}' has already been declared.", - E012: "const '{a}' is initialized to 'undefined'.", - E013: "Attempting to override '{a}' which is a constant.", - - // Regular expressions - E014: "A regular expression literal can be confused with '/='.", - E015: "Unclosed regular expression.", - E016: "Invalid regular expression.", - - // Tokens - E017: "Unclosed comment.", - E018: "Unbegun comment.", - E019: "Unmatched '{a}'.", - E020: "Expected '{a}' to match '{b}' from line {c} and instead saw '{d}'.", - E021: "Expected '{a}' and instead saw '{b}'.", - E022: "Line breaking error '{a}'.", - E023: "Missing '{a}'.", - E024: "Unexpected '{a}'.", - E025: "Missing ':' on a case clause.", - E026: "Missing '}' to match '{' from line {a}.", - E027: "Missing ']' to match '[' form line {a}.", - E028: "Illegal comma.", - E029: "Unclosed string.", - - // Everything else - E030: "Expected an identifier and instead saw '{a}'.", - E031: "Bad assignment.", // FIXME: Rephrase - E032: "Expected a small integer or 'false' and instead saw '{a}'.", - E033: "Expected an operator and instead saw '{a}'.", - E034: "get/set are ES5 features.", - E035: "Missing property name.", - E036: "Expected to see a statement and instead saw a block.", - E037: "Constant {a} was not declared correctly.", - E038: "Variable {a} was not declared correctly.", - E039: "Function declarations are not invocable. Wrap the whole function invocation in parens.", - E040: "Each value should have its own case label.", - E041: "Unrecoverable syntax error.", - E042: "Stopping.", - E043: "Too many errors.", - E044: "'{a}' is already defined and can't be redefined.", - E045: "Invalid for each loop.", - E046: "A yield statement shall be within a generator function (with syntax: `function*`)", - E047: "A generator function shall contain a yield statement.", - E048: "Let declaration not directly within block.", - E049: "A {a} cannot be named '{b}'." -}; - -var warnings = { - W001: "'hasOwnProperty' is a really bad name.", - W002: "Value of '{a}' may be overwritten in IE.", - W003: "'{a}' was used before it was defined.", - W004: "'{a}' is already defined.", - W005: "A dot following a number can be confused with a decimal point.", - W006: "Confusing minuses.", - W007: "Confusing pluses.", - W008: "A leading decimal point can be confused with a dot: '{a}'.", - W009: "The array literal notation [] is preferrable.", - W010: "The object literal notation {} is preferrable.", - W011: "Unexpected space after '{a}'.", - W012: "Unexpected space before '{a}'.", - W013: "Missing space after '{a}'.", - W014: "Bad line breaking before '{a}'.", - W015: "Expected '{a}' to have an indentation at {b} instead at {c}.", - W016: "Unexpected use of '{a}'.", - W017: "Bad operand.", - W018: "Confusing use of '{a}'.", - W019: "Use the isNaN function to compare with NaN.", - W020: "Read only.", - W021: "'{a}' is a function.", - W022: "Do not assign to the exception parameter.", - W023: "Expected an identifier in an assignment and instead saw a function invocation.", - W024: "Expected an identifier and instead saw '{a}' (a reserved word).", - W025: "Missing name in function declaration.", - W026: "Inner functions should be listed at the top of the outer function.", - W027: "Unreachable '{a}' after '{b}'.", - W028: "Label '{a}' on {b} statement.", - W030: "Expected an assignment or function call and instead saw an expression.", - W031: "Do not use 'new' for side effects.", - W032: "Unnecessary semicolon.", - W033: "Missing semicolon.", - W034: "Unnecessary directive \"{a}\".", - W035: "Empty block.", - W036: "Unexpected /*member '{a}'.", - W037: "'{a}' is a statement label.", - W038: "'{a}' used out of scope.", - W039: "'{a}' is not allowed.", - W040: "Possible strict violation.", - W041: "Use '{a}' to compare with '{b}'.", - W042: "Avoid EOL escaping.", - W043: "Bad escaping of EOL. Use option multistr if needed.", - W044: "Bad or unnecessary escaping.", - W045: "Bad number '{a}'.", - W046: "Don't use extra leading zeros '{a}'.", - W047: "A trailing decimal point can be confused with a dot: '{a}'.", - W048: "Unexpected control character in regular expression.", - W049: "Unexpected escaped character '{a}' in regular expression.", - W050: "JavaScript URL.", - W051: "Variables should not be deleted.", - W052: "Unexpected '{a}'.", - W053: "Do not use {a} as a constructor.", - W054: "The Function constructor is a form of eval.", - W055: "A constructor name should start with an uppercase letter.", - W056: "Bad constructor.", - W057: "Weird construction. Is 'new' unnecessary?", - W058: "Missing '()' invoking a constructor.", - W059: "Avoid arguments.{a}.", - W060: "document.write can be a form of eval.", - W061: "eval can be harmful.", - W062: "Wrap an immediate function invocation in parens " + - "to assist the reader in understanding that the expression " + - "is the result of a function, and not the function itself.", - W063: "Math is not a function.", - W064: "Missing 'new' prefix when invoking a constructor.", - W065: "Missing radix parameter.", - W066: "Implied eval. Consider passing a function instead of a string.", - W067: "Bad invocation.", - W068: "Wrapping non-IIFE function literals in parens is unnecessary.", - W069: "['{a}'] is better written in dot notation.", - W070: "Extra comma. (it breaks older versions of IE)", - W071: "This function has too many statements. ({a})", - W072: "This function has too many parameters. ({a})", - W073: "Blocks are nested too deeply. ({a})", - W074: "This function's cyclomatic complexity is too high. ({a})", - W075: "Duplicate key '{a}'.", - W076: "Unexpected parameter '{a}' in get {b} function.", - W077: "Expected a single parameter in set {a} function.", - W078: "Setter is defined without getter.", - W079: "Redefinition of '{a}'.", - W080: "It's not necessary to initialize '{a}' to 'undefined'.", - W081: "Too many var statements.", - W082: "Function declarations should not be placed in blocks. " + - "Use a function expression or move the statement to the top of " + - "the outer function.", - W083: "Don't make functions within a loop.", - W084: "Expected a conditional expression and instead saw an assignment.", - W085: "Don't use 'with'.", - W086: "Expected a 'break' statement before '{a}'.", - W087: "Forgotten 'debugger' statement?", - W088: "Creating global 'for' variable. Should be 'for (var {a} ...'.", - W089: "The body of a for in should be wrapped in an if statement to filter " + - "unwanted properties from the prototype.", - W090: "'{a}' is not a statement label.", - W091: "'{a}' is out of scope.", - W092: "Wrap the /regexp/ literal in parens to disambiguate the slash operator.", - W093: "Did you mean to return a conditional instead of an assignment?", - W094: "Unexpected comma.", - W095: "Expected a string and instead saw {a}.", - W096: "The '{a}' key may produce unexpected results.", - W097: "Use the function form of \"use strict\".", - W098: "'{a}' is defined but never used.", - W099: "Mixed spaces and tabs.", - W100: "This character may get silently deleted by one or more browsers.", - W101: "Line is too long.", - W102: "Trailing whitespace.", - W103: "The '{a}' property is deprecated.", - W104: "'{a}' is only available in JavaScript 1.7.", - W105: "Unexpected {a} in '{b}'.", - W106: "Identifier '{a}' is not in camel case.", - W107: "Script URL.", - W108: "Strings must use doublequote.", - W109: "Strings must use singlequote.", - W110: "Mixed double and single quotes.", - W112: "Unclosed string.", - W113: "Control character in string: {a}.", - W114: "Avoid {a}.", - W115: "Octal literals are not allowed in strict mode.", - W116: "Expected '{a}' and instead saw '{b}'.", - W117: "'{a}' is not defined.", - W118: "'{a}' is only available in Mozilla JavaScript extensions (use moz option).", - W119: "'{a}' is only available in ES6 (use esnext option)." -}; - -var info = { - I001: "Comma warnings can be turned off with 'laxcomma'.", - I002: "Reserved words as properties can be used under the 'es5' option.", - I003: "ES5 option is now set per default" -}; - -exports.errors = {}; -exports.warnings = {}; -exports.info = {}; - -_.each(errors, function (desc, code) { - exports.errors[code] = { code: code, desc: desc }; -}); - -_.each(warnings, function (desc, code) { - exports.warnings[code] = { code: code, desc: desc }; -}); - -_.each(info, function (desc, code) { - exports.info[code] = { code: code, desc: desc }; -}); - -})() -},{"underscore":11}],8:[function(require,module,exports){ -var events = require('events'); - -exports.isArray = isArray; -exports.isDate = function(obj){return Object.prototype.toString.call(obj) === '[object Date]'}; -exports.isRegExp = function(obj){return Object.prototype.toString.call(obj) === '[object RegExp]'}; - - -exports.print = function () {}; -exports.puts = function () {}; -exports.debug = function() {}; - -exports.inspect = function(obj, showHidden, depth, colors) { - var seen = []; - - var stylize = function(str, styleType) { - // http://en.wikipedia.org/wiki/ANSI_escape_code#graphics - var styles = - { 'bold' : [1, 22], - 'italic' : [3, 23], - 'underline' : [4, 24], - 'inverse' : [7, 27], - 'white' : [37, 39], - 'grey' : [90, 39], - 'black' : [30, 39], - 'blue' : [34, 39], - 'cyan' : [36, 39], - 'green' : [32, 39], - 'magenta' : [35, 39], - 'red' : [31, 39], - 'yellow' : [33, 39] }; - - var style = - { 'special': 'cyan', - 'number': 'blue', - 'boolean': 'yellow', - 'undefined': 'grey', - 'null': 'bold', - 'string': 'green', - 'date': 'magenta', - // "name": intentionally not styling - 'regexp': 'red' }[styleType]; - - if (style) { - return '\033[' + styles[style][0] + 'm' + str + - '\033[' + styles[style][1] + 'm'; - } else { - return str; - } - }; - if (! colors) { - stylize = function(str, styleType) { return str; }; - } - - function format(value, recurseTimes) { - // Provide a hook for user-specified inspect functions. - // Check that value is an object with an inspect function on it - if (value && typeof value.inspect === 'function' && - // Filter out the util module, it's inspect function is special - value !== exports && - // Also filter out any prototype objects using the circular check. - !(value.constructor && value.constructor.prototype === value)) { - return value.inspect(recurseTimes); - } - - // Primitive types cannot have properties - switch (typeof value) { - case 'undefined': - return stylize('undefined', 'undefined'); - - case 'string': - var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') - .replace(/'/g, "\\'") - .replace(/\\"/g, '"') + '\''; - return stylize(simple, 'string'); - - case 'number': - return stylize('' + value, 'number'); - - case 'boolean': - return stylize('' + value, 'boolean'); - } - // For some reason typeof null is "object", so special case here. - if (value === null) { - return stylize('null', 'null'); - } - - // Look up the keys of the object. - var visible_keys = Object_keys(value); - var keys = showHidden ? Object_getOwnPropertyNames(value) : visible_keys; - - // Functions without properties can be shortcutted. - if (typeof value === 'function' && keys.length === 0) { - if (isRegExp(value)) { - return stylize('' + value, 'regexp'); - } else { - var name = value.name ? ': ' + value.name : ''; - return stylize('[Function' + name + ']', 'special'); - } - } - - // Dates without properties can be shortcutted - if (isDate(value) && keys.length === 0) { - return stylize(value.toUTCString(), 'date'); - } - - var base, type, braces; - // Determine the object type - if (isArray(value)) { - type = 'Array'; - braces = ['[', ']']; - } else { - type = 'Object'; - braces = ['{', '}']; - } - - // Make functions say that they are functions - if (typeof value === 'function') { - var n = value.name ? ': ' + value.name : ''; - base = (isRegExp(value)) ? ' ' + value : ' [Function' + n + ']'; - } else { - base = ''; - } - - // Make dates with properties first say the date - if (isDate(value)) { - base = ' ' + value.toUTCString(); - } - - if (keys.length === 0) { - return braces[0] + base + braces[1]; - } - - if (recurseTimes < 0) { - if (isRegExp(value)) { - return stylize('' + value, 'regexp'); - } else { - return stylize('[Object]', 'special'); - } - } - - seen.push(value); - - var output = keys.map(function(key) { - var name, str; - if (value.__lookupGetter__) { - if (value.__lookupGetter__(key)) { - if (value.__lookupSetter__(key)) { - str = stylize('[Getter/Setter]', 'special'); - } else { - str = stylize('[Getter]', 'special'); - } - } else { - if (value.__lookupSetter__(key)) { - str = stylize('[Setter]', 'special'); - } - } - } - if (visible_keys.indexOf(key) < 0) { - name = '[' + key + ']'; - } - if (!str) { - if (seen.indexOf(value[key]) < 0) { - if (recurseTimes === null) { - str = format(value[key]); - } else { - str = format(value[key], recurseTimes - 1); - } - if (str.indexOf('\n') > -1) { - if (isArray(value)) { - str = str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n').substr(2); - } else { - str = '\n' + str.split('\n').map(function(line) { - return ' ' + line; - }).join('\n'); - } - } - } else { - str = stylize('[Circular]', 'special'); - } - } - if (typeof name === 'undefined') { - if (type === 'Array' && key.match(/^\d+$/)) { - return str; - } - name = JSON.stringify('' + key); - if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { - name = name.substr(1, name.length - 2); - name = stylize(name, 'name'); - } else { - name = name.replace(/'/g, "\\'") - .replace(/\\"/g, '"') - .replace(/(^"|"$)/g, "'"); - name = stylize(name, 'string'); - } - } - - return name + ': ' + str; - }); - - seen.pop(); - - var numLinesEst = 0; - var length = output.reduce(function(prev, cur) { - numLinesEst++; - if (cur.indexOf('\n') >= 0) numLinesEst++; - return prev + cur.length + 1; - }, 0); - - if (length > 50) { - output = braces[0] + - (base === '' ? '' : base + '\n ') + - ' ' + - output.join(',\n ') + - ' ' + - braces[1]; - - } else { - output = braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; - } - - return output; - } - return format(obj, (typeof depth === 'undefined' ? 2 : depth)); -}; - - -function isArray(ar) { - return ar instanceof Array || - Array.isArray(ar) || - (ar && ar !== Object.prototype && isArray(ar.__proto__)); -} - - -function isRegExp(re) { - return re instanceof RegExp || - (typeof re === 'object' && Object.prototype.toString.call(re) === '[object RegExp]'); -} - - -function isDate(d) { - if (d instanceof Date) return true; - if (typeof d !== 'object') return false; - var properties = Date.prototype && Object_getOwnPropertyNames(Date.prototype); - var proto = d.__proto__ && Object_getOwnPropertyNames(d.__proto__); - return JSON.stringify(proto) === JSON.stringify(properties); -} - -function pad(n) { - return n < 10 ? '0' + n.toString(10) : n.toString(10); -} - -var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', - 'Oct', 'Nov', 'Dec']; - -// 26 Feb 16:19:34 -function timestamp() { - var d = new Date(); - var time = [pad(d.getHours()), - pad(d.getMinutes()), - pad(d.getSeconds())].join(':'); - return [d.getDate(), months[d.getMonth()], time].join(' '); -} - -exports.log = function (msg) {}; - -exports.pump = null; - -var Object_keys = Object.keys || function (obj) { - var res = []; - for (var key in obj) res.push(key); - return res; -}; - -var Object_getOwnPropertyNames = Object.getOwnPropertyNames || function (obj) { - var res = []; - for (var key in obj) { - if (Object.hasOwnProperty.call(obj, key)) res.push(key); - } - return res; -}; - -var Object_create = Object.create || function (prototype, properties) { - // from es5-shim - var object; - if (prototype === null) { - object = { '__proto__' : null }; - } - else { - if (typeof prototype !== 'object') { - throw new TypeError( - 'typeof prototype[' + (typeof prototype) + '] != \'object\'' - ); - } - var Type = function () {}; - Type.prototype = prototype; - object = new Type(); - object.__proto__ = prototype; - } - if (typeof properties !== 'undefined' && Object.defineProperties) { - Object.defineProperties(object, properties); - } - return object; -}; - -exports.inherits = function(ctor, superCtor) { - ctor.super_ = superCtor; - ctor.prototype = Object_create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); -}; - -var formatRegExp = /%[sdj%]/g; -exports.format = function(f) { - if (typeof f !== 'string') { - var objects = []; - for (var i = 0; i < arguments.length; i++) { - objects.push(exports.inspect(arguments[i])); - } - return objects.join(' '); - } - - var i = 1; - var args = arguments; - var len = args.length; - var str = String(f).replace(formatRegExp, function(x) { - if (x === '%%') return '%'; - if (i >= len) return x; - switch (x) { - case '%s': return String(args[i++]); - case '%d': return Number(args[i++]); - case '%j': return JSON.stringify(args[i++]); - default: - return x; - } - }); - for(var x = args[i]; i < len; x = args[++i]){ - if (x === null || typeof x !== 'object') { - str += ' ' + x; - } else { - str += ' ' + exports.inspect(x); - } - } - return str; -}; - -},{"events":2}],9:[function(require,module,exports){ -(function(){// UTILITY -var util = require('util'); -var Buffer = require("buffer").Buffer; -var pSlice = Array.prototype.slice; - -function objectKeys(object) { - if (Object.keys) return Object.keys(object); - var result = []; - for (var name in object) { - if (Object.prototype.hasOwnProperty.call(object, name)) { - result.push(name); - } - } - return result; -} - -// 1. The assert module provides functions that throw -// AssertionError's when particular conditions are not met. The -// assert module must conform to the following interface. - -var assert = module.exports = ok; - -// 2. The AssertionError is defined in assert. -// new assert.AssertionError({ message: message, -// actual: actual, -// expected: expected }) - -assert.AssertionError = function AssertionError(options) { - this.name = 'AssertionError'; - this.message = options.message; - this.actual = options.actual; - this.expected = options.expected; - this.operator = options.operator; - var stackStartFunction = options.stackStartFunction || fail; - - if (Error.captureStackTrace) { - Error.captureStackTrace(this, stackStartFunction); - } -}; -util.inherits(assert.AssertionError, Error); - -function replacer(key, value) { - if (value === undefined) { - return '' + value; - } - if (typeof value === 'number' && (isNaN(value) || !isFinite(value))) { - return value.toString(); - } - if (typeof value === 'function' || value instanceof RegExp) { - return value.toString(); - } - return value; -} - -function truncate(s, n) { - if (typeof s == 'string') { - return s.length < n ? s : s.slice(0, n); - } else { - return s; - } -} - -assert.AssertionError.prototype.toString = function() { - if (this.message) { - return [this.name + ':', this.message].join(' '); - } else { - return [ - this.name + ':', - truncate(JSON.stringify(this.actual, replacer), 128), - this.operator, - truncate(JSON.stringify(this.expected, replacer), 128) - ].join(' '); - } -}; - -// assert.AssertionError instanceof Error - -assert.AssertionError.__proto__ = Error.prototype; - -// At present only the three keys mentioned above are used and -// understood by the spec. Implementations or sub modules can pass -// other keys to the AssertionError's constructor - they will be -// ignored. - -// 3. All of the following functions must throw an AssertionError -// when a corresponding condition is not met, with a message that -// may be undefined if not provided. All assertion methods provide -// both the actual and expected values to the assertion error for -// display purposes. - -function fail(actual, expected, message, operator, stackStartFunction) { - throw new assert.AssertionError({ - message: message, - actual: actual, - expected: expected, - operator: operator, - stackStartFunction: stackStartFunction - }); -} - -// EXTENSION! allows for well behaved errors defined elsewhere. -assert.fail = fail; - -// 4. Pure assertion tests whether a value is truthy, as determined -// by !!guard. -// assert.ok(guard, message_opt); -// This statement is equivalent to assert.equal(true, guard, -// message_opt);. To test strictly for the value true, use -// assert.strictEqual(true, guard, message_opt);. - -function ok(value, message) { - if (!!!value) fail(value, true, message, '==', assert.ok); -} -assert.ok = ok; - -// 5. The equality assertion tests shallow, coercive equality with -// ==. -// assert.equal(actual, expected, message_opt); - -assert.equal = function equal(actual, expected, message) { - if (actual != expected) fail(actual, expected, message, '==', assert.equal); -}; - -// 6. The non-equality assertion tests for whether two objects are not equal -// with != assert.notEqual(actual, expected, message_opt); - -assert.notEqual = function notEqual(actual, expected, message) { - if (actual == expected) { - fail(actual, expected, message, '!=', assert.notEqual); - } -}; - -// 7. The equivalence assertion tests a deep equality relation. -// assert.deepEqual(actual, expected, message_opt); - -assert.deepEqual = function deepEqual(actual, expected, message) { - if (!_deepEqual(actual, expected)) { - fail(actual, expected, message, 'deepEqual', assert.deepEqual); - } -}; - -function _deepEqual(actual, expected) { - // 7.1. All identical values are equivalent, as determined by ===. - if (actual === expected) { - return true; - - } else if (Buffer.isBuffer(actual) && Buffer.isBuffer(expected)) { - if (actual.length != expected.length) return false; - - for (var i = 0; i < actual.length; i++) { - if (actual[i] !== expected[i]) return false; - } - - return true; - - // 7.2. If the expected value is a Date object, the actual value is - // equivalent if it is also a Date object that refers to the same time. - } else if (actual instanceof Date && expected instanceof Date) { - return actual.getTime() === expected.getTime(); - - // 7.3. Other pairs that do not both pass typeof value == 'object', - // equivalence is determined by ==. - } else if (typeof actual != 'object' && typeof expected != 'object') { - return actual == expected; - - // 7.4. For all other Object pairs, including Array objects, equivalence is - // determined by having the same number of owned properties (as verified - // with Object.prototype.hasOwnProperty.call), the same set of keys - // (although not necessarily the same order), equivalent values for every - // corresponding key, and an identical 'prototype' property. Note: this - // accounts for both named and indexed properties on Arrays. - } else { - return objEquiv(actual, expected); - } -} - -function isUndefinedOrNull(value) { - return value === null || value === undefined; -} - -function isArguments(object) { - return Object.prototype.toString.call(object) == '[object Arguments]'; -} - -function objEquiv(a, b) { - if (isUndefinedOrNull(a) || isUndefinedOrNull(b)) - return false; - // an identical 'prototype' property. - if (a.prototype !== b.prototype) return false; - //~~~I've managed to break Object.keys through screwy arguments passing. - // Converting to array solves the problem. - if (isArguments(a)) { - if (!isArguments(b)) { - return false; - } - a = pSlice.call(a); - b = pSlice.call(b); - return _deepEqual(a, b); - } - try { - var ka = objectKeys(a), - kb = objectKeys(b), - key, i; - } catch (e) {//happens when one is a string literal and the other isn't - return false; - } - // having the same number of owned properties (keys incorporates - // hasOwnProperty) - if (ka.length != kb.length) - return false; - //the same set of keys (although not necessarily the same order), - ka.sort(); - kb.sort(); - //~~~cheap key test - for (i = ka.length - 1; i >= 0; i--) { - if (ka[i] != kb[i]) - return false; - } - //equivalent values for every corresponding key, and - //~~~possibly expensive deep test - for (i = ka.length - 1; i >= 0; i--) { - key = ka[i]; - if (!_deepEqual(a[key], b[key])) return false; - } - return true; -} - -// 8. The non-equivalence assertion tests for any deep inequality. -// assert.notDeepEqual(actual, expected, message_opt); - -assert.notDeepEqual = function notDeepEqual(actual, expected, message) { - if (_deepEqual(actual, expected)) { - fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); - } -}; - -// 9. The strict equality assertion tests strict equality, as determined by ===. -// assert.strictEqual(actual, expected, message_opt); - -assert.strictEqual = function strictEqual(actual, expected, message) { - if (actual !== expected) { - fail(actual, expected, message, '===', assert.strictEqual); - } -}; - -// 10. The strict non-equality assertion tests for strict inequality, as -// determined by !==. assert.notStrictEqual(actual, expected, message_opt); - -assert.notStrictEqual = function notStrictEqual(actual, expected, message) { - if (actual === expected) { - fail(actual, expected, message, '!==', assert.notStrictEqual); - } -}; - -function expectedException(actual, expected) { - if (!actual || !expected) { - return false; - } - - if (expected instanceof RegExp) { - return expected.test(actual); - } else if (actual instanceof expected) { - return true; - } else if (expected.call({}, actual) === true) { - return true; - } - - return false; -} - -function _throws(shouldThrow, block, expected, message) { - var actual; - - if (typeof expected === 'string') { - message = expected; - expected = null; - } - - try { - block(); - } catch (e) { - actual = e; - } - - message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + - (message ? ' ' + message : '.'); - - if (shouldThrow && !actual) { - fail('Missing expected exception' + message); - } - - if (!shouldThrow && expectedException(actual, expected)) { - fail('Got unwanted exception' + message); - } - - if ((shouldThrow && actual && expected && - !expectedException(actual, expected)) || (!shouldThrow && actual)) { - throw actual; - } -} - -// 11. Expected to throw an error: -// assert.throws(block, Error_opt, message_opt); - -assert.throws = function(block, /*optional*/error, /*optional*/message) { - _throws.apply(this, [true].concat(pSlice.call(arguments))); -}; - -// EXTENSION! This is annoying to write outside this module. -assert.doesNotThrow = function(block, /*optional*/error, /*optional*/message) { - _throws.apply(this, [false].concat(pSlice.call(arguments))); -}; - -assert.ifError = function(err) { if (err) {throw err;}}; - -})() -},{"util":8,"buffer":13}],11:[function(require,module,exports){ -(function(){// Underscore.js 1.4.4 -// http://underscorejs.org -// (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore may be freely distributed under the MIT license. - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var push = ArrayProto.push, - slice = ArrayProto.slice, - concat = ArrayProto.concat, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { - if (obj instanceof _) return obj; - if (!(this instanceof _)) return new _(obj); - this._wrapped = obj; - }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object via a string identifier, - // for Closure Compiler "advanced" mode. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root._ = _; - } - - // Current version. - _.VERSION = '1.4.4'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - if (iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var key in obj) { - if (_.has(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } - } - } - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); - }); - return results; - }; - - var reduceError = 'Reduce of empty array with no initial value'; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var length = obj.length; - if (length !== +length) { - var keys = _.keys(obj); - length = keys.length; - } - each(obj, function(value, index, list) { - index = keys ? keys[--length] : --length; - if (!initial) { - memo = obj[index]; - initial = true; - } else { - memo = iterator.call(context, memo, obj[index], index, list); - } - }); - if (!initial) throw new TypeError(reduceError); - return memo; - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { - var result; - any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); - each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { - return _.filter(obj, function(value, index, list) { - return !iterator.call(context, value, index, list); - }, context); - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); - each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); - each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if the array or object contains a given value (using `===`). - // Aliased as `include`. - _.contains = _.include = function(obj, target) { - if (obj == null) return false; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - return any(obj, function(value) { - return value === target; - }); - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - var isFunc = _.isFunction(method); - return _.map(obj, function(value) { - return (isFunc ? method : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); - }; - - // Convenience version of a common use case of `filter`: selecting only objects - // containing specific `key:value` pairs. - _.where = function(obj, attrs, first) { - if (_.isEmpty(attrs)) return first ? null : []; - return _[first ? 'find' : 'filter'](obj, function(value) { - for (var key in attrs) { - if (attrs[key] !== value[key]) return false; - } - return true; - }); - }; - - // Convenience version of a common use case of `find`: getting the first object - // containing specific `key:value` pairs. - _.findWhere = function(obj, attrs) { - return _.where(obj, attrs, true); - }; - - // Return the maximum element or (element-based computation). - // Can't optimize arrays of integers longer than 65,535 elements. - // See: https://bugs.webkit.org/show_bug.cgi?id=80797 - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.max.apply(Math, obj); - } - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity, value: -Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) { - return Math.min.apply(Math, obj); - } - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity, value: Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Shuffle an array. - _.shuffle = function(obj) { - var rand; - var index = 0; - var shuffled = []; - each(obj, function(value) { - rand = _.random(index++); - shuffled[index - 1] = shuffled[rand]; - shuffled[rand] = value; - }); - return shuffled; - }; - - // An internal function to generate lookup iterators. - var lookupIterator = function(value) { - return _.isFunction(value) ? value : function(obj){ return obj[value]; }; - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, value, context) { - var iterator = lookupIterator(value); - return _.pluck(_.map(obj, function(value, index, list) { - return { - value : value, - index : index, - criteria : iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria; - var b = right.criteria; - if (a !== b) { - if (a > b || a === void 0) return 1; - if (a < b || b === void 0) return -1; - } - return left.index < right.index ? -1 : 1; - }), 'value'); - }; - - // An internal function used for aggregate "group by" operations. - var group = function(obj, value, context, behavior) { - var result = {}; - var iterator = lookupIterator(value || _.identity); - each(obj, function(value, index) { - var key = iterator.call(context, value, index, obj); - behavior(result, key, value); - }); - return result; - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = function(obj, value, context) { - return group(obj, value, context, function(result, key, value) { - (_.has(result, key) ? result[key] : (result[key] = [])).push(value); - }); - }; - - // Counts instances of an object that group by a certain criterion. Pass - // either a string attribute to count by, or a function that returns the - // criterion. - _.countBy = function(obj, value, context) { - return group(obj, value, context, function(result, key) { - if (!_.has(result, key)) result[key] = 0; - result[key]++; - }); - }; - - // Use a comparator function to figure out the smallest index at which - // an object should be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator, context) { - iterator = iterator == null ? _.identity : lookupIterator(iterator); - var value = iterator.call(context, obj); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >>> 1; - iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely convert anything iterable into a real, live array. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (obj.length === +obj.length) return _.map(obj, _.identity); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - if (obj == null) return 0; - return (obj.length === +obj.length) ? obj.length : _.keys(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - if (array == null) return void 0; - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; - }; - - // Returns everything but the last entry of the array. Especially useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. The **guard** check allows it to work with - // `_.map`. - _.initial = function(array, n, guard) { - return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. The **guard** check allows it to work with `_.map`. - _.last = function(array, n, guard) { - if (array == null) return void 0; - if ((n != null) && !guard) { - return slice.call(array, Math.max(array.length - n, 0)); - } else { - return array[array.length - 1]; - } - }; - - // Returns everything but the first entry of the array. Aliased as `tail` and `drop`. - // Especially useful on the arguments object. Passing an **n** will return - // the rest N values in the array. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = _.drop = function(array, n, guard) { - return slice.call(array, (n == null) || guard ? 1 : n); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, _.identity); - }; - - // Internal implementation of a recursive `flatten` function. - var flatten = function(input, shallow, output) { - each(input, function(value) { - if (_.isArray(value)) { - shallow ? push.apply(output, value) : flatten(value, shallow, output); - } else { - output.push(value); - } - }); - return output; - }; - - // Return a completely flattened version of an array. - _.flatten = function(array, shallow) { - return flatten(array, shallow, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iterator, context) { - if (_.isFunction(isSorted)) { - context = iterator; - iterator = isSorted; - isSorted = false; - } - var initial = iterator ? _.map(array, iterator, context) : array; - var results = []; - var seen = []; - each(initial, function(value, index) { - if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) { - seen.push(value); - results.push(array[index]); - } - }); - return results; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(concat.apply(ArrayProto, arguments)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. - _.intersection = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; - }); - }); - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = concat.apply(ArrayProto, slice.call(arguments, 1)); - return _.filter(array, function(value){ return !_.contains(rest, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) { - results[i] = _.pluck(args, "" + i); - } - return results; - }; - - // Converts lists into objects. Pass either a single array of `[key, value]` - // pairs, or two parallel arrays of the same length -- one of keys, and one of - // the corresponding values. - _.object = function(list, values) { - if (list == null) return {}; - var result = {}; - for (var i = 0, l = list.length; i < l; i++) { - if (values) { - result[list[i]] = values[i]; - } else { - result[list[i][0]] = list[i][1]; - } - } - return result; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i = 0, l = array.length; - if (isSorted) { - if (typeof isSorted == 'number') { - i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted); - } else { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted); - for (; i < l; i++) if (array[i] === item) return i; - return -1; - }; - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item, from) { - if (array == null) return -1; - var hasIndex = from != null; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) { - return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item); - } - var i = (hasIndex ? from : array.length); - while (i--) if (array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var len = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(len); - - while(idx < len) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if - // available. - _.bind = function(func, context) { - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - var args = slice.call(arguments, 2); - return function() { - return func.apply(context, args.concat(slice.call(arguments))); - }; - }; - - // Partially apply a function by creating a version that has had some of its - // arguments pre-filled, without changing its dynamic `this` context. - _.partial = function(func) { - var args = slice.call(arguments, 1); - return function() { - return func.apply(this, args.concat(slice.call(arguments))); - }; - }; - - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length === 0) funcs = _.functions(obj); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(null, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - var context, args, timeout, result; - var previous = 0; - var later = function() { - previous = new Date; - timeout = null; - result = func.apply(context, args); - }; - return function() { - var now = new Date; - var remaining = wait - (now - previous); - context = this; - args = arguments; - if (remaining <= 0) { - clearTimeout(timeout); - timeout = null; - previous = now; - result = func.apply(context, args); - } else if (!timeout) { - timeout = setTimeout(later, remaining); - } - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout, result; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) result = func.apply(context, args); - }; - var callNow = immediate && !timeout; - clearTimeout(timeout); - timeout = setTimeout(later, wait); - if (callNow) result = func.apply(context, args); - return result; - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - memo = func.apply(this, arguments); - func = null; - return memo; - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return function() { - var args = [func]; - push.apply(args, arguments); - return wrapper.apply(this, args); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = arguments; - return function() { - var args = arguments; - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - if (times <= 0) return func(); - return function() { - if (--times < 1) { - return func.apply(this, arguments); - } - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - var values = []; - for (var key in obj) if (_.has(obj, key)) values.push(obj[key]); - return values; - }; - - // Convert an object into a list of `[key, value]` pairs. - _.pairs = function(obj) { - var pairs = []; - for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]); - return pairs; - }; - - // Invert the keys and values of an object. The values must be serializable. - _.invert = function(obj) { - var result = {}; - for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key; - return result; - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - each(keys, function(key) { - if (key in obj) copy[key] = obj[key]; - }); - return copy; - }; - - // Return a copy of the object without the blacklisted properties. - _.omit = function(obj) { - var copy = {}; - var keys = concat.apply(ArrayProto, slice.call(arguments, 1)); - for (var key in obj) { - if (!_.contains(keys, key)) copy[key] = obj[key]; - } - return copy; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - if (source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Internal recursive comparison function for `isEqual`. - var eq = function(a, b, aStack, bStack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. - if (a === b) return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a instanceof _) a = a._wrapped; - if (b instanceof _) b = b._wrapped; - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') return false; - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - var length = aStack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (aStack[length] == a) return bStack[length] == b; - } - // Add the first object to the stack of traversed objects. - aStack.push(a); - bStack.push(b); - var size = 0, result = true; - // Recursively compare objects and arrays. - if (className == '[object Array]') { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - if (!(result = eq(a[size], b[size], aStack, bStack))) break; - } - } - } else { - // Objects with different constructors are not equivalent, but `Object`s - // from different frames are. - var aCtor = a.constructor, bCtor = b.constructor; - if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) && - _.isFunction(bCtor) && (bCtor instanceof bCtor))) { - return false; - } - // Deep compare objects. - for (var key in a) { - if (_.has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (_.has(b, key) && !(size--)) break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - aStack.pop(); - bStack.pop(); - return result; - }; - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b, [], []); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (_.has(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType === 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp. - each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) { - _['is' + name] = function(obj) { - return toString.call(obj) == '[object ' + name + ']'; - }; - }); - - // Define a fallback version of the method in browsers (ahem, IE), where - // there isn't any inspectable "Arguments" type. - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return !!(obj && _.has(obj, 'callee')); - }; - } - - // Optimize `isFunction` if appropriate. - if (typeof (/./) !== 'function') { - _.isFunction = function(obj) { - return typeof obj === 'function'; - }; - } - - // Is a given object a finite number? - _.isFinite = function(obj) { - return isFinite(obj) && !isNaN(parseFloat(obj)); - }; - - // Is the given value `NaN`? (NaN is the only number which does not equal itself). - _.isNaN = function(obj) { - return _.isNumber(obj) && obj != +obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Shortcut function for checking if an object has a given property directly - // on itself (in other words, not on a prototype). - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - // Run a function **n** times. - _.times = function(n, iterator, context) { - var accum = Array(n); - for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i); - return accum; - }; - - // Return a random integer between min and max (inclusive). - _.random = function(min, max) { - if (max == null) { - max = min; - min = 0; - } - return min + Math.floor(Math.random() * (max - min + 1)); - }; - - // List of HTML entities for escaping. - var entityMap = { - escape: { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''', - '/': '/' - } - }; - entityMap.unescape = _.invert(entityMap.escape); - - // Regexes containing the keys and values listed immediately above. - var entityRegexes = { - escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'), - unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g') - }; - - // Functions for escaping and unescaping strings to/from HTML interpolation. - _.each(['escape', 'unescape'], function(method) { - _[method] = function(string) { - if (string == null) return ''; - return ('' + string).replace(entityRegexes[method], function(match) { - return entityMap[method][match]; - }); - }; - }); - - // If the value of the named property is a function then invoke it; - // otherwise, return it. - _.result = function(object, property) { - if (object == null) return null; - var value = object[property]; - return _.isFunction(value) ? value.call(object) : value; - }; - - // Add your own custom functions to the Underscore object. - _.mixin = function(obj) { - each(_.functions(obj), function(name){ - var func = _[name] = obj[name]; - _.prototype[name] = function() { - var args = [this._wrapped]; - push.apply(args, arguments); - return result.call(this, func.apply(_, args)); - }; - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = ++idCounter + ''; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /(.)^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - "'": "'", - '\\': '\\', - '\r': 'r', - '\n': 'n', - '\t': 't', - '\u2028': 'u2028', - '\u2029': 'u2029' - }; - - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(text, data, settings) { - var render; - settings = _.defaults({}, settings, _.templateSettings); - - // Combine delimiters into one regular expression via alternation. - var matcher = new RegExp([ - (settings.escape || noMatch).source, - (settings.interpolate || noMatch).source, - (settings.evaluate || noMatch).source - ].join('|') + '|$', 'g'); - - // Compile the template source, escaping string literals appropriately. - var index = 0; - var source = "__p+='"; - text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { - source += text.slice(index, offset) - .replace(escaper, function(match) { return '\\' + escapes[match]; }); - - if (escape) { - source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; - } - if (interpolate) { - source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; - } - if (evaluate) { - source += "';\n" + evaluate + "\n__p+='"; - } - index = offset + match.length; - return match; - }); - source += "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __t,__p='',__j=Array.prototype.join," + - "print=function(){__p+=__j.call(arguments,'');};\n" + - source + "return __p;\n"; - - try { - render = new Function(settings.variable || 'obj', '_', source); - } catch (e) { - e.source = source; - throw e; - } - - if (data) return render(data, _); - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled function source as a convenience for precompilation. - template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; - - return template; - }; - - // Add a "chain" function, which will delegate to the wrapper. - _.chain = function(obj) { - return _(obj).chain(); - }; - - // OOP - // --------------- - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - - // Helper function to continue chaining intermediate results. - var result = function(obj) { - return this._chain ? _(obj).chain() : obj; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - var obj = this._wrapped; - method.apply(obj, arguments); - if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0]; - return result.call(this, obj); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - _.prototype[name] = function() { - return result.call(this, method.apply(this._wrapped, arguments)); - }; - }); - - _.extend(_.prototype, { - - // Start chaining a wrapped Underscore object. - chain: function() { - this._chain = true; - return this; - }, - - // Extracts the result from a wrapped and chained object. - value: function() { - return this._wrapped; - } - - }); - -}).call(this); - -})() -},{}],14:[function(require,module,exports){ -exports.readIEEE754 = function(buffer, offset, isBE, mLen, nBytes) { - var e, m, - eLen = nBytes * 8 - mLen - 1, - eMax = (1 << eLen) - 1, - eBias = eMax >> 1, - nBits = -7, - i = isBE ? 0 : (nBytes - 1), - d = isBE ? 1 : -1, - s = buffer[offset + i]; - - i += d; - - e = s & ((1 << (-nBits)) - 1); - s >>= (-nBits); - nBits += eLen; - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); - - m = e & ((1 << (-nBits)) - 1); - e >>= (-nBits); - nBits += mLen; - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); - - if (e === 0) { - e = 1 - eBias; - } else if (e === eMax) { - return m ? NaN : ((s ? -1 : 1) * Infinity); - } else { - m = m + Math.pow(2, mLen); - e = e - eBias; - } - return (s ? -1 : 1) * m * Math.pow(2, e - mLen); -}; - -exports.writeIEEE754 = function(buffer, value, offset, isBE, mLen, nBytes) { - var e, m, c, - eLen = nBytes * 8 - mLen - 1, - eMax = (1 << eLen) - 1, - eBias = eMax >> 1, - rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), - i = isBE ? (nBytes - 1) : 0, - d = isBE ? -1 : 1, - s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; - - value = Math.abs(value); - - if (isNaN(value) || value === Infinity) { - m = isNaN(value) ? 1 : 0; - e = eMax; - } else { - e = Math.floor(Math.log(value) / Math.LN2); - if (value * (c = Math.pow(2, -e)) < 1) { - e--; - c *= 2; - } - if (e + eBias >= 1) { - value += rt / c; - } else { - value += rt * Math.pow(2, 1 - eBias); - } - if (value * c >= 2) { - e++; - c /= 2; - } - - if (e + eBias >= eMax) { - m = 0; - e = eMax; - } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen); - e = e + eBias; - } else { - m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); - e = 0; - } - } - - for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); - - e = (e << mLen) | m; - eLen += mLen; - for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); - - buffer[offset + i - d] |= s * 128; -}; - -},{}],13:[function(require,module,exports){ -(function(){function SlowBuffer (size) { - this.length = size; -}; - -var assert = require('assert'); - -exports.INSPECT_MAX_BYTES = 50; - - -function toHex(n) { - if (n < 16) return '0' + n.toString(16); - return n.toString(16); -} - -function utf8ToBytes(str) { - var byteArray = []; - for (var i = 0; i < str.length; i++) - if (str.charCodeAt(i) <= 0x7F) - byteArray.push(str.charCodeAt(i)); - else { - var h = encodeURIComponent(str.charAt(i)).substr(1).split('%'); - for (var j = 0; j < h.length; j++) - byteArray.push(parseInt(h[j], 16)); - } - - return byteArray; -} - -function asciiToBytes(str) { - var byteArray = [] - for (var i = 0; i < str.length; i++ ) - // Node's code seems to be doing this and not & 0x7F.. - byteArray.push( str.charCodeAt(i) & 0xFF ); - - return byteArray; -} - -function base64ToBytes(str) { - return require("base64-js").toByteArray(str); -} - -SlowBuffer.byteLength = function (str, encoding) { - switch (encoding || "utf8") { - case 'hex': - return str.length / 2; - - case 'utf8': - case 'utf-8': - return utf8ToBytes(str).length; - - case 'ascii': - case 'binary': - return str.length; - - case 'base64': - return base64ToBytes(str).length; - - default: - throw new Error('Unknown encoding'); - } -}; - -function blitBuffer(src, dst, offset, length) { - var pos, i = 0; - while (i < length) { - if ((i+offset >= dst.length) || (i >= src.length)) - break; - - dst[i + offset] = src[i]; - i++; - } - return i; -} - -SlowBuffer.prototype.utf8Write = function (string, offset, length) { - var bytes, pos; - return SlowBuffer._charsWritten = blitBuffer(utf8ToBytes(string), this, offset, length); -}; - -SlowBuffer.prototype.asciiWrite = function (string, offset, length) { - var bytes, pos; - return SlowBuffer._charsWritten = blitBuffer(asciiToBytes(string), this, offset, length); -}; - -SlowBuffer.prototype.binaryWrite = SlowBuffer.prototype.asciiWrite; - -SlowBuffer.prototype.base64Write = function (string, offset, length) { - var bytes, pos; - return SlowBuffer._charsWritten = blitBuffer(base64ToBytes(string), this, offset, length); -}; - -SlowBuffer.prototype.base64Slice = function (start, end) { - var bytes = Array.prototype.slice.apply(this, arguments) - return require("base64-js").fromByteArray(bytes); -} - -function decodeUtf8Char(str) { - try { - return decodeURIComponent(str); - } catch (err) { - return String.fromCharCode(0xFFFD); // UTF 8 invalid char - } -} - -SlowBuffer.prototype.utf8Slice = function () { - var bytes = Array.prototype.slice.apply(this, arguments); - var res = ""; - var tmp = ""; - var i = 0; - while (i < bytes.length) { - if (bytes[i] <= 0x7F) { - res += decodeUtf8Char(tmp) + String.fromCharCode(bytes[i]); - tmp = ""; - } else - tmp += "%" + bytes[i].toString(16); - - i++; - } - - return res + decodeUtf8Char(tmp); -} - -SlowBuffer.prototype.asciiSlice = function () { - var bytes = Array.prototype.slice.apply(this, arguments); - var ret = ""; - for (var i = 0; i < bytes.length; i++) - ret += String.fromCharCode(bytes[i]); - return ret; -} - -SlowBuffer.prototype.binarySlice = SlowBuffer.prototype.asciiSlice; - -SlowBuffer.prototype.inspect = function() { - var out = [], - len = this.length; - for (var i = 0; i < len; i++) { - out[i] = toHex(this[i]); - if (i == exports.INSPECT_MAX_BYTES) { - out[i + 1] = '...'; - break; - } - } - return ''; -}; - - -SlowBuffer.prototype.hexSlice = function(start, end) { - var len = this.length; - - if (!start || start < 0) start = 0; - if (!end || end < 0 || end > len) end = len; - - var out = ''; - for (var i = start; i < end; i++) { - out += toHex(this[i]); - } - return out; -}; - - -SlowBuffer.prototype.toString = function(encoding, start, end) { - encoding = String(encoding || 'utf8').toLowerCase(); - start = +start || 0; - if (typeof end == 'undefined') end = this.length; - - // Fastpath empty strings - if (+end == start) { - return ''; - } - - switch (encoding) { - case 'hex': - return this.hexSlice(start, end); - - case 'utf8': - case 'utf-8': - return this.utf8Slice(start, end); - - case 'ascii': - return this.asciiSlice(start, end); - - case 'binary': - return this.binarySlice(start, end); - - case 'base64': - return this.base64Slice(start, end); - - case 'ucs2': - case 'ucs-2': - return this.ucs2Slice(start, end); - - default: - throw new Error('Unknown encoding'); - } -}; - - -SlowBuffer.prototype.hexWrite = function(string, offset, length) { - offset = +offset || 0; - var remaining = this.length - offset; - if (!length) { - length = remaining; - } else { - length = +length; - if (length > remaining) { - length = remaining; - } - } - - // must be an even number of digits - var strLen = string.length; - if (strLen % 2) { - throw new Error('Invalid hex string'); - } - if (length > strLen / 2) { - length = strLen / 2; - } - for (var i = 0; i < length; i++) { - var byte = parseInt(string.substr(i * 2, 2), 16); - if (isNaN(byte)) throw new Error('Invalid hex string'); - this[offset + i] = byte; - } - SlowBuffer._charsWritten = i * 2; - return i; -}; - - -SlowBuffer.prototype.write = function(string, offset, length, encoding) { - // Support both (string, offset, length, encoding) - // and the legacy (string, encoding, offset, length) - if (isFinite(offset)) { - if (!isFinite(length)) { - encoding = length; - length = undefined; - } - } else { // legacy - var swap = encoding; - encoding = offset; - offset = length; - length = swap; - } - - offset = +offset || 0; - var remaining = this.length - offset; - if (!length) { - length = remaining; - } else { - length = +length; - if (length > remaining) { - length = remaining; - } - } - encoding = String(encoding || 'utf8').toLowerCase(); - - switch (encoding) { - case 'hex': - return this.hexWrite(string, offset, length); - - case 'utf8': - case 'utf-8': - return this.utf8Write(string, offset, length); - - case 'ascii': - return this.asciiWrite(string, offset, length); - - case 'binary': - return this.binaryWrite(string, offset, length); - - case 'base64': - return this.base64Write(string, offset, length); - - case 'ucs2': - case 'ucs-2': - return this.ucs2Write(string, offset, length); - - default: - throw new Error('Unknown encoding'); - } -}; - - -// slice(start, end) -SlowBuffer.prototype.slice = function(start, end) { - if (end === undefined) end = this.length; - - if (end > this.length) { - throw new Error('oob'); - } - if (start > end) { - throw new Error('oob'); - } - - return new Buffer(this, end - start, +start); -}; - -SlowBuffer.prototype.copy = function(target, targetstart, sourcestart, sourceend) { - var temp = []; - for (var i=sourcestart; i this.length) { - throw new Error('oob'); - } - if (start > end) { - throw new Error('oob'); - } - - for (var i = start; i < end; i++) { - this[i] = value; - } -} - -function coerce(length) { - // Coerce length to a number (possibly NaN), round up - // in case it's fractional (e.g. 123.456) then do a - // double negate to coerce a NaN to 0. Easy, right? - length = ~~Math.ceil(+length); - return length < 0 ? 0 : length; -} - - -// Buffer - -function Buffer(subject, encoding, offset) { - if (!(this instanceof Buffer)) { - return new Buffer(subject, encoding, offset); - } - - var type; - - // Are we slicing? - if (typeof offset === 'number') { - this.length = coerce(encoding); - this.parent = subject; - this.offset = offset; - } else { - // Find the length - switch (type = typeof subject) { - case 'number': - this.length = coerce(subject); - break; - - case 'string': - this.length = Buffer.byteLength(subject, encoding); - break; - - case 'object': // Assume object is an array - this.length = coerce(subject.length); - break; - - default: - throw new Error('First argument needs to be a number, ' + - 'array or string.'); - } - - if (this.length > Buffer.poolSize) { - // Big buffer, just alloc one. - this.parent = new SlowBuffer(this.length); - this.offset = 0; - - } else { - // Small buffer. - if (!pool || pool.length - pool.used < this.length) allocPool(); - this.parent = pool; - this.offset = pool.used; - pool.used += this.length; - } - - // Treat array-ish objects as a byte array. - if (isArrayIsh(subject)) { - for (var i = 0; i < this.length; i++) { - if (subject instanceof Buffer) { - this.parent[i + this.offset] = subject.readUInt8(i); - } - else { - this.parent[i + this.offset] = subject[i]; - } - } - } else if (type == 'string') { - // We are a string - this.length = this.write(subject, 0, encoding); - } - } - -} - -function isArrayIsh(subject) { - return Array.isArray(subject) || Buffer.isBuffer(subject) || - subject && typeof subject === 'object' && - typeof subject.length === 'number'; -} - -exports.SlowBuffer = SlowBuffer; -exports.Buffer = Buffer; - -Buffer.poolSize = 8 * 1024; -var pool; - -function allocPool() { - pool = new SlowBuffer(Buffer.poolSize); - pool.used = 0; -} - - -// Static methods -Buffer.isBuffer = function isBuffer(b) { - return b instanceof Buffer || b instanceof SlowBuffer; -}; - -Buffer.concat = function (list, totalLength) { - if (!Array.isArray(list)) { - throw new Error("Usage: Buffer.concat(list, [totalLength])\n \ - list should be an Array."); - } - - if (list.length === 0) { - return new Buffer(0); - } else if (list.length === 1) { - return list[0]; - } - - if (typeof totalLength !== 'number') { - totalLength = 0; - for (var i = 0; i < list.length; i++) { - var buf = list[i]; - totalLength += buf.length; - } - } - - var buffer = new Buffer(totalLength); - var pos = 0; - for (var i = 0; i < list.length; i++) { - var buf = list[i]; - buf.copy(buffer, pos); - pos += buf.length; - } - return buffer; -}; - -// Inspect -Buffer.prototype.inspect = function inspect() { - var out = [], - len = this.length; - - for (var i = 0; i < len; i++) { - out[i] = toHex(this.parent[i + this.offset]); - if (i == exports.INSPECT_MAX_BYTES) { - out[i + 1] = '...'; - break; - } - } - - return ''; -}; - - -Buffer.prototype.get = function get(i) { - if (i < 0 || i >= this.length) throw new Error('oob'); - return this.parent[this.offset + i]; -}; - - -Buffer.prototype.set = function set(i, v) { - if (i < 0 || i >= this.length) throw new Error('oob'); - return this.parent[this.offset + i] = v; -}; - - -// write(string, offset = 0, length = buffer.length-offset, encoding = 'utf8') -Buffer.prototype.write = function(string, offset, length, encoding) { - // Support both (string, offset, length, encoding) - // and the legacy (string, encoding, offset, length) - if (isFinite(offset)) { - if (!isFinite(length)) { - encoding = length; - length = undefined; - } - } else { // legacy - var swap = encoding; - encoding = offset; - offset = length; - length = swap; - } - - offset = +offset || 0; - var remaining = this.length - offset; - if (!length) { - length = remaining; - } else { - length = +length; - if (length > remaining) { - length = remaining; - } - } - encoding = String(encoding || 'utf8').toLowerCase(); - - var ret; - switch (encoding) { - case 'hex': - ret = this.parent.hexWrite(string, this.offset + offset, length); - break; - - case 'utf8': - case 'utf-8': - ret = this.parent.utf8Write(string, this.offset + offset, length); - break; - - case 'ascii': - ret = this.parent.asciiWrite(string, this.offset + offset, length); - break; - - case 'binary': - ret = this.parent.binaryWrite(string, this.offset + offset, length); - break; - - case 'base64': - // Warning: maxLength not taken into account in base64Write - ret = this.parent.base64Write(string, this.offset + offset, length); - break; - - case 'ucs2': - case 'ucs-2': - ret = this.parent.ucs2Write(string, this.offset + offset, length); - break; - - default: - throw new Error('Unknown encoding'); - } - - Buffer._charsWritten = SlowBuffer._charsWritten; - - return ret; -}; - - -// toString(encoding, start=0, end=buffer.length) -Buffer.prototype.toString = function(encoding, start, end) { - encoding = String(encoding || 'utf8').toLowerCase(); - - if (typeof start == 'undefined' || start < 0) { - start = 0; - } else if (start > this.length) { - start = this.length; - } - - if (typeof end == 'undefined' || end > this.length) { - end = this.length; - } else if (end < 0) { - end = 0; - } - - start = start + this.offset; - end = end + this.offset; - - switch (encoding) { - case 'hex': - return this.parent.hexSlice(start, end); - - case 'utf8': - case 'utf-8': - return this.parent.utf8Slice(start, end); - - case 'ascii': - return this.parent.asciiSlice(start, end); - - case 'binary': - return this.parent.binarySlice(start, end); - - case 'base64': - return this.parent.base64Slice(start, end); - - case 'ucs2': - case 'ucs-2': - return this.parent.ucs2Slice(start, end); - - default: - throw new Error('Unknown encoding'); - } -}; - - -// byteLength -Buffer.byteLength = SlowBuffer.byteLength; - - -// fill(value, start=0, end=buffer.length) -Buffer.prototype.fill = function fill(value, start, end) { - value || (value = 0); - start || (start = 0); - end || (end = this.length); - - if (typeof value === 'string') { - value = value.charCodeAt(0); - } - if (!(typeof value === 'number') || isNaN(value)) { - throw new Error('value is not a number'); - } - - if (end < start) throw new Error('end < start'); - - // Fill 0 bytes; we're done - if (end === start) return 0; - if (this.length == 0) return 0; - - if (start < 0 || start >= this.length) { - throw new Error('start out of bounds'); - } - - if (end < 0 || end > this.length) { - throw new Error('end out of bounds'); - } - - return this.parent.fill(value, - start + this.offset, - end + this.offset); -}; - - -// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) -Buffer.prototype.copy = function(target, target_start, start, end) { - var source = this; - start || (start = 0); - end || (end = this.length); - target_start || (target_start = 0); - - if (end < start) throw new Error('sourceEnd < sourceStart'); - - // Copy 0 bytes; we're done - if (end === start) return 0; - if (target.length == 0 || source.length == 0) return 0; - - if (target_start < 0 || target_start >= target.length) { - throw new Error('targetStart out of bounds'); - } - - if (start < 0 || start >= source.length) { - throw new Error('sourceStart out of bounds'); - } - - if (end < 0 || end > source.length) { - throw new Error('sourceEnd out of bounds'); - } - - // Are we oob? - if (end > this.length) { - end = this.length; - } - - if (target.length - target_start < end - start) { - end = target.length - target_start + start; - } - - return this.parent.copy(target.parent, - target_start + target.offset, - start + this.offset, - end + this.offset); -}; - - -// slice(start, end) -Buffer.prototype.slice = function(start, end) { - if (end === undefined) end = this.length; - if (end > this.length) throw new Error('oob'); - if (start > end) throw new Error('oob'); - - return new Buffer(this.parent, end - start, +start + this.offset); -}; - - -// Legacy methods for backwards compatibility. - -Buffer.prototype.utf8Slice = function(start, end) { - return this.toString('utf8', start, end); -}; - -Buffer.prototype.binarySlice = function(start, end) { - return this.toString('binary', start, end); -}; - -Buffer.prototype.asciiSlice = function(start, end) { - return this.toString('ascii', start, end); -}; - -Buffer.prototype.utf8Write = function(string, offset) { - return this.write(string, offset, 'utf8'); -}; - -Buffer.prototype.binaryWrite = function(string, offset) { - return this.write(string, offset, 'binary'); -}; - -Buffer.prototype.asciiWrite = function(string, offset) { - return this.write(string, offset, 'ascii'); -}; - -Buffer.prototype.readUInt8 = function(offset, noAssert) { - var buffer = this; - - if (!noAssert) { - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return; - - return buffer.parent[buffer.offset + offset]; -}; - -function readUInt16(buffer, offset, isBigEndian, noAssert) { - var val = 0; - - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return 0; - - if (isBigEndian) { - val = buffer.parent[buffer.offset + offset] << 8; - if (offset + 1 < buffer.length) { - val |= buffer.parent[buffer.offset + offset + 1]; - } - } else { - val = buffer.parent[buffer.offset + offset]; - if (offset + 1 < buffer.length) { - val |= buffer.parent[buffer.offset + offset + 1] << 8; - } - } - - return val; -} - -Buffer.prototype.readUInt16LE = function(offset, noAssert) { - return readUInt16(this, offset, false, noAssert); -}; - -Buffer.prototype.readUInt16BE = function(offset, noAssert) { - return readUInt16(this, offset, true, noAssert); -}; - -function readUInt32(buffer, offset, isBigEndian, noAssert) { - var val = 0; - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return 0; - - if (isBigEndian) { - if (offset + 1 < buffer.length) - val = buffer.parent[buffer.offset + offset + 1] << 16; - if (offset + 2 < buffer.length) - val |= buffer.parent[buffer.offset + offset + 2] << 8; - if (offset + 3 < buffer.length) - val |= buffer.parent[buffer.offset + offset + 3]; - val = val + (buffer.parent[buffer.offset + offset] << 24 >>> 0); - } else { - if (offset + 2 < buffer.length) - val = buffer.parent[buffer.offset + offset + 2] << 16; - if (offset + 1 < buffer.length) - val |= buffer.parent[buffer.offset + offset + 1] << 8; - val |= buffer.parent[buffer.offset + offset]; - if (offset + 3 < buffer.length) - val = val + (buffer.parent[buffer.offset + offset + 3] << 24 >>> 0); - } - - return val; -} - -Buffer.prototype.readUInt32LE = function(offset, noAssert) { - return readUInt32(this, offset, false, noAssert); -}; - -Buffer.prototype.readUInt32BE = function(offset, noAssert) { - return readUInt32(this, offset, true, noAssert); -}; - - -/* - * Signed integer types, yay team! A reminder on how two's complement actually - * works. The first bit is the signed bit, i.e. tells us whether or not the - * number should be positive or negative. If the two's complement value is - * positive, then we're done, as it's equivalent to the unsigned representation. - * - * Now if the number is positive, you're pretty much done, you can just leverage - * the unsigned translations and return those. Unfortunately, negative numbers - * aren't quite that straightforward. - * - * At first glance, one might be inclined to use the traditional formula to - * translate binary numbers between the positive and negative values in two's - * complement. (Though it doesn't quite work for the most negative value) - * Mainly: - * - invert all the bits - * - add one to the result - * - * Of course, this doesn't quite work in Javascript. Take for example the value - * of -128. This could be represented in 16 bits (big-endian) as 0xff80. But of - * course, Javascript will do the following: - * - * > ~0xff80 - * -65409 - * - * Whoh there, Javascript, that's not quite right. But wait, according to - * Javascript that's perfectly correct. When Javascript ends up seeing the - * constant 0xff80, it has no notion that it is actually a signed number. It - * assumes that we've input the unsigned value 0xff80. Thus, when it does the - * binary negation, it casts it into a signed value, (positive 0xff80). Then - * when you perform binary negation on that, it turns it into a negative number. - * - * Instead, we're going to have to use the following general formula, that works - * in a rather Javascript friendly way. I'm glad we don't support this kind of - * weird numbering scheme in the kernel. - * - * (BIT-MAX - (unsigned)val + 1) * -1 - * - * The astute observer, may think that this doesn't make sense for 8-bit numbers - * (really it isn't necessary for them). However, when you get 16-bit numbers, - * you do. Let's go back to our prior example and see how this will look: - * - * (0xffff - 0xff80 + 1) * -1 - * (0x007f + 1) * -1 - * (0x0080) * -1 - */ -Buffer.prototype.readInt8 = function(offset, noAssert) { - var buffer = this; - var neg; - - if (!noAssert) { - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to read beyond buffer length'); - } - - if (offset >= buffer.length) return; - - neg = buffer.parent[buffer.offset + offset] & 0x80; - if (!neg) { - return (buffer.parent[buffer.offset + offset]); - } - - return ((0xff - buffer.parent[buffer.offset + offset] + 1) * -1); -}; - -function readInt16(buffer, offset, isBigEndian, noAssert) { - var neg, val; - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'Trying to read beyond buffer length'); - } - - val = readUInt16(buffer, offset, isBigEndian, noAssert); - neg = val & 0x8000; - if (!neg) { - return val; - } - - return (0xffff - val + 1) * -1; -} - -Buffer.prototype.readInt16LE = function(offset, noAssert) { - return readInt16(this, offset, false, noAssert); -}; - -Buffer.prototype.readInt16BE = function(offset, noAssert) { - return readInt16(this, offset, true, noAssert); -}; - -function readInt32(buffer, offset, isBigEndian, noAssert) { - var neg, val; - - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); - } - - val = readUInt32(buffer, offset, isBigEndian, noAssert); - neg = val & 0x80000000; - if (!neg) { - return (val); - } - - return (0xffffffff - val + 1) * -1; -} - -Buffer.prototype.readInt32LE = function(offset, noAssert) { - return readInt32(this, offset, false, noAssert); -}; - -Buffer.prototype.readInt32BE = function(offset, noAssert) { - return readInt32(this, offset, true, noAssert); -}; - -function readFloat(buffer, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to read beyond buffer length'); - } - - return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, - 23, 4); -} - -Buffer.prototype.readFloatLE = function(offset, noAssert) { - return readFloat(this, offset, false, noAssert); -}; - -Buffer.prototype.readFloatBE = function(offset, noAssert) { - return readFloat(this, offset, true, noAssert); -}; - -function readDouble(buffer, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset + 7 < buffer.length, - 'Trying to read beyond buffer length'); - } - - return require('./buffer_ieee754').readIEEE754(buffer, offset, isBigEndian, - 52, 8); -} - -Buffer.prototype.readDoubleLE = function(offset, noAssert) { - return readDouble(this, offset, false, noAssert); -}; - -Buffer.prototype.readDoubleBE = function(offset, noAssert) { - return readDouble(this, offset, true, noAssert); -}; - - -/* - * We have to make sure that the value is a valid integer. This means that it is - * non-negative. It has no fractional component and that it does not exceed the - * maximum allowed value. - * - * value The number to check for validity - * - * max The maximum value - */ -function verifuint(value, max) { - assert.ok(typeof (value) == 'number', - 'cannot write a non-number as a number'); - - assert.ok(value >= 0, - 'specified a negative value for writing an unsigned value'); - - assert.ok(value <= max, 'value is larger than maximum value for type'); - - assert.ok(Math.floor(value) === value, 'value has a fractional component'); -} - -Buffer.prototype.writeUInt8 = function(value, offset, noAssert) { - var buffer = this; - - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'trying to write beyond buffer length'); - - verifuint(value, 0xff); - } - - if (offset < buffer.length) { - buffer.parent[buffer.offset + offset] = value; - } -}; - -function writeUInt16(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'trying to write beyond buffer length'); - - verifuint(value, 0xffff); - } - - for (var i = 0; i < Math.min(buffer.length - offset, 2); i++) { - buffer.parent[buffer.offset + offset + i] = - (value & (0xff << (8 * (isBigEndian ? 1 - i : i)))) >>> - (isBigEndian ? 1 - i : i) * 8; - } - -} - -Buffer.prototype.writeUInt16LE = function(value, offset, noAssert) { - writeUInt16(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeUInt16BE = function(value, offset, noAssert) { - writeUInt16(this, value, offset, true, noAssert); -}; - -function writeUInt32(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'trying to write beyond buffer length'); - - verifuint(value, 0xffffffff); - } - - for (var i = 0; i < Math.min(buffer.length - offset, 4); i++) { - buffer.parent[buffer.offset + offset + i] = - (value >>> (isBigEndian ? 3 - i : i) * 8) & 0xff; - } -} - -Buffer.prototype.writeUInt32LE = function(value, offset, noAssert) { - writeUInt32(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeUInt32BE = function(value, offset, noAssert) { - writeUInt32(this, value, offset, true, noAssert); -}; - - -/* - * We now move onto our friends in the signed number category. Unlike unsigned - * numbers, we're going to have to worry a bit more about how we put values into - * arrays. Since we are only worrying about signed 32-bit values, we're in - * slightly better shape. Unfortunately, we really can't do our favorite binary - * & in this system. It really seems to do the wrong thing. For example: - * - * > -32 & 0xff - * 224 - * - * What's happening above is really: 0xe0 & 0xff = 0xe0. However, the results of - * this aren't treated as a signed number. Ultimately a bad thing. - * - * What we're going to want to do is basically create the unsigned equivalent of - * our representation and pass that off to the wuint* functions. To do that - * we're going to do the following: - * - * - if the value is positive - * we can pass it directly off to the equivalent wuint - * - if the value is negative - * we do the following computation: - * mb + val + 1, where - * mb is the maximum unsigned value in that byte size - * val is the Javascript negative integer - * - * - * As a concrete value, take -128. In signed 16 bits this would be 0xff80. If - * you do out the computations: - * - * 0xffff - 128 + 1 - * 0xffff - 127 - * 0xff80 - * - * You can then encode this value as the signed version. This is really rather - * hacky, but it should work and get the job done which is our goal here. - */ - -/* - * A series of checks to make sure we actually have a signed 32-bit number - */ -function verifsint(value, max, min) { - assert.ok(typeof (value) == 'number', - 'cannot write a non-number as a number'); - - assert.ok(value <= max, 'value larger than maximum allowed value'); - - assert.ok(value >= min, 'value smaller than minimum allowed value'); - - assert.ok(Math.floor(value) === value, 'value has a fractional component'); -} - -function verifIEEE754(value, max, min) { - assert.ok(typeof (value) == 'number', - 'cannot write a non-number as a number'); - - assert.ok(value <= max, 'value larger than maximum allowed value'); - - assert.ok(value >= min, 'value smaller than minimum allowed value'); -} - -Buffer.prototype.writeInt8 = function(value, offset, noAssert) { - var buffer = this; - - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset < buffer.length, - 'Trying to write beyond buffer length'); - - verifsint(value, 0x7f, -0x80); - } - - if (value >= 0) { - buffer.writeUInt8(value, offset, noAssert); - } else { - buffer.writeUInt8(0xff + value + 1, offset, noAssert); - } -}; - -function writeInt16(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 1 < buffer.length, - 'Trying to write beyond buffer length'); - - verifsint(value, 0x7fff, -0x8000); - } - - if (value >= 0) { - writeUInt16(buffer, value, offset, isBigEndian, noAssert); - } else { - writeUInt16(buffer, 0xffff + value + 1, offset, isBigEndian, noAssert); - } -} - -Buffer.prototype.writeInt16LE = function(value, offset, noAssert) { - writeInt16(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeInt16BE = function(value, offset, noAssert) { - writeInt16(this, value, offset, true, noAssert); -}; - -function writeInt32(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to write beyond buffer length'); - - verifsint(value, 0x7fffffff, -0x80000000); - } - - if (value >= 0) { - writeUInt32(buffer, value, offset, isBigEndian, noAssert); - } else { - writeUInt32(buffer, 0xffffffff + value + 1, offset, isBigEndian, noAssert); - } -} - -Buffer.prototype.writeInt32LE = function(value, offset, noAssert) { - writeInt32(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeInt32BE = function(value, offset, noAssert) { - writeInt32(this, value, offset, true, noAssert); -}; - -function writeFloat(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 3 < buffer.length, - 'Trying to write beyond buffer length'); - - verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38); - } - - require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, - 23, 4); -} - -Buffer.prototype.writeFloatLE = function(value, offset, noAssert) { - writeFloat(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeFloatBE = function(value, offset, noAssert) { - writeFloat(this, value, offset, true, noAssert); -}; - -function writeDouble(buffer, value, offset, isBigEndian, noAssert) { - if (!noAssert) { - assert.ok(value !== undefined && value !== null, - 'missing value'); - - assert.ok(typeof (isBigEndian) === 'boolean', - 'missing or invalid endian'); - - assert.ok(offset !== undefined && offset !== null, - 'missing offset'); - - assert.ok(offset + 7 < buffer.length, - 'Trying to write beyond buffer length'); - - verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308); - } - - require('./buffer_ieee754').writeIEEE754(buffer, value, offset, isBigEndian, - 52, 8); -} - -Buffer.prototype.writeDoubleLE = function(value, offset, noAssert) { - writeDouble(this, value, offset, false, noAssert); -}; - -Buffer.prototype.writeDoubleBE = function(value, offset, noAssert) { - writeDouble(this, value, offset, true, noAssert); -}; - -SlowBuffer.prototype.readUInt8 = Buffer.prototype.readUInt8; -SlowBuffer.prototype.readUInt16LE = Buffer.prototype.readUInt16LE; -SlowBuffer.prototype.readUInt16BE = Buffer.prototype.readUInt16BE; -SlowBuffer.prototype.readUInt32LE = Buffer.prototype.readUInt32LE; -SlowBuffer.prototype.readUInt32BE = Buffer.prototype.readUInt32BE; -SlowBuffer.prototype.readInt8 = Buffer.prototype.readInt8; -SlowBuffer.prototype.readInt16LE = Buffer.prototype.readInt16LE; -SlowBuffer.prototype.readInt16BE = Buffer.prototype.readInt16BE; -SlowBuffer.prototype.readInt32LE = Buffer.prototype.readInt32LE; -SlowBuffer.prototype.readInt32BE = Buffer.prototype.readInt32BE; -SlowBuffer.prototype.readFloatLE = Buffer.prototype.readFloatLE; -SlowBuffer.prototype.readFloatBE = Buffer.prototype.readFloatBE; -SlowBuffer.prototype.readDoubleLE = Buffer.prototype.readDoubleLE; -SlowBuffer.prototype.readDoubleBE = Buffer.prototype.readDoubleBE; -SlowBuffer.prototype.writeUInt8 = Buffer.prototype.writeUInt8; -SlowBuffer.prototype.writeUInt16LE = Buffer.prototype.writeUInt16LE; -SlowBuffer.prototype.writeUInt16BE = Buffer.prototype.writeUInt16BE; -SlowBuffer.prototype.writeUInt32LE = Buffer.prototype.writeUInt32LE; -SlowBuffer.prototype.writeUInt32BE = Buffer.prototype.writeUInt32BE; -SlowBuffer.prototype.writeInt8 = Buffer.prototype.writeInt8; -SlowBuffer.prototype.writeInt16LE = Buffer.prototype.writeInt16LE; -SlowBuffer.prototype.writeInt16BE = Buffer.prototype.writeInt16BE; -SlowBuffer.prototype.writeInt32LE = Buffer.prototype.writeInt32LE; -SlowBuffer.prototype.writeInt32BE = Buffer.prototype.writeInt32BE; -SlowBuffer.prototype.writeFloatLE = Buffer.prototype.writeFloatLE; -SlowBuffer.prototype.writeFloatBE = Buffer.prototype.writeFloatBE; -SlowBuffer.prototype.writeDoubleLE = Buffer.prototype.writeDoubleLE; -SlowBuffer.prototype.writeDoubleBE = Buffer.prototype.writeDoubleBE; - -})() -},{"assert":9,"./buffer_ieee754":14,"base64-js":15}],15:[function(require,module,exports){ -(function (exports) { - 'use strict'; - - var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - - function b64ToByteArray(b64) { - var i, j, l, tmp, placeHolders, arr; - - if (b64.length % 4 > 0) { - throw 'Invalid string. Length must be a multiple of 4'; - } - - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - placeHolders = b64.indexOf('='); - placeHolders = placeHolders > 0 ? b64.length - placeHolders : 0; - - // base64 is 4/3 + up to two characters of the original data - arr = [];//new Uint8Array(b64.length * 3 / 4 - placeHolders); - - // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? b64.length - 4 : b64.length; - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (lookup.indexOf(b64[i]) << 18) | (lookup.indexOf(b64[i + 1]) << 12) | (lookup.indexOf(b64[i + 2]) << 6) | lookup.indexOf(b64[i + 3]); - arr.push((tmp & 0xFF0000) >> 16); - arr.push((tmp & 0xFF00) >> 8); - arr.push(tmp & 0xFF); - } - - if (placeHolders === 2) { - tmp = (lookup.indexOf(b64[i]) << 2) | (lookup.indexOf(b64[i + 1]) >> 4); - arr.push(tmp & 0xFF); - } else if (placeHolders === 1) { - tmp = (lookup.indexOf(b64[i]) << 10) | (lookup.indexOf(b64[i + 1]) << 4) | (lookup.indexOf(b64[i + 2]) >> 2); - arr.push((tmp >> 8) & 0xFF); - arr.push(tmp & 0xFF); - } - - return arr; - } - - function uint8ToBase64(uint8) { - var i, - extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes - output = "", - temp, length; - - function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; - }; - - // go through the array every three bytes, we'll deal with trailing stuff later - for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { - temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); - output += tripletToBase64(temp); - } - - // pad the end with zeros, but make sure to not forget the extra bytes - switch (extraBytes) { - case 1: - temp = uint8[uint8.length - 1]; - output += lookup[temp >> 2]; - output += lookup[(temp << 4) & 0x3F]; - output += '=='; - break; - case 2: - temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]); - output += lookup[temp >> 10]; - output += lookup[(temp >> 4) & 0x3F]; - output += lookup[(temp << 2) & 0x3F]; - output += '='; - break; - } - - return output; - } - - module.exports.toByteArray = b64ToByteArray; - module.exports.fromByteArray = uint8ToBase64; -}()); - -},{}]},{},["E/GbHF"]) -; -JSHINT = require('jshint').JSHINT; -}()); diff --git a/dom/system/gonk/tests/marionette/ril_jshint/jshintrc b/dom/system/gonk/tests/marionette/ril_jshint/jshintrc deleted file mode 100644 index 437fe1a6f..000000000 --- a/dom/system/gonk/tests/marionette/ril_jshint/jshintrc +++ /dev/null @@ -1,118 +0,0 @@ -{ - // JSHint Default Configuration File (as on JSHint website) - // See http://jshint.com/docs/ for more details - - // Modify for RIL usage. - - "maxerr" : 10000, // {int} Maximum error before stopping - - // Enforcing - "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.) - "camelcase" : false, // true: Identifiers must be in camelCase - "curly" : false, // true: Require {} for every new block or scope - "eqeqeq" : false, // true: Require triple equals (===) for comparison - "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty() - "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());` - //"indent" : 2, // {int} Number of spaces to use for indentation - "latedef" : false, // true: Require variables/functions to be defined before being used - "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()` - "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee` - "noempty" : false, // true: Prohibit use of empty blocks - "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment) - "plusplus" : false, // true: Prohibit use of `++` & `--` - "quotmark" : false, // Quotation mark consistency: - // false : do nothing (default) - // true : ensure whatever is used is consistent - // "single" : require single quotes - // "double" : require double quotes - "undef" : false, // true: Require all non-global variables to be declared (prevents global leaks) - "unused" : false, // true: Require all defined variables be used - "strict" : false, // true: Requires all functions run in ES5 Strict Mode - "trailing" : false, // true: Prohibit trailing whitespaces - "maxparams" : false, // {int} Max number of formal params allowed per function - "maxdepth" : false, // {int} Max depth of nested blocks (within functions) - "maxstatements" : false, // {int} Max number statements per function - "maxcomplexity" : false, // {int} Max cyclomatic complexity per function - "maxlen" : false, // {int} Max number of characters per line - - // Relaxing - "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons) - "boss" : false, // true: Tolerate assignments where comparisons would be expected - "debug" : false, // true: Allow debugger statements e.g. browser breakpoints. - "eqnull" : true, // true: Tolerate use of `== null` - "es5" : false, // true: Allow ES5 syntax (ex: getters and setters) - "esnext" : false, // true: Allow ES.next (ES6) syntax (ex: `const`) - "moz" : true, // true: Allow Mozilla specific syntax (extends and overrides esnext features) - // (ex: `for each`, multiple try/catch, function expression…) - "evil" : false, // true: Tolerate use of `eval` and `new Function()` - "expr" : false, // true: Tolerate `ExpressionStatement` as Programs - "funcscope" : false, // true: Tolerate defining variables inside control statements" - "globalstrict" : true, // true: Allow global "use strict" (also enables 'strict') - "iterator" : false, // true: Tolerate using the `__iterator__` property - "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block - "laxbreak" : true, // true: Tolerate possibly unsafe line breakings - "laxcomma" : false, // true: Tolerate comma-first style coding - "loopfunc" : false, // true: Tolerate functions being defined in loops - "multistr" : false, // true: Tolerate multi-line strings - "proto" : true, // true: Tolerate using the `__proto__` property - "scripturl" : false, // true: Tolerate script-targeted URLs - "smarttabs" : false, // true: Tolerate mixed tabs/spaces when used for alignment - "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;` - "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation - "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;` - "validthis" : true, // true: Tolerate using this in a non-constructor function - - // Environments - "browser" : false, // Web Browser (window, document, etc) - "couch" : false, // CouchDB - "devel" : true, // Development/debugging (alert, confirm, etc) - "dojo" : false, // Dojo Toolkit - "jquery" : false, // jQuery - "mootools" : false, // MooTools - "node" : false, // Node.js - "nonstandard" : false, // Widely adopted globals (escape, unescape, etc) - "prototypejs" : false, // Prototype and Scriptaculous - "rhino" : false, // Rhino - "worker" : true, // Web Workers - "wsh" : false, // Windows Scripting Host - "yui" : false, // Yahoo User Interface - - // Legacy - "nomen" : false, // true: Prohibit dangling `_` in variables - "onevar" : false, // true: Allow only one `var` statement per function - "passfail" : false, // true: Stop on first error - "white" : false, // true: Check against strict whitespace and indentation rules - - // Custom Globals - "predef" : [ ], // additional predefined global variables - - "globals": { - "ChromeWorker": false, - "Components": false, - "DOMRequestIpcHelper": false, - "ObjectWrapper": false, - "PhoneNumberUtils": false, - "RILNetworkInterface": false, - "Services": false, - "Uint8Array": false, - "WAP": false, - "XPCOMUtils": false, - "cpmm": false, - "dump": false, - "gAudioManager": false, - "gMessageManager": false, - "gMobileMessageDatabaseService": false, - "gMobileMessageService": false, - "gNetworkManager": false, - "gPowerManagerService": false, - "gSettingsService": false, - "gSmsService": false, - "gSystemMessenger": false, - "gSystemWorkerManager": false, - "gTimeService": false, - "gUUIDGenerator": false, - "ppmm": true, - - "__end_guardian_for_easy_sorting__": false - } -} diff --git a/dom/system/gonk/tests/marionette/test_all_network_info.js b/dom/system/gonk/tests/marionette/test_all_network_info.js deleted file mode 100644 index 5225ab6d6..000000000 --- a/dom/system/gonk/tests/marionette/test_all_network_info.js +++ /dev/null @@ -1,106 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -var networkManager = - Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager); -ok(networkManager, - "networkManager.constructor is " + networkManager.constructor); - -var wifiManager = window.navigator.mozWifiManager; -ok(wifiManager, "wifiManager.constructor is " + wifiManager.constructor); - -function setEmulatorAPN() { - let apn = [ - [{"carrier":"T-Mobile US", - "apn":"epc.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["default","supl","mms","ims","dun", "fota"]}] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -function ensureWifiEnabled(aEnabled) { - if (wifiManager.enabled === aEnabled) { - log('Already ' + (aEnabled ? 'enabled' : 'disabled')); - return Promise.resolve(); - } - return requestWifiEnabled(aEnabled); -} - -function requestWifiEnabled(aEnabled) { - let promises = []; - - promises.push(waitForTargetEvent(wifiManager, aEnabled ? 'enabled' : 'disabled', - function() { - return wifiManager.enabled === aEnabled ? true : false; - })); - promises.push(setSettings(SETTINGS_KEY_WIFI_ENABLED, aEnabled)); - - return Promise.all(promises); -} - -// Test initial State -function verifyInitialState() { - log("= verifyInitialState ="); - - // Data and wifi should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }) - .then(() => ensureWifiEnabled(false)); -} - -function testAllNetworkInfo(aAnyConnected) { - log("= testAllNetworkInfo = " + aAnyConnected); - - let allNetworkInfo = networkManager.allNetworkInfo; - ok(allNetworkInfo, "NetworkManager.allNetworkInfo"); - - let count = Object.keys(allNetworkInfo).length; - ok(count > 0, "NetworkManager.allNetworkInfo count"); - - let connected = false; - for (let networkId in allNetworkInfo) { - if (allNetworkInfo.hasOwnProperty(networkId)) { - let networkInfo = allNetworkInfo[networkId]; - if (networkInfo.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED) { - connected = true; - break; - } - } - } - - is(aAnyConnected, connected, "NetworkManager.allNetworkInfo any connected"); -} - -// Start test -startTestBase(function() { - - let origApnSettings, origWifiEnabled; - return Promise.resolve() - .then(() => { - origWifiEnabled = wifiManager.enabled; - }) - .then(() => verifyInitialState()) - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setEmulatorAPN()) - .then(() => setDataEnabledAndWait(true)) - .then(() => testAllNetworkInfo(true)) - .then(() => setDataEnabledAndWait(false)) - .then(() => testAllNetworkInfo(false)) - // Restore original apn settings and wifi state. - .then(() => { - if (origApnSettings) { - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings); - } - }) - .then(() => ensureWifiEnabled(origWifiEnabled)); -}); diff --git a/dom/system/gonk/tests/marionette/test_data_connection.js b/dom/system/gonk/tests/marionette/test_data_connection.js deleted file mode 100644 index 5a53b1e5f..000000000 --- a/dom/system/gonk/tests/marionette/test_data_connection.js +++ /dev/null @@ -1,70 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -function setEmulatorAPN() { - let apn = [ - [{"carrier":"T-Mobile US", - "apn":"epc.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["default","supl","mms","ims","dun", "fota"]}] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -// Test initial State -function testInitialState() { - log("= testInitialState ="); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -// Test default data Connection -function testDefaultDataConnection() { - log("= testDefaultDataConnection ="); - - // Enable default data - return setDataEnabledAndWait(true) - // Disable default data - .then(() => setDataEnabledAndWait(false)); -} - -// Test non default data connection -function testNonDefaultDataConnection() { - log("= testNonDefaultDataConnection ="); - - function doTestNonDefaultDataConnection(type) { - log("doTestNonDefaultDataConnection: " + type); - - return setupDataCallAndWait(type) - .then(() => deactivateDataCallAndWait(type)); - } - - let currentApn; - return getSettings(SETTINGS_KEY_DATA_APN_SETTINGS) - .then(value => { - currentApn = value; - }) - .then(setEmulatorAPN) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_MMS)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_SUPL)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_IMS)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_DUN)) - .then(() => doTestNonDefaultDataConnection(NETWORK_TYPE_MOBILE_FOTA)) - // Restore APN settings - .then(() => setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, currentApn)); -} - -// Start test -startTestBase(function() { - return testInitialState() - .then(() => testDefaultDataConnection()) - .then(() => testNonDefaultDataConnection()); -}); diff --git a/dom/system/gonk/tests/marionette/test_data_connection_proxy.js b/dom/system/gonk/tests/marionette/test_data_connection_proxy.js deleted file mode 100644 index a99187538..000000000 --- a/dom/system/gonk/tests/marionette/test_data_connection_proxy.js +++ /dev/null @@ -1,99 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -const HTTP_PROXY = "10.0.2.200"; -const HTTP_PROXY_PORT = "8080"; -const MANUAL_PROXY_CONFIGURATION = 1; - -// Test initial State -function verifyInitialState() { - log("= verifyInitialState ="); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -function setTestApn() { - let apn = [ - [ {"carrier": "T-Mobile US", - "apn": "epc.tmobile.com", - "proxy": HTTP_PROXY, - "port": HTTP_PROXY_PORT, - "mmsc": "http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types": ["default","supl","mms"]} ] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -function waitForHttpProxyVerified(aShouldBeSet) { - let TIME_OUT_VALUE = 20000; - - return new Promise(function(aResolve, aReject) { - try { - waitFor(aResolve, () => { - let proxyType = SpecialPowers.getIntPref("network.proxy.type"); - let httpProxy = SpecialPowers.getCharPref("network.proxy.http"); - let sslProxy = SpecialPowers.getCharPref("network.proxy.ssl"); - let httpProxyPort = SpecialPowers.getIntPref("network.proxy.http_port"); - let sslProxyPort = SpecialPowers.getIntPref("network.proxy.ssl_port"); - - if ((aShouldBeSet && - proxyType == MANUAL_PROXY_CONFIGURATION && - httpProxy == HTTP_PROXY && - sslProxy == HTTP_PROXY && - httpProxyPort == HTTP_PROXY_PORT && - sslProxyPort == HTTP_PROXY_PORT) || - (!aShouldBeSet && proxyType != MANUAL_PROXY_CONFIGURATION && - !httpProxy && !sslProxy && !httpProxyPort && !sslProxyPort)) { - return true; - } - - return false; - }, TIME_OUT_VALUE); - } catch(aError) { - // Timed out. - aReject(aError); - } - }); -} - -function testDefaultDataHttpProxy() { - log("= testDefaultDataHttpProxy ="); - - return setDataEnabledAndWait(true) - .then(() => waitForHttpProxyVerified(true)) - .then(() => setDataEnabledAndWait(false)) - .then(() => waitForHttpProxyVerified(false)); -} - -function testNonDefaultDataHttpProxy(aType) { - log("= testNonDefaultDataHttpProxy - " + aType + " ="); - - return setupDataCallAndWait(aType) - // Http proxy should not be set for non-default data connections. - .then(() => waitForHttpProxyVerified(false)) - .then(() => deactivateDataCallAndWait(aType)); -} - -// Start test -startTestBase(function() { - let origApnSettings; - return verifyInitialState() - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setTestApn()) - .then(() => testDefaultDataHttpProxy()) - .then(() => testNonDefaultDataHttpProxy(NETWORK_TYPE_MOBILE_MMS)) - .then(() => testNonDefaultDataHttpProxy(NETWORK_TYPE_MOBILE_SUPL)) - // Restore APN settings - .then(() => setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings)); -}); diff --git a/dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js b/dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js deleted file mode 100644 index e178b8b65..000000000 --- a/dom/system/gonk/tests/marionette/test_dsds_numRadioInterfaces.js +++ /dev/null @@ -1,43 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_CONTEXT = "chrome"; - -Cu.import("resource://gre/modules/Promise.jsm"); -Cu.import("resource://gre/modules/systemlibs.js"); - -const NS_RIL_CONTRACTID = "@mozilla.org/ril;1"; - -const PROP_RO_MOZ_RIL_NUMCLIENTS = "ro.moz.ril.numclients"; - -const PREF_RIL_NUM_RADIO_INTERFACES = "ril.numRadioInterfaces"; - -ok(libcutils, "libcutils is available"); - -var propNum = (function() { - try { - let numString = libcutils.property_get(PROP_RO_MOZ_RIL_NUMCLIENTS, "1"); - let num = parseInt(numString, 10); - if (num >= 0) { - return num; - } - } catch (e) {} -})(); - -log("Retrieved '" + PROP_RO_MOZ_RIL_NUMCLIENTS + "' = " + propNum); -ok(propNum, PROP_RO_MOZ_RIL_NUMCLIENTS); - -var prefNum = Services.prefs.getIntPref(PREF_RIL_NUM_RADIO_INTERFACES); -log("Retrieved '" + PREF_RIL_NUM_RADIO_INTERFACES + "' = " + prefNum); - -var ril = Cc[NS_RIL_CONTRACTID].getService(Ci.nsIRadioInterfaceLayer); -ok(ril, "ril.constructor is " + ril.constructor); - -var ifaceNum = ril.numRadioInterfaces; -log("Retrieved 'nsIRadioInterfaceLayer.numRadioInterfaces' = " + ifaceNum); - -is(propNum, prefNum); -is(propNum, ifaceNum); - -finish(); diff --git a/dom/system/gonk/tests/marionette/test_fakevolume.js b/dom/system/gonk/tests/marionette/test_fakevolume.js deleted file mode 100644 index 173f9ac11..000000000 --- a/dom/system/gonk/tests/marionette/test_fakevolume.js +++ /dev/null @@ -1,25 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -var Cc = SpecialPowers.Cc; -var Ci = SpecialPowers.Ci; - -var volumeService = Cc["@mozilla.org/telephony/volume-service;1"].getService(Ci.nsIVolumeService); -ok(volumeService, "Should have volume service"); - -var volName = "fake"; -var mountPoint = "/data/fake/storage"; -volumeService.createFakeVolume(volName, mountPoint); - -var vol = volumeService.getVolumeByName(volName); -ok(vol, "volume shouldn't be null"); - -is(volName, vol.name, "name"); -is(mountPoint, vol.mountPoint, "moutnPoint"); -is(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state"); - -ok(vol.mountGeneration > 0, "mount generation should not be zero"); - -finish(); diff --git a/dom/system/gonk/tests/marionette/test_geolocation.js b/dom/system/gonk/tests/marionette/test_geolocation.js deleted file mode 100644 index 201c8b3e3..000000000 --- a/dom/system/gonk/tests/marionette/test_geolocation.js +++ /dev/null @@ -1,117 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -var geolocation = window.navigator.geolocation; -ok(geolocation); - -var sample = []; -var result = []; -var wpid; - -/** - * Grant special power to get the geolocation - */ -SpecialPowers.addPermission("geolocation", true, document); - -/** - * Disable wifi geolocation provider - */ -wifiUri = SpecialPowers.getCharPref("geo.wifi.uri"); -SpecialPowers.setCharPref("geo.wifi.uri", "http://mochi.test:8888/tests/dom/tests/mochitest/geolocation/network_geolocation.sjs?action=stop-responding"); - -/** - * Helper that compares the geolocation against the web API. - */ -function verifyLocation() { - - log("Sample:" + sample.join(',')); - log("Result:" + result.join(',')); - - for (i in sample) { - is(sample.pop(), result.pop()); - } - - window.setTimeout(cleanup, 0); -} - -/** - * Test story begins here. - */ -function setup() { - log("Providing initial setup: set geographic position watcher."); - - - wpid = geolocation.watchPosition(function(position) { - log("Position changes: (" + position.coords.latitude + "/" + position.coords.longitude + ")"); - result.push(""+position.coords.latitude + "/" + position.coords.longitude); - }); - - lat = 0; - lon = 0; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(movePosition_1, 0); - }); -} - -function movePosition_1() { - log("Geolocation changes. Move to Position 1."); - - lat = 25; - lon = 121.56499833333334; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(movePosition_2, 0); - }); -} - -function movePosition_2() { - log("Geolocation changes to a negative longitude. Move to Position 2."); - - lat = 37.393; - lon = -122.08199833333335; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(movePosition_3, 0); - }); -} - -function movePosition_3() { - log("Geolocation changes with WatchPosition. Move to Position 3."); - - lat = -22; - lon = -43; - - cmd = "geo fix " + lon + " " + lat; - sample.push(lat+"/"+lon); - - geolocation.getCurrentPosition(function(position) { - log("getCurrentPosition: Expected location: ("+lat+"/"+lon+"); Current location: (" + position.coords.latitude + "/" + position.coords.longitude + ")"); - is(lat, position.coords.latitude); - is(lon, position.coords.longitude); - }); - - runEmulatorCmd(cmd, function(result) { - window.setTimeout(verifyLocation, 0); - }); -} - -function cleanup() { - geolocation.clearWatch(wpid); - SpecialPowers.removePermission("geolocation", document); - SpecialPowers.setCharPref("geo.wifi.uri", wifiUri); - finish(); -} - -setup(); diff --git a/dom/system/gonk/tests/marionette/test_multiple_data_connection.js b/dom/system/gonk/tests/marionette/test_multiple_data_connection.js deleted file mode 100644 index 24abd4451..000000000 --- a/dom/system/gonk/tests/marionette/test_multiple_data_connection.js +++ /dev/null @@ -1,89 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -// Must sync with hardware/ril/reference-ril/reference-ril.c -const MAX_DATA_CONTEXTS = 4; - -function setEmulatorAPN() { - // Use different apn for each network type. - let apn = [[ { "carrier":"T-Mobile US", - "apn":"epc1.tmobile.com", - "types":["default"] }, - { "carrier":"T-Mobile US", - "apn":"epc2.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["mms"] }, - { "carrier":"T-Mobile US", - "apn":"epc3.tmobile.com", - "types":["supl"] }, - { "carrier":"T-Mobile US", - "apn":"epc4.tmobile.com", - "types":["ims"] }, - { "carrier":"T-Mobile US", - "apn":"epc5.tmobile.com", - "types":["dun"] }, - { "carrier":"T-Mobile US", - "apn":"epc6.tmobile.com", - "types":["fota"] }]]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -// Test initial State -function testInitialState() { - log("= testInitialState ="); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -function testSetupConcurrentDataCalls() { - log("= testSetupConcurrentDataCalls ="); - - let promise = Promise.resolve(); - // Skip default mobile type. - for (let i = 1; i < MAX_DATA_CONTEXTS; i++) { - let type = networkTypes[i]; - promise = promise.then(() => setupDataCallAndWait(type)); - } - return promise; -} - -function testDeactivateConcurrentDataCalls() { - log("= testDeactivateConcurrentDataCalls ="); - - let promise = Promise.resolve(); - // Skip default mobile type. - for (let i = 1; i < MAX_DATA_CONTEXTS; i++) { - let type = networkTypes[i]; - promise = promise.then(() => deactivateDataCallAndWait(type)); - } - return promise; -} - -// Start test -startTestBase(function() { - - let origApnSettings; - return testInitialState() - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setEmulatorAPN()) - .then(() => setDataEnabledAndWait(true)) - .then(() => testSetupConcurrentDataCalls()) - .then(() => testDeactivateConcurrentDataCalls()) - .then(() => setDataEnabledAndWait(false)) - .then(() => { - if (origApnSettings) { - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings); - } - }); -}); diff --git a/dom/system/gonk/tests/marionette/test_network_active_changed.js b/dom/system/gonk/tests/marionette/test_network_active_changed.js deleted file mode 100644 index 5886f37ed..000000000 --- a/dom/system/gonk/tests/marionette/test_network_active_changed.js +++ /dev/null @@ -1,52 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -var networkManager = - Cc["@mozilla.org/network/manager;1"].getService(Ci.nsINetworkManager); -ok(networkManager, - "networkManager.constructor is " + networkManager.constructor); - -function testInitialState() { - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then((enabled) => { - is(enabled, false, "data should be off by default"); - is(networkManager.activeNetworkInfo, null, - "networkManager.activeNetworkInfo should be null by default"); - }); -} - -function testActiveNetworkChangedBySwitchingDataCall(aDataCallEnabled) { - log("Test active network by switching dataCallEnabled to " + aDataCallEnabled); - - let promises = []; - promises.push(waitForObserverEvent(TOPIC_NETWORK_ACTIVE_CHANGED)); - promises.push(setSettings(SETTINGS_KEY_DATA_ENABLED, aDataCallEnabled)); - - return Promise.all(promises).then(function(results) { - let subject = results[0]; - - if (aDataCallEnabled) { - ok(subject instanceof Ci.nsINetworkInfo, - "subject should be an instance of nsINetworkInfo"); - ok(subject instanceof Ci.nsIRilNetworkInfo, - "subject should be an instance of nsIRilNetworkInfo"); - is(subject.type, NETWORK_TYPE_MOBILE, - "subject.type should be NETWORK_TYPE_MOBILE"); - } - - is(subject, networkManager.activeNetworkInfo, - "subject should be equal with networkManager.activeNetworkInfo"); - }); -} - -// Start test -startTestBase(function() { - return testInitialState() - // Test active network changed by enabling data call. - .then(() => testActiveNetworkChangedBySwitchingDataCall(true)) - // Test active network changed by disabling data call. - .then(() => testActiveNetworkChangedBySwitchingDataCall(false)); -}); diff --git a/dom/system/gonk/tests/marionette/test_network_interface_list_service.js b/dom/system/gonk/tests/marionette/test_network_interface_list_service.js deleted file mode 100644 index 549940fa5..000000000 --- a/dom/system/gonk/tests/marionette/test_network_interface_list_service.js +++ /dev/null @@ -1,95 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -function getNetworkInfo(aType) { - let networkListService = - Cc["@mozilla.org/network/interface-list-service;1"]. - getService(Ci.nsINetworkInterfaceListService); - // Get all available interfaces - let networkList = networkListService.getDataInterfaceList(0); - - // Try to get nsINetworkInterface for aType. - let numberOfInterface = networkList.getNumberOfInterface(); - for (let i = 0; i < numberOfInterface; i++) { - let info = networkList.getInterfaceInfo(i); - if (info.type === aType) { - return info; - } - } - - return null; -} - -// Test getDataInterfaceList by enabling/disabling mobile data. -function testGetDataInterfaceList(aMobileDataEnabled) { - log("Test getDataInterfaceList with mobile data " + - aMobileDataEnabled ? "enabled" : "disabled"); - - return setDataEnabledAndWait(aMobileDataEnabled) - .then(() => getNetworkInfo(NETWORK_TYPE_MOBILE)) - .then((networkInfo) => { - if (!networkInfo) { - ok(false, "Should get an valid nsINetworkInfo for mobile"); - return; - } - - ok(networkInfo instanceof Ci.nsINetworkInfo, - "networkInfo should be an instance of nsINetworkInfo"); - - let ipAddresses = {}; - let prefixs = {}; - let numOfGateways = {}; - let numOfDnses = {}; - let numOfIpAddresses = networkInfo.getAddresses(ipAddresses, prefixs); - let gateways = networkInfo.getGateways(numOfGateways); - let dnses = networkInfo.getDnses(numOfDnses); - - if (aMobileDataEnabled) { - // Mobile data is enabled. - is(networkInfo.state, NETWORK_STATE_CONNECTED, "check state"); - ok(numOfIpAddresses > 0, "check number of ipAddresses"); - ok(ipAddresses.value.length > 0, "check ipAddresses.length"); - ok(prefixs.value.length > 0, "check prefixs.length"); - ok(numOfGateways.value > 0, "check number of gateways"); - ok(prefixs.value.length > 0, "check prefixs.length"); - ok(gateways.length > 0, "check gateways.length"); - ok(numOfDnses.value > 0, "check number of dnses"); - ok(dnses.length > 0, "check dnses.length"); - } else { - // Mobile data is disabled. - is(networkInfo.state, NETWORK_STATE_DISCONNECTED, "check state"); - is(numOfIpAddresses, 0, "check number of ipAddresses"); - is(ipAddresses.value.length, 0, "check ipAddresses.length"); - is(prefixs.value.length, 0, "check prefixs.length"); - is(numOfGateways.value, 0, "check number of gateways"); - is(prefixs.value.length, 0, "check prefixs.length"); - is(gateways.length, 0, "check gateways.length"); - is(numOfDnses.value, 0, "check number of dnses"); - is(dnses.length, 0, "check dnses.length"); - } - }); -} - -// Start test -startTestBase(function() { - return Promise.resolve() - // Test initial State - .then(() => { - log("Test initial state"); - - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Mobile data must be off"); - }); - }) - - // Test getDataInterfaceList with mobile data enabled. - .then(() => testGetDataInterfaceList(true)) - - // Test getDataInterfaceList with mobile data disabled. - .then(() => testGetDataInterfaceList(false)); -}); diff --git a/dom/system/gonk/tests/marionette/test_network_interface_mtu.js b/dom/system/gonk/tests/marionette/test_network_interface_mtu.js deleted file mode 100644 index 679efe2ed..000000000 --- a/dom/system/gonk/tests/marionette/test_network_interface_mtu.js +++ /dev/null @@ -1,100 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = "head.js"; - -const TEST_MTU1 = "1410"; -const TEST_MTU2 = "1440"; - -function setEmulatorAPN() { - let apn = [ - [ { "carrier":"T-Mobile US", - "apn":"epc1.tmobile.com", - "types":["default"], - "mtu": TEST_MTU1 }, - { "carrier":"T-Mobile US", - "apn":"epc2.tmobile.com", - "mmsc":"http://mms.msg.eng.t-mobile.com/mms/wapenc", - "types":["supl","mms","ims","dun", "fota"], - "mtu": TEST_MTU2 } ] - ]; - - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, apn); -} - -function verifyInitialState() { - // Data should be off before starting any test. - return getSettings(SETTINGS_KEY_DATA_ENABLED) - .then(value => { - is(value, false, "Data must be off"); - }); -} - -function verifyMtu(aInterfaceName, aMtu) { - return runEmulatorShellCmdSafe(['ip', 'link', 'show', 'dev', aInterfaceName]) - .then(aLines => { - // Sample output: - // - // 4: rmnet0: mtu 1410 qdisc pfifo_fast state DOWN mode DEFAULT qlen 1000 - // link/ether 52:54:00:12:34:58 brd ff:ff:ff:ff:ff:ff - // - let mtu; - aLines.some(function (aLine) { - let tokens = aLine.trim().split(/\s+/); - let mtuIndex = tokens.indexOf('mtu'); - if (mtuIndex < 0 || mtuIndex + 1 >= tokens.length) { - return false; - } - - mtu = tokens[mtuIndex + 1]; - return true; - }); - - is(mtu, aMtu, aInterfaceName + "'s mtu."); - }); -} - -function testDefaultDataCallMtu() { - log("= testDefaultDataCallMtu ="); - - return setDataEnabledAndWait(true) - .then(aNetworkInfo => verifyMtu(aNetworkInfo.name, TEST_MTU1)) - .then(() => setDataEnabledAndWait(false)); -} - -function testNonDefaultDataCallMtu() { - log("= testNonDefaultDataCallMtu ="); - - function doTestNonDefaultDataCallMtu(aType) { - log("doTestNonDefaultDataCallMtu: " + aType); - - return setupDataCallAndWait(aType) - .then(aNetworkInfo => verifyMtu(aNetworkInfo.name, TEST_MTU2)) - .then(() => deactivateDataCallAndWait(aType)); - } - - return doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_MMS) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_SUPL)) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_IMS)) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_DUN)) - .then(() => doTestNonDefaultDataCallMtu(NETWORK_TYPE_MOBILE_FOTA)); -} - -// Start test -startTestBase(function() { - let origApnSettings; - return verifyInitialState() - .then(() => getSettings(SETTINGS_KEY_DATA_APN_SETTINGS)) - .then(value => { - origApnSettings = value; - }) - .then(() => setEmulatorAPN()) - .then(() => testDefaultDataCallMtu()) - .then(() => testNonDefaultDataCallMtu()) - .then(() => { - if (origApnSettings) { - return setSettings(SETTINGS_KEY_DATA_APN_SETTINGS, origApnSettings); - } - }); -}); diff --git a/dom/system/gonk/tests/marionette/test_ril_code_quality.py b/dom/system/gonk/tests/marionette/test_ril_code_quality.py deleted file mode 100644 index d741d8a2e..000000000 --- a/dom/system/gonk/tests/marionette/test_ril_code_quality.py +++ /dev/null @@ -1,371 +0,0 @@ -""" -The test performs the static code analysis check by JSHint. - -Target js files: -- RadioInterfaceLayer.js -- ril_worker.js -- ril_consts.js - -If the js file contains the line of 'importScript()' (Ex: ril_worker.js), the -test will perform a special merge step before excuting JSHint. - -Ex: Script A --------------------------------- -importScripts('Script B') -... --------------------------------- - -We merge these two scripts into one by the following way. - --------------------------------- -[Script B (ex: ril_consts.js)] -(function(){ [Script A (ex: ril_worker.js)] -})(); --------------------------------- - -Script A (ril_worker.js) runs global strict mode. -Script B (ril_consts.js) not. - -The above merge way ensures the correct scope of 'strict mode.' -""" - -import bisect -import inspect -import os -import os.path -import re -import unicodedata - -from marionette_harness import MarionetteTestCase - - -class StringUtility: - - """A collection of some string utilities.""" - - @staticmethod - def find_match_lines(lines, pattern): - """Return a list of lines that contains given pattern.""" - return [line for line in lines if pattern in line] - - @staticmethod - def remove_non_ascii(data): - """Remove non ascii characters in data and return it as new string.""" - if type(data).__name__ == 'unicode': - data = unicodedata.normalize( - 'NFKD', data).encode('ascii', 'ignore') - return data - - @staticmethod - def auto_close(lines): - """Ensure every line ends with '\n'.""" - if lines and not lines[-1].endswith('\n'): - lines[-1] += '\n' - return lines - - @staticmethod - def auto_wrap_strict_mode(lines): - """Wrap by function scope if lines contain 'use strict'.""" - if StringUtility.find_match_lines(lines, 'use strict'): - lines[0] = '(function(){' + lines[0] - lines.append('})();\n') - return lines - - @staticmethod - def get_imported_list(lines): - """Get a list of imported items.""" - return [item - for line in StringUtility.find_match_lines(lines, 'importScripts') - for item in StringUtility._get_imported_list_from_line(line)] - - @staticmethod - def _get_imported_list_from_line(line): - """Extract all items from 'importScripts(...)'. - - importScripts("ril_consts.js", "systemlibs.js") - => ['ril_consts', 'systemlibs.js'] - - """ - pattern = re.compile(r'\s*importScripts\((.*)\)') - m = pattern.match(line) - if not m: - raise Exception('Parse importScripts error.') - return [name.translate(None, '\' "') for name in m.group(1).split(',')] - - -class ResourceUriFileReader: - - """Handle the process of reading the source code from system.""" - - URI_PREFIX = 'resource://gre/' - URI_PATH = { - 'RadioInterfaceLayer.js': 'components/RadioInterfaceLayer.js', - 'ril_worker.js': 'modules/ril_worker.js', - 'ril_consts.js': 'modules/ril_consts.js', - 'systemlibs.js': 'modules/systemlibs.js', - 'worker_buf.js': 'modules/workers/worker_buf.js', - } - - CODE_OPEN_CHANNEL_BY_URI = ''' - var Cc = Components.classes; - var Ci = Components.interfaces; - var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService); - var secMan = Cc["@mozilla.org/scriptsecuritymanager;1"].getService(Ci.nsIScriptSecurityManager); - global.uri = '%(uri)s'; - global.channel = ios.newChannel2(global.uri, - null, - null, - null, // aLoadingNode - secMan.getSystemPrincipal(), - null, // aTriggeringPrincipal - Ci.nsILoadInfo.SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, - Ci.nsIContentPolicy.TYPE_OTHER); - ''' - - CODE_GET_SPEC = ''' - return global.channel.URI.spec; - ''' - - CODE_READ_CONTENT = ''' - var Cc = Components.classes; - var Ci = Components.interfaces; - - var zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(Ci.nsIZipReader); - var inputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream); - - var jaruri = global.channel.URI.QueryInterface(Ci.nsIJARURI); - var file = jaruri.JARFile.QueryInterface(Ci.nsIFileURL).file; - var entry = jaruri.JAREntry; - zipReader.open(file); - inputStream.init(zipReader.getInputStream(entry)); - var content = inputStream.read(inputStream.available()); - inputStream.close(); - zipReader.close(); - return content; - ''' - - @classmethod - def get_uri(cls, filename): - """Convert filename to URI in system.""" - if filename.startswith(cls.URI_PREFIX): - return filename - else: - return cls.URI_PREFIX + cls.URI_PATH[filename] - - def __init__(self, marionette): - self.runjs = lambda x: marionette.execute_script(x, - new_sandbox=False, - sandbox='system') - - def read_file(self, filename): - """Read file and return the contents as string.""" - content = self._read_uri(self.get_uri(filename)) - content = content.replace('"use strict";', '') - return StringUtility.remove_non_ascii(content) - - def _read_uri(self, uri): - """Read URI in system and return the contents as string.""" - # Open the uri as a channel. - self.runjs(self.CODE_OPEN_CHANNEL_BY_URI % {'uri': uri}) - - # Make sure spec is a jar uri, and not recursive. - # Ex: 'jar:file:///system/b2g/omni.ja!/modules/ril_worker.js' - # - # For simplicity, we don't handle other special cases in this test. - # If B2G build system changes in the future, such as put the jar in - # another jar, the test case will fail. - spec = self.runjs(self.CODE_GET_SPEC) - if (not spec.startswith('jar:file://')) or (spec.count('jar:') != 1): - raise Exception('URI resolve error') - - # Read the content from channel. - content = self.runjs(self.CODE_READ_CONTENT) - return content - - -class JSHintEngine: - - """Invoke jshint script on system.""" - - CODE_INIT_JSHINT = ''' - %(script)s; - global.JSHINT = JSHINT; - global.options = JSON.parse(%(config_string)s); - global.globals = global.options.globals; - delete global.options.globals; - ''' - - CODE_RUN_JSHINT = ''' - global.script = %(code)s; - return global.JSHINT(global.script, global.options, global.globals); - ''' - - CODE_GET_JSHINT_ERROR = ''' - return global.JSHINT.errors; - ''' - - def __init__(self, marionette, script, config): - # Remove single line comment in config. - config = '\n'.join([line.partition('//')[0] - for line in config.splitlines()]) - - # Set global (JSHINT, options, global) in js environment. - self.runjs = lambda x: marionette.execute_script(x, - new_sandbox=False, - sandbox='system') - self.runjs(self.CODE_INIT_JSHINT % - {'script': script, 'config_string': repr(config)}) - - def run(self, code, filename=''): - """Excute JShint check for the given code.""" - check_pass = self.runjs(self.CODE_RUN_JSHINT % {'code': repr(code)}) - errors = self.runjs(self.CODE_GET_JSHINT_ERROR) - return check_pass, self._get_error_messages(errors, filename) - - def _get_error_messages(self, errors, filename=''): - """ - Convert an error object to a list of readable string. - - [{"a": null, "c": null, "code": "W033", "d": null, "character": 6, - "evidence": "var a", "raw": "Missing semicolon.", - "reason": "Missing semicolon.", "b": null, "scope": "(main)", "line": 1, - "id": "(error)"}] - => line 1, col 6, Missing semicolon. - - """ - LINE, COL, REASON = u'line', u'character', u'reason' - return ["%s: line %s, col %s, %s" % - (filename, error[LINE], error[COL], error[REASON]) - for error in errors if error] - - -class Linter: - - """Handle the linting related process.""" - - def __init__(self, code_reader, jshint, reporter=None): - """Set the linter with code_reader, jshint engine, and reporter. - - Should have following functionality. - - code_reader.read_file(filename) - - jshint.run(code, filename) - - reporter([...]) - - """ - self.code_reader = code_reader - self.jshint = jshint - if reporter is None: - self.reporter = lambda x: '\n'.join(x) - else: - self.reporter = reporter - - def lint_file(self, filename): - """Lint the file and return (pass, error_message).""" - # Get code contents. - code = self.code_reader.read_file(filename) - lines = code.splitlines() - import_list = StringUtility.get_imported_list(lines) - if not import_list: - check_pass, error_message = self.jshint.run(code, filename) - else: - newlines, info = self._merge_multiple_codes(filename, import_list) - # Each line of |newlines| contains '\n'. - check_pass, error_message = self.jshint.run(''.join(newlines)) - error_message = self._convert_merged_result(error_message, info) - # Only keep errors for this file. - error_message = [line for line in error_message - if line.startswith(filename)] - check_pass = (len(error_message) == 0) - return check_pass, self.reporter(error_message) - - def _merge_multiple_codes(self, filename, import_list): - """Merge multiple codes from filename and import_list.""" - dirname, filename = os.path.split(filename) - dst_line = 1 - dst_results = [] - info = [] - - # Put the imported script first, and then the original script. - for f in import_list + [filename]: - filepath = os.path.join(dirname, f) - - # Maintain a mapping table. - # New line number after merge => original file and line number. - info.append((dst_line, filepath, 1)) - try: - code = self.code_reader.read_file(filepath) - lines = code.splitlines(True) # Keep '\n'. - src_results = StringUtility.auto_wrap_strict_mode( - StringUtility.auto_close(lines)) - dst_results.extend(src_results) - dst_line += len(src_results) - except: - info.pop() - return dst_results, info - - def _convert_merged_result(self, error_lines, line_info): - pattern = re.compile(r'(.*): line (\d+),(.*)') - start_line = [info[0] for info in line_info] - new_result_lines = [] - for line in error_lines: - m = pattern.match(line) - if not m: - continue - - line_number, remain = int(m.group(2)), m.group(3) - - # [1, 2, 7, 8] - # ^ for 7, pos = 3 - # ^ for 6, pos = 2 - pos = bisect.bisect_right(start_line, line_number) - dst_line, name, src_line = line_info[pos - 1] - real_line_number = line_number - dst_line + src_line - new_result_lines.append( - "%s: line %s,%s" % (name, real_line_number, remain)) - return new_result_lines - - -class TestRILCodeQuality(MarionetteTestCase): - - JSHINT_PATH = 'ril_jshint/jshint.js' - JSHINTRC_PATH = 'ril_jshint/jshintrc' - - def _read_local_file(self, filepath): - """Read file content from local (folder of this test case).""" - test_dir = os.path.dirname(inspect.getfile(TestRILCodeQuality)) - return open(os.path.join(test_dir, filepath)).read() - - def _get_extended_error_message(self, error_message): - return '\n'.join(['See errors below and more information in Bug 880643', - '\n'.join(error_message), - 'See errors above and more information in Bug 880643']) - - def _check(self, filename): - check_pass, error_message = self.linter.lint_file(filename) - self.assertTrue(check_pass, error_message) - - def setUp(self): - MarionetteTestCase.setUp(self) - self.linter = Linter( - ResourceUriFileReader(self.marionette), - JSHintEngine(self.marionette, - self._read_local_file(self.JSHINT_PATH), - self._read_local_file(self.JSHINTRC_PATH)), - self._get_extended_error_message) - - def tearDown(self): - MarionetteTestCase.tearDown(self) - - def test_RadioInterfaceLayer(self): - self._check('RadioInterfaceLayer.js') - - # Bug 936504. Disable the test for 'ril_worker.js'. It sometimes runs very - # slow and causes the timeout fail on try server. - #def test_ril_worker(self): - # self._check('ril_worker.js') - - def test_ril_consts(self): - self._check('ril_consts.js') - - def test_worker_buf(self): - self._check('worker_buf.js') diff --git a/dom/system/gonk/tests/marionette/test_screen_state.js b/dom/system/gonk/tests/marionette/test_screen_state.js deleted file mode 100644 index 2281412d5..000000000 --- a/dom/system/gonk/tests/marionette/test_screen_state.js +++ /dev/null @@ -1,47 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 10000; - -var Services = SpecialPowers.Services; - -function testScreenState(on, expected, msg) { - // send event to RadioInterface - Services.obs.notifyObservers(null, 'screen-state-changed', on); - // maybe rild/qemu needs some time to process the event - window.setTimeout(function() { - runEmulatorCmd('gsm report creg', function(result) { - is(result.pop(), 'OK', '\'gsm report creg\' successful'); - ok(result.indexOf(expected) !== -1, msg); - runNextTest(); - })}, 1000); -} - -function testScreenStateDisabled() { - testScreenState('off', '+CREG: 1', 'screen is disabled'); -} - -function testScreenStateEnabled() { - testScreenState('on', '+CREG: 2', 'screen is enabled'); -} - -var tests = [ - testScreenStateDisabled, - testScreenStateEnabled -]; - -function runNextTest() { - let test = tests.shift(); - if (!test) { - cleanUp(); - return; - } - - test(); -} - -function cleanUp() { - finish(); -} - -runNextTest(); diff --git a/dom/system/gonk/tests/marionette/test_timezone_changes.js b/dom/system/gonk/tests/marionette/test_timezone_changes.js deleted file mode 100644 index 11dbaec5a..000000000 --- a/dom/system/gonk/tests/marionette/test_timezone_changes.js +++ /dev/null @@ -1,135 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -MARIONETTE_TIMEOUT = 60000; -MARIONETTE_HEAD_JS = 'head.js'; - -function init() { - let promises = []; - - /* - * The initial timezone of the emulator could be anywhere, depends the host - * machine. Ensure resetting it to UTC before testing. - */ - promises.push(runEmulatorCmdSafe('gsm timezone 0')); - promises.push(new Promise((aResolve, aReject) => { - waitFor(aResolve, () => { - return new Date().getTimezoneOffset() === 0; - }); - })); - - return Promise.all(promises); -} - -function paddingZeros(aNumber, aLength) { - let str = '' + aNumber; - while (str.length < aLength) { - str = '0' + str; - } - - return str; -} - -function verifyDate(aTestDate, aUTCOffsetDate) { - // Verify basic properties. - is(aUTCOffsetDate.getUTCFullYear(), aTestDate.getFullYear(), 'year'); - is(aUTCOffsetDate.getUTCMonth(), aTestDate.getMonth(), 'month'); - is(aUTCOffsetDate.getUTCDate(), aTestDate.getDate(), 'date'); - is(aUTCOffsetDate.getUTCHours(), aTestDate.getHours(), 'hours'); - is(aUTCOffsetDate.getUTCMinutes(), aTestDate.getMinutes(), 'minutes'); - is(aUTCOffsetDate.getUTCMilliseconds(), aTestDate.getMilliseconds(), 'milliseconds'); - - // Ensure toLocaleString also uses correct timezone. - // It uses ICU's timezone instead of the offset calculated from gecko prtime. - let expectedDateString = - paddingZeros(aUTCOffsetDate.getUTCMonth() + 1, 2) + '/' + - paddingZeros(aUTCOffsetDate.getUTCDate(), 2); - let dateString = aTestDate.toLocaleString('en-US', { - month: '2-digit', - day: '2-digit', - }); - let expectedTimeString = - paddingZeros(aUTCOffsetDate.getUTCHours(), 2) + ':' + - paddingZeros(aUTCOffsetDate.getUTCMinutes(), 2); - let timeString = aTestDate.toLocaleString('en-US', { - hour12: false, - hour: '2-digit', - minute: '2-digit' - }); - - is(expectedDateString, dateString, 'dateString'); - is(expectedTimeString, timeString, 'timeString'); -} - -function waitForTimezoneUpdate(aTzOffset, - aTestDateInMillis = 86400000, // Use 'UTC 00:00:00, 2nd of Jan, 1970' by default. - aTransTzOffset, aTransTestDateInMillis) { - return new Promise(function(aResolve, aReject) { - window.addEventListener('moztimechange', function onevent(aEvent) { - // Since there could be multiple duplicate moztimechange event, wait until - // timezone is actually changed to expected value before removing the - // listener. - let testDate = new Date(aTestDateInMillis); - if (testDate.getTimezoneOffset() === aTzOffset) { - window.removeEventListener('moztimechange', onevent); - - // The UTC time of offsetDate is the same as the expected local time of - // testDate. We'll use it to verify the values. - let offsetDate = new Date(aTestDateInMillis - aTzOffset * 60 * 1000); - verifyDate(testDate, offsetDate); - - // Verify transition time if given. - if (aTransTzOffset !== undefined) { - testDate = new Date(aTransTestDateInMillis); - is(testDate.getTimezoneOffset(), aTransTzOffset); - - // Verify transition date. - offsetDate = new Date(aTransTestDateInMillis - aTransTzOffset * 60 * 1000); - verifyDate(testDate, offsetDate); - } - - aResolve(aEvent); - } - }); - }); -} - -function testChangeNitzTimezone(aTzDiff) { - let promises = []; - - // aTzOffset should be the expected value for getTimezoneOffset(). - // Note that getTimezoneOffset() is not so straightforward, - // it values (UTC - localtime), so UTC+08:00 returns -480. - promises.push(waitForTimezoneUpdate(-aTzDiff * 15)); - promises.push(runEmulatorCmdSafe('gsm timezone ' + aTzDiff)); - - return Promise.all(promises); -} - -function testChangeOlsonTimezone(aOlsonTz, aTzOffset, aTestDateInMillis, - aTransTzOffset, aTransTestDateInMillis) { - let promises = []; - - promises.push(waitForTimezoneUpdate(aTzOffset, aTestDateInMillis, - aTransTzOffset, aTransTestDateInMillis)); - promises.push(setSettings('time.timezone', aOlsonTz)); - - return Promise.all(promises); -} - -// Start test -startTestBase(function() { - return init() - .then(() => testChangeNitzTimezone(36)) // UTC+09:00 - .then(() => testChangeOlsonTimezone('America/New_York', - 300, 1446357600000, // 2015/11/01 02:00 UTC-04:00 => 01:00 UTC-05:00 (EST) - 240, 1425798000000)) // 2015/03/08 02:00 UTC-05:00 => 03:00 UTC-04:00 (EDT) - .then(() => testChangeNitzTimezone(-22)) // UTC-05:30 - .then(() => testChangeNitzTimezone(51)) // UTC+12:45 - .then(() => testChangeOlsonTimezone('Australia/Adelaide', - -570, 1428165000000, // 2015/04/05 03:00 UTC+10:30 => 02:00 UTC+09:30 (ACST) - -630, 1443889800000)) // 2015/10/04 02:00 UTC+09:30 => 03:00 UTC+10:30 (ACDT) - .then(() => testChangeNitzTimezone(-38)) // UTC-09:30 - .then(() => testChangeNitzTimezone(0)) // UTC - .then(() => runEmulatorCmdSafe('gsm timezone auto')); -}); diff --git a/dom/system/gonk/tests/test_ril_system_messenger.js b/dom/system/gonk/tests/test_ril_system_messenger.js deleted file mode 100644 index a588d0ddb..000000000 --- a/dom/system/gonk/tests/test_ril_system_messenger.js +++ /dev/null @@ -1,1187 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -var RIL = {}; -Cu.import("resource://gre/modules/ril_consts.js", RIL); - -XPCOMUtils.defineLazyServiceGetter(this, "gStkCmdFactory", - "@mozilla.org/icc/stkcmdfactory;1", - "nsIStkCmdFactory"); - -/** - * Name space for RILSystemMessenger.jsm. Only initialized after first call to - * newRILSystemMessenger. - */ -var RSM; - -var gReceivedMsgType = null; -var gReceivedMessage = null; - -/** - * Create a new RILSystemMessenger instance. - * - * @return a RILSystemMessenger instance. - */ -function newRILSystemMessenger() { - if (!RSM) { - RSM = Cu.import("resource://gre/modules/RILSystemMessenger.jsm", {}); - equal(typeof RSM.RILSystemMessenger, "function", "RSM.RILSystemMessenger"); - } - - let rsm = new RSM.RILSystemMessenger(); - rsm.broadcastMessage = (aType, aMessage) => { - gReceivedMsgType = aType; - gReceivedMessage = aMessage; - }; - - rsm.createCommandMessage = (aStkProactiveCmd) => { - return gStkCmdFactory.createCommandMessage(aStkProactiveCmd); - }; - - return rsm; -} - -function equal_received_system_message(aType, aMessage) { - equal(aType, gReceivedMsgType); - deepEqual(aMessage, gReceivedMessage); - gReceivedMsgType = null; - gReceivedMessage = null; -} - -/** - * Verify that each nsIXxxMessenger could be retrieved. - */ -function run_test() { - let telephonyMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsITelephonyMessenger); - - let smsMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsISmsMessenger); - - let cellbroadcastMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsICellbroadcastMessenger); - - let mobileConnectionMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsIMobileConnectionMessenger); - - let iccMessenger = Cc["@mozilla.org/ril/system-messenger-helper;1"] - .getService(Ci.nsIIccMessenger); - - ok(telephonyMessenger !== null, "Get TelephonyMessenger."); - ok(smsMessenger != null, "Get SmsMessenger."); - ok(cellbroadcastMessenger != null, "Get CellbroadcastMessenger."); - ok(mobileConnectionMessenger != null, "Get MobileConnectionMessenger."); - ok(iccMessenger != null, "Get IccMessenger."); - - run_next_test(); -} - -/** - * Verify RILSystemMessenger.notifyNewCall() - */ -add_test(function test_telephony_messenger_notify_new_call() { - let messenger = newRILSystemMessenger(); - - messenger.notifyNewCall(); - equal_received_system_message("telephony-new-call", {}); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyCallEnded() - */ -add_test(function test_telephony_messenger_notify_call_ended() { - let messenger = newRILSystemMessenger(); - - messenger.notifyCallEnded(1, - "+0987654321", - null, - true, - 500, - false, - true); - - equal_received_system_message("telephony-call-ended", { - serviceId: 1, - number: "+0987654321", - emergency: true, - duration: 500, - direction: "incoming", - hangUpLocal: true - }); - - // Verify 'optional' parameter of secondNumber. - messenger.notifyCallEnded(1, - "+0987654321", - "+1234567890", - true, - 500, - true, - false); - - equal_received_system_message("telephony-call-ended", { - serviceId: 1, - number: "+0987654321", - emergency: true, - duration: 500, - direction: "outgoing", - hangUpLocal: false, - secondNumber: "+1234567890" - }); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifySms() - */ -add_test(function test_sms_messenger_notify_sms() { - let messenger = newRILSystemMessenger(); - let timestamp = Date.now(); - let sentTimestamp = timestamp + 100; - let deliveryTimestamp = sentTimestamp + 100; - - // Verify 'sms-received' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_RECEIVED, - 1, - 2, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_RECEIVED, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS, - "+0987654321", - null, - "Incoming message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_CLASS_2, - timestamp, - sentTimestamp, - 0, - false); - - equal_received_system_message("sms-received", { - iccId: "99887766554433221100", - type: "sms", - id: 1, - threadId: 2, - delivery: "received", - deliveryStatus: "success", - sender: "+0987654321", - receiver: null, - body: "Incoming message", - messageClass: "class-2", - timestamp: timestamp, - sentTimestamp: sentTimestamp, - deliveryTimestamp: 0, - read: false - }); - - // Verify 'sms-sent' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT, - 3, - 4, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_SENT, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_PENDING, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - 0, - true); - - equal_received_system_message("sms-sent", { - iccId: "99887766554433221100", - type: "sms", - id: 3, - threadId: 4, - delivery: "sent", - deliveryStatus: "pending", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: 0, - read: true - }); - - // Verify 'sms-delivery-success' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_DELIVERY_SUCCESS, - 5, - 6, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_SENT, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - deliveryTimestamp, - true); - - equal_received_system_message("sms-delivery-success", { - iccId: "99887766554433221100", - type: "sms", - id: 5, - threadId: 6, - delivery: "sent", - deliveryStatus: "success", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: deliveryTimestamp, - read: true - }); - - // Verify 'sms-failed' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_SENT_FAILED, - 7, - 8, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_ERROR, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_ERROR, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - 0, - true); - - equal_received_system_message("sms-failed", { - iccId: "99887766554433221100", - type: "sms", - id: 7, - threadId: 8, - delivery: "error", - deliveryStatus: "error", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: 0, - read: true - }); - - // Verify 'sms-delivery-error' system message. - messenger.notifySms(Ci.nsISmsMessenger.NOTIFICATION_TYPE_DELIVERY_ERROR, - 9, - 10, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_SENT, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_ERROR, - null, - "+0987654321", - "Outgoing message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - 0, - 0, - true); - - equal_received_system_message("sms-delivery-error", { - iccId: "99887766554433221100", - type: "sms", - id: 9, - threadId: 10, - delivery: "sent", - deliveryStatus: "error", - sender: null, - receiver: "+0987654321", - body: "Outgoing message", - messageClass: "normal", - timestamp: timestamp, - sentTimestamp: 0, - deliveryTimestamp: 0, - read: true - }); - - // Verify the protection of invalid nsISmsMessenger.NOTIFICATION_TYPEs. - try { - messenger.notifySms(5, - 1, - 2, - "99887766554433221100", - Ci.nsISmsService.DELIVERY_TYPE_RECEIVED, - Ci.nsISmsService.DELIVERY_STATUS_TYPE_SUCCESS, - "+0987654321", - null, - "Incoming message", - Ci.nsISmsService.MESSAGE_CLASS_TYPE_NORMAL, - timestamp, - sentTimestamp, - 0, - false); - ok(false, "Failed to verify the protection of invalid nsISmsMessenger.NOTIFICATION_TYPE!"); - } catch (e) {} - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyCbMessageReceived() - */ -add_test(function test_cellbroadcast_messenger_notify_cb_message_received() { - let messenger = newRILSystemMessenger(); - let timestamp = Date.now(); - - // Verify ETWS - messenger.notifyCbMessageReceived(0, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_CELL_IMMEDIATE, - 256, - 4352, - null, - null, - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL, - timestamp, - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID, - true, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_EARTHQUAKE, - false, - true); - equal_received_system_message("cellbroadcast-received", { - serviceId: 0, - gsmGeographicalScope: "cell-immediate", - messageCode: 256, - messageId: 4352, - language: null, - body: null, - messageClass: "normal", - timestamp: timestamp, - cdmaServiceCategory: null, - etws: { - warningType: "earthquake", - emergencyUserAlert: false, - popup: true - } - }); - - // Verify Normal CB Message - messenger.notifyCbMessageReceived(1, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_PLMN, - 0, - 50, - "en", - "The quick brown fox jumps over the lazy dog", - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL, - timestamp, - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID, - false, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID, - false, - false); - equal_received_system_message("cellbroadcast-received", { - serviceId: 1, - gsmGeographicalScope: "plmn", - messageCode: 0, - messageId: 50, - language: "en", - body: "The quick brown fox jumps over the lazy dog", - messageClass: "normal", - timestamp: timestamp, - cdmaServiceCategory: null, - etws: null - }); - - // Verify CB Message with ETWS Info - messenger.notifyCbMessageReceived(0, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_LOCATION_AREA, - 0, - 4354, - "en", - "Earthquake & Tsunami Warning!", - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_0, - timestamp, - Ci.nsICellBroadcastService.CDMA_SERVICE_CATEGORY_INVALID, - true, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_EARTHQUAKE_TSUNAMI, - true, - false); - equal_received_system_message("cellbroadcast-received", { - serviceId: 0, - gsmGeographicalScope: "location-area", - messageCode: 0, - messageId: 4354, - language: "en", - body: "Earthquake & Tsunami Warning!", - messageClass: "class-0", - timestamp: timestamp, - cdmaServiceCategory: null, - etws: { - warningType: "earthquake-tsunami", - emergencyUserAlert: true, - popup: false - } - }); - - // Verify CDMA CB Message - messenger.notifyCbMessageReceived(0, - Ci.nsICellBroadcastService.GSM_GEOGRAPHICAL_SCOPE_INVALID, - 0, - 0, - null, - "CDMA CB Message", - Ci.nsICellBroadcastService.GSM_MESSAGE_CLASS_NORMAL, - timestamp, - 512, - false, - Ci.nsICellBroadcastService.GSM_ETWS_WARNING_INVALID, - false, - false); - equal_received_system_message("cellbroadcast-received", { - serviceId: 0, - gsmGeographicalScope: null, - messageCode: 0, - messageId: 0, - language: null, - body: "CDMA CB Message", - messageClass: "normal", - timestamp: timestamp, - cdmaServiceCategory: 512, - etws: null - }); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyUssdReceived() - */ -add_test(function test_mobileconnection_notify_ussd_received() { - let messenger = newRILSystemMessenger(); - - messenger.notifyUssdReceived(0, "USSD Message", false); - - equal_received_system_message("ussd-received", { - serviceId: 0, - message: "USSD Message", - sessionEnded: false - }); - - messenger.notifyUssdReceived(1, "USSD Message", true); - - equal_received_system_message("ussd-received", { - serviceId: 1, - message: "USSD Message", - sessionEnded: true - }); - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyCdmaInfoRecXXX() - */ -add_test(function test_mobileconnection_notify_cdma_info() { - let messenger = newRILSystemMessenger(); - - messenger.notifyCdmaInfoRecDisplay(0, "CDMA Display Info"); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - display: "CDMA Display Info" - }); - - messenger.notifyCdmaInfoRecCalledPartyNumber(1, 1, 2, "+0987654321", 3, 4); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - calledNumber: { - type: 1, - plan: 2, - number: "+0987654321", - pi: 3, - si: 4 - } - }); - - messenger.notifyCdmaInfoRecCallingPartyNumber(0, 5, 6, "+1234567890", 7, 8); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - callingNumber: { - type: 5, - plan: 6, - number: "+1234567890", - pi: 7, - si: 8 - } - }); - - messenger.notifyCdmaInfoRecConnectedPartyNumber(1, 4, 3, "+56473839201", 2, 1); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - connectedNumber: { - type: 4, - plan: 3, - number: "+56473839201", - pi: 2, - si: 1 - } - }); - - messenger.notifyCdmaInfoRecSignal(0, 1, 2, 3); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - signal: { - type: 1, - alertPitch: 2, - signal: 3 - } - }); - - messenger.notifyCdmaInfoRecRedirectingNumber(1, 8, 7, "+1029384756", 6, 5, 4); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - redirect: { - type: 8, - plan: 7, - number: "+1029384756", - pi: 6, - si: 5, - reason: 4 - } - }); - - messenger.notifyCdmaInfoRecLineControl(0, 1, 0, 1, 255); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - lineControl: { - polarityIncluded: 1, - toggle: 0, - reverse: 1, - powerDenial: 255 - } - }); - - messenger.notifyCdmaInfoRecClir(1, 256); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 1, - clirCause: 256 - }); - - messenger.notifyCdmaInfoRecAudioControl(0, 255, -1); - - equal_received_system_message("cdma-info-rec-received", { - clientId: 0, - audioControl: { - upLink: 255, - downLink: -1 - } - }); - - run_next_test(); -}); - -/** - * Verify Error Handling of StkProactiveCmdFactory.createCommand() - */ -add_test(function test_icc_stk_cmd_factory_create_command_error() { - let messenger = newRILSystemMessenger(); - - // Verify the protection of invalid typeOfCommand. - try { - gStkCmdFactory.createCommand({ - commandNumber: 0, - typeOfCommand: RIL.STK_CMD_MORE_TIME, // Invalid TypeOfCommand - commandQualifier: 0x00 - }); - - ok(false, "Failed to verify the protection of createCommand()!"); - } catch (e) { - ok(e.message.indexOf("Unknown Command Type") !== -1, - "Invalid typeOfCommand!"); - } - - run_next_test(); -}); - -/** - * Verify Error Handling of StkProactiveCmdFactory.createCommandMessage() - */ -add_test(function test_icc_stk_cmd_factory_create_system_msg_invalid_cmd_type() { - let messenger = newRILSystemMessenger(); - let iccId = "99887766554433221100"; - - // Verify the protection of invalid typeOfCommand. - try { - gStkCmdFactory.createCommandMessage({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIStkProactiveCmd]), - - // nsIStkProactiveCmd - commandNumber: 0, - typeOfCommand: RIL.STK_CMD_MORE_TIME, // Invalid TypeOfCommand - commandQualifier: 0 - }); - - ok(false, "Failed to identify invalid typeOfCommand!"); - } catch (e) { - ok(e.message.indexOf("Unknown Command Type") !== -1, - "Invalid typeOfCommand!"); - } - - run_next_test(); -}); - -/** - * Verify Error Handling of StkProactiveCmdFactory.createCommandMessage() - */ -add_test(function test_icc_stk_cmd_factory_create_system_msg_incorrect_cmd_type() { - let messenger = newRILSystemMessenger(); - let iccId = "99887766554433221100"; - - // Verify the protection of invalid typeOfCommand. - try { - gStkCmdFactory.createCommandMessage({ - QueryInterface: XPCOMUtils.generateQI([Ci.nsIStkProactiveCmd, - Ci.nsIStkProvideLocalInfoCmd]), - - // nsIStkProactiveCmd - commandNumber: 0, - typeOfCommand: RIL.STK_CMD_POLL_INTERVAL, // Incorrect typeOfCommand - commandQualifier: 0, - // nsIStkProvideLocalInfoCmd - localInfoType: 0x00, - }); - - ok(false, "Failed to identify incorrect typeOfCommand!"); - } catch (e) { - ok(e.message.indexOf("Failed to convert command into concrete class: ") !== -1); - } - - run_next_test(); -}); - -/** - * Verify RILSystemMessenger.notifyStkProactiveCommand() - */ -add_test(function test_icc_notify_stk_proactive_command() { - let messenger = newRILSystemMessenger(); - let iccId = "99887766554433221100"; - let WHT = 0xFFFFFFFF; - let BLK = 0x000000FF; - let RED = 0xFF0000FF; - let GRN = 0x00FF00FF; - let BLU = 0x0000FFFF; - let TSP = 0; - // Basic Image, see Anex B.1 in TS 31.102. - let basicIcon = { - width: 8, - height: 8, - codingScheme: "basic", - pixels: [WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT, - BLK, BLK, BLK, BLK, BLK, BLK, WHT, WHT, - WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT, - WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT, - WHT, BLK, BLK, WHT, WHT, BLK, BLK, WHT, - WHT, BLK, WHT, BLK, BLK, WHT, BLK, WHT, - WHT, WHT, BLK, BLK, BLK, BLK, WHT, WHT, - WHT, WHT, WHT, WHT, WHT, WHT, WHT, WHT] - }; - // Color Image, see Anex B.2 in TS 31.102. - let colorIcon = { - width: 8, - height: 8, - codingScheme: "color", - pixels: [BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU, - BLU, RED, RED, RED, RED, RED, RED, BLU, - BLU, RED, GRN, GRN, GRN, RED, RED, BLU, - BLU, RED, RED, GRN, GRN, RED, RED, BLU, - BLU, RED, RED, GRN, GRN, RED, RED, BLU, - BLU, RED, RED, GRN, GRN, GRN, RED, BLU, - BLU, RED, RED, RED, RED, RED, RED, BLU, - BLU, BLU, BLU, BLU, BLU, BLU, BLU, BLU] - }; - // Color Image with Transparency, see Anex B.2 in TS 31.102. - let colorTransparencyIcon = { - width: 8, - height: 8, - codingScheme: "color-transparency", - pixels: [TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP, - TSP, RED, RED, RED, RED, RED, RED, TSP, - TSP, RED, GRN, GRN, GRN, RED, RED, TSP, - TSP, RED, RED, GRN, GRN, RED, RED, TSP, - TSP, RED, RED, GRN, GRN, RED, RED, TSP, - TSP, RED, RED, GRN, GRN, GRN, RED, TSP, - TSP, RED, RED, RED, RED, RED, RED, TSP, - TSP, TSP, TSP, TSP, TSP, TSP, TSP, TSP] - }; - - let cmdCount = 0; - - // Test Messages: - let messages = [ - // STK_CMD_REFRESH - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_REFRESH, - commandQualifier: 0x04 // UICC Reset - }, - // STK_CMD_POLL_INTERVAL - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_POLL_INTERVAL, - commandQualifier: 0x00, // RFU - options: { - timeUnit: RIL.STK_TIME_UNIT_TENTH_SECOND, - timeInterval: 0x05 - } - }, - // STK_CMD_POLL_OFF - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_POLL_OFF, - commandQualifier: 0x00, // RFU - }, - // STK_CMD_PROVIDE_LOCAL_INFO - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_PROVIDE_LOCAL_INFO, - commandQualifier: 0x01, // IMEI of the terminal - options: { - localInfoType: 0x01 // IMEI of the terminal - } - }, - // STK_CMD_SET_UP_EVENT_LIST with eventList - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_EVENT_LIST, - commandQualifier: 0x00, // RFU - options: { - eventList: [ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1A, 0x1B, 0x1C ] - } - }, - // STK_CMD_SET_UP_EVENT_LIST without eventList - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_EVENT_LIST, - commandQualifier: 0x00, // RFU - options: { - eventList: null - } - }, - // STK_CMD_SET_UP_MENU with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_MENU, - commandQualifier: 0x80, // bit 8: 1 = help information available - options: { - title: "Toolkit Menu 1", - items: [ - { identifier: 0x01, text: "Menu Item 1" }, - { identifier: 0x02, text: "Menu Item 2" }, - { identifier: 0x03, text: "Menu Item 3" } - ], - isHelpAvailable: true - } - }, - // STK_CMD_SET_UP_MENU with optional properties including: - // iconInfo for this menu, iconInfo for each item and nextActionList. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_MENU, - commandQualifier: 0x00, // bit 8: 0 = help information is not available - options: { - title: "Toolkit Menu 2", - items: [ - { identifier: 0x01, - text: "Menu Item 1", - iconSelfExplanatory: true, - icons: [basicIcon] - }, - { identifier: 0x02, - text: "Menu Item 2", - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon] - }, - { identifier: 0x03, - text: "Menu Item 3", - iconSelfExplanatory: true, - icons: [basicIcon, colorIcon, colorTransparencyIcon] - }, - ], - nextActionList: [ - RIL.STK_NEXT_ACTION_END_PROACTIVE_SESSION, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL - ], - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon, colorTransparencyIcon], - isHelpAvailable: false - } - }, - // STK_CMD_SELECT_ITEM with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SELECT_ITEM, - commandQualifier: RIL.STK_PRESENTATION_TYPE_NOT_SPECIFIED, - options: { - title: null, - items: [ - { identifier: 0x01, text: "Menu Item 1" }, - { identifier: 0x02, text: "Menu Item 2" }, - { identifier: 0x03, text: "Menu Item 3" } - ], - presentationType: RIL.STK_PRESENTATION_TYPE_NOT_SPECIFIED, - isHelpAvailable: false - } - }, - // STK_CMD_SELECT_ITEM with optional properties including: - // title, iconInfo for this menu, iconInfo for each item and nextActionList. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SELECT_ITEM, - commandQualifier: RIL.STK_PRESENTATION_TYPE_NAVIGATION_OPTIONS, - options: { - title: "Selected Toolkit Menu", - items: [ - { identifier: 0x01, - text: "Menu Item 1", - iconSelfExplanatory: true, - icons: [basicIcon] - }, - { identifier: 0x02, - text: "Menu Item 2", - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon] - }, - { identifier: 0x03, - text: "Menu Item 3", - iconSelfExplanatory: true, - icons: [basicIcon, colorIcon, colorTransparencyIcon] - }, - ], - nextActionList: [ - RIL.STK_NEXT_ACTION_END_PROACTIVE_SESSION, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL, - RIL.STK_NEXT_ACTION_NULL - ], - defaultItem: 0x02, - iconSelfExplanatory: false, - icons: [basicIcon, colorIcon, colorTransparencyIcon], - presentationType: RIL.STK_PRESENTATION_TYPE_NAVIGATION_OPTIONS, - isHelpAvailable: false - } - }, - // STK_CMD_DISPLAY_TEXT with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_DISPLAY_TEXT, - commandQualifier: 0x01, // bit 1: High Priority - options: { - text: "Display Text 1", - isHighPriority: true, - userClear: false, - responseNeeded: false - } - }, - // STK_CMD_DISPLAY_TEXT with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_DISPLAY_TEXT, - commandQualifier: 0x80, // bit 8: User Clear - options: { - text: "Display Text 2", - isHighPriority: false, - userClear: true, - responseNeeded: true, - duration: { - timeUnit: RIL.STK_TIME_UNIT_TENTH_SECOND, - timeInterval: 0x05 - }, - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_SET_UP_IDLE_MODE_TEXT - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_IDLE_MODE_TEXT, - commandQualifier: 0x00, // RFU - options: { - text: "Setup Idle Mode Text" - } - }, - // STK_CMD_SEND_SS - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_SS, - commandQualifier: 0x00, // RFU - options: { - text: "Send SS", - iconSelfExplanatory: true, - icons: [colorIcon] - } - }, - // STK_CMD_SEND_USSD - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_USSD, - commandQualifier: 0x00, // RFU - options: { - text: "Send USSD" - } - }, - // STK_CMD_SEND_SMS - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_SMS, - commandQualifier: 0x00, // RFU - options: { - text: "Send SMS", - iconSelfExplanatory: false, - icons: [colorTransparencyIcon] - } - }, - // STK_CMD_SEND_DTMF - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_DTMF, - commandQualifier: 0x00, // RFU - options: { - text: "Send DTMF", - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_GET_INKEY - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_GET_INKEY, - commandQualifier: 0x84, // bit 3: isYesNoRequested, bit 8: isHelpAvailable - options: { - text: "Get Input Key", - minLength: 1, - maxLength: 1, - duration: { - timeUnit: RIL.STK_TIME_UNIT_SECOND, - timeInterval: 0x0A - }, - isAlphabet: false, - isUCS2: false, - isYesNoRequested: true, - isHelpAvailable: true, - defaultText: null, - iconSelfExplanatory: false, - icons: [colorIcon] - } - }, - // STK_CMD_GET_INPUT - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_GET_INPUT, - commandQualifier: 0x0F, // bit 1-4: isAlphabet, isUCS2, hideInput, isPacked - options: { - text: "Get Input Text", - minLength: 1, - maxLength: 255, - defaultText: "Default Input Text", - isAlphabet: true, - isUCS2: true, - hideInput: true, - isPacked: true, - isHelpAvailable: false, - defaultText: null, - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_SET_UP_CALL with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_CALL, - commandQualifier: 0x00, // RFU - options: { - address: "+0987654321" - } - }, - // STK_CMD_SET_UP_CALL with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SET_UP_CALL, - commandQualifier: 0x00, // RFU - options: { - address: "+0987654321", - confirmMessage: { - text: "Confirm Message", - iconSelfExplanatory: false, - icons: [colorIcon] - }, - callMessage: { - text: "Call Message", - iconSelfExplanatory: true, - icons: [basicIcon] - }, - duration: { - timeUnit: RIL.STK_TIME_UNIT_SECOND, - timeInterval: 0x0A - } - } - }, - // STK_CMD_LAUNCH_BROWSER with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_LAUNCH_BROWSER, - commandQualifier: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER, - options: { - url: "http://www.mozilla.org", - mode: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER - } - }, - // STK_CMD_LAUNCH_BROWSER with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_LAUNCH_BROWSER, - commandQualifier: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER, - options: { - url: "http://www.mozilla.org", - mode: RIL.STK_BROWSER_MODE_USING_NEW_BROWSER, - confirmMessage: { - text: "Confirm Message for Launch Browser", - iconSelfExplanatory: false, - icons: [colorTransparencyIcon] - } - } - }, - // STK_CMD_PLAY_TONE with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_PLAY_TONE, - commandQualifier: 0x01, // isVibrate - options: { - text: null, - isVibrate: true - } - }, - // STK_CMD_PLAY_TONE with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_PLAY_TONE, - commandQualifier: 0x00, // isVibrate = false - options: { - text: "Play Tone", - tone: RIL.STK_TONE_TYPE_CONGESTION, - isVibrate: false, - duration: { - timeUnit: RIL.STK_TIME_UNIT_SECOND, - timeInterval: 0x0A - }, - iconSelfExplanatory: true, - icons: [basicIcon] - } - }, - // STK_CMD_TIMER_MANAGEMENT with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_TIMER_MANAGEMENT, - commandQualifier: RIL.STK_TIMER_DEACTIVATE, - options: { - timerId: 0x08, - timerAction: RIL.STK_TIMER_DEACTIVATE - } - }, - // STK_CMD_TIMER_MANAGEMENT with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_TIMER_MANAGEMENT, - commandQualifier: RIL.STK_TIMER_START, - options: { - timerId: 0x01, - timerValue: (12 * 60 * 60) + (30 * 60) + (30), // 12:30:30 - timerAction: RIL.STK_TIMER_START - } - }, - // STK_CMD_OPEN_CHANNEL with mandatory properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_OPEN_CHANNEL, - commandQualifier: 0x00, //RFU - options: { - text: null, - } - }, - // STK_CMD_OPEN_CHANNEL with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_OPEN_CHANNEL, - commandQualifier: 0x00, //RFU - options: { - text: "Open Channel", - iconSelfExplanatory: false, - icons: [colorIcon] - } - }, - // STK_CMD_CLOSE_CHANNEL with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_CLOSE_CHANNEL, - commandQualifier: 0x00, //RFU - options: { - text: "Close Channel", - iconSelfExplanatory: true, - icons: [colorTransparencyIcon] - } - }, - // STK_CMD_SEND_DATA with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_SEND_DATA, - commandQualifier: 0x00, //RFU - options: { - text: null, - iconSelfExplanatory: false, - icons: [basicIcon] - } - }, - // STK_CMD_RECEIVE_DATA with optional properties. - { - commandNumber: ++cmdCount, - typeOfCommand: RIL.STK_CMD_RECEIVE_DATA, - commandQualifier: 0x00, //RFU - options: { - text: "Receive Data" - } - }, - null // Termination condition to run_next_test() - ]; - - messages.forEach(function(aMessage) { - if (!aMessage) { - run_next_test(); - return; - } - - messenger.notifyStkProactiveCommand(iccId, - gStkCmdFactory.createCommand(aMessage)); - - equal_received_system_message("icc-stkcommand", { - iccId: iccId, - command: aMessage - }); - }); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_barring_password.js b/dom/system/gonk/tests/test_ril_worker_barring_password.js deleted file mode 100644 index fcd3e4405..000000000 --- a/dom/system/gonk/tests/test_ril_worker_barring_password.js +++ /dev/null @@ -1,61 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -const PIN = "0000"; -const NEW_PIN = "1234"; - -add_test(function test_change_call_barring_password() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - function do_test(facility, pin, newPin) { - buf.sendParcel = function fakeSendParcel () { - // Request Type. - equal(this.readInt32(), REQUEST_CHANGE_BARRING_PASSWORD); - - // Token : we don't care. - this.readInt32(); - - let parcel = this.readStringList(); - equal(parcel.length, 3); - equal(parcel[0], facility); - equal(parcel[1], pin); - equal(parcel[2], newPin); - }; - - let options = {facility: facility, pin: pin, newPin: newPin}; - context.RIL.changeCallBarringPassword(options); - } - - do_test(ICC_CB_FACILITY_BA_ALL, PIN, NEW_PIN); - - run_next_test(); -}); - -add_test(function test_check_change_call_barring_password_result() { - let barringPasswordOptions; - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - - let context = worker.ContextPool._contexts[0]; - context.RIL.changeCallBarringPassword = - function fakeChangeCallBarringPassword(options) { - barringPasswordOptions = options; - context.RIL[REQUEST_CHANGE_BARRING_PASSWORD](0, {}); - }; - - context.RIL.changeCallBarringPassword({pin: PIN, newPin: NEW_PIN}); - - let postedMessage = workerHelper.postedMessage; - equal(barringPasswordOptions.pin, PIN); - equal(barringPasswordOptions.newPin, NEW_PIN); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_buf.js b/dom/system/gonk/tests/test_ril_worker_buf.js deleted file mode 100644 index 30054a881..000000000 --- a/dom/system/gonk/tests/test_ril_worker_buf.js +++ /dev/null @@ -1,187 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -function run_test() { - run_next_test(); -} - -/** - * Add test function with specified parcel and request handler. - * - * @param parcel - * Incoming parcel to be tested. - * @param handler - * Handler to be invoked as RIL request handler. - */ -function add_test_incoming_parcel(parcel, handler) { - add_test(function test_incoming_parcel() { - let worker = newWorker({ - postRILMessage: function(data) { - // do nothing - }, - postMessage: function(message) { - // do nothing - } - }); - - if (!parcel) { - parcel = newIncomingParcel(-1, - worker.RESPONSE_TYPE_UNSOLICITED, - worker.REQUEST_VOICE_REGISTRATION_STATE, - [0, 0, 0, 0]); - } - - let context = worker.ContextPool._contexts[0]; - // supports only requests less or equal than UINT8_MAX(255). - let buf = context.Buf; - let request = parcel[buf.PARCEL_SIZE_SIZE + buf.UINT32_SIZE]; - context.RIL[request] = function ril_request_handler() { - handler.apply(this, arguments); - }; - - worker.onRILMessage(0, parcel); - - // end of incoming parcel's trip, let's do next test. - run_next_test(); - }); -} - -// Test normal parcel handling. -add_test_incoming_parcel(null, - function test_normal_parcel_handling() { - let self = this; - try { - // reads exactly the same size, should not throw anything. - self.context.Buf.readInt32(); - } catch (e) { - ok(false, "Got exception: " + e); - } - } -); - -// Test parcel under read. -add_test_incoming_parcel(null, - function test_parcel_under_read() { - let self = this; - try { - // reads less than parcel size, should not throw. - self.context.Buf.readUint16(); - } catch (e) { - ok(false, "Got exception: " + e); - } - } -); - -// Test parcel over read. -add_test_incoming_parcel(null, - function test_parcel_over_read() { - let buf = this.context.Buf; - - // read all data available - while (buf.readAvailable > 0) { - buf.readUint8(); - } - - throws(function over_read_handler() { - // reads more than parcel size, should throw an error. - buf.readUint8(); - },"Trying to read data beyond the parcel end!"); - } -); - -// Test Bug 814761: buffer overwritten -add_test(function test_incoming_parcel_buffer_overwritten() { - let worker = newWorker({ - postRILMessage: function(data) { - // do nothing - }, - postMessage: function(message) { - // do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - // A convenient alias. - let buf = context.Buf; - - // Allocate an array of specified size and set each of its elements to value. - function calloc(length, value) { - let array = new Array(length); - for (let i = 0; i < length; i++) { - array[i] = value; - } - return array; - } - - // Do nothing in handleParcel(). - let request = worker.REQUEST_VOICE_REGISTRATION_STATE; - context.RIL[request] = null; - - // Prepare two parcels, whose sizes are both smaller than the incoming buffer - // size but larger when combined, to trigger the bug. - let pA_dataLength = buf.incomingBufferLength / 2; - let pA = newIncomingParcel(-1, - worker.RESPONSE_TYPE_UNSOLICITED, - request, - calloc(pA_dataLength, 1)); - let pA_parcelSize = pA.length - buf.PARCEL_SIZE_SIZE; - - let pB_dataLength = buf.incomingBufferLength * 3 / 4; - let pB = newIncomingParcel(-1, - worker.RESPONSE_TYPE_UNSOLICITED, - request, - calloc(pB_dataLength, 1)); - let pB_parcelSize = pB.length - buf.PARCEL_SIZE_SIZE; - - // First, send an incomplete pA and verifies related data pointer: - let p1 = pA.subarray(0, pA.length - 1); - worker.onRILMessage(0, p1); - // The parcel should not have been processed. - equal(buf.readAvailable, 0); - // buf.currentParcelSize should have been set because incoming data has more - // than 4 octets. - equal(buf.currentParcelSize, pA_parcelSize); - // buf.readIncoming should contains remaining unconsumed octets count. - equal(buf.readIncoming, p1.length - buf.PARCEL_SIZE_SIZE); - // buf.incomingWriteIndex should be ready to accept the last octet. - equal(buf.incomingWriteIndex, p1.length); - - // Second, send the last octet of pA and whole pB. The Buf should now expand - // to cover both pA & pB. - let p2 = new Uint8Array(1 + pB.length); - p2.set(pA.subarray(pA.length - 1), 0); - p2.set(pB, 1); - worker.onRILMessage(0, p2); - // The parcels should have been both consumed. - equal(buf.readAvailable, 0); - // No parcel data remains. - equal(buf.currentParcelSize, 0); - // No parcel data remains. - equal(buf.readIncoming, 0); - // The Buf should now expand to cover both pA & pB. - equal(buf.incomingWriteIndex, pA.length + pB.length); - - // end of incoming parcel's trip, let's do next test. - run_next_test(); -}); - -// Test Buf.readUint8Array. -add_test_incoming_parcel(null, - function test_buf_readUint8Array() { - let buf = this.context.Buf; - - let u8array = buf.readUint8Array(1); - equal(u8array instanceof Uint8Array, true); - equal(u8array.length, 1); - equal(buf.readAvailable, 3); - - u8array = buf.readUint8Array(2); - equal(u8array.length, 2); - equal(buf.readAvailable, 1); - - throws(function over_read_handler() { - // reads more than parcel size, should throw an error. - u8array = buf.readUint8Array(2); - }, "Trying to read data beyond the parcel end!"); - } -); diff --git a/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js b/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js deleted file mode 100644 index 335c0c403..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cdma_info_rec.js +++ /dev/null @@ -1,234 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Helper function. - */ -function newWorkerWithParcel(parcelBuf) { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let index = 0; // index for read - let buf = parcelBuf; - - let context = worker.ContextPool._contexts[0]; - context.Buf.readUint8 = function() { - return buf[index++]; - }; - - context.Buf.readUint16 = function() { - return buf[index++]; - }; - - context.Buf.readInt32 = function() { - return buf[index++]; - }; - - context.Buf.seekIncoming = function(offset) { - index += offset / context.Buf.UINT32_SIZE; - }; - - return worker; -} - -// Test CDMA information record decoder. - -/** - * Verify decoder for type DISPLAY - */ -add_test(function test_display() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x00, // type: display - 0x09, // length: 9 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Info"); - - run_next_test(); -}); - -/** - * Verify decoder for type EXTENDED DISPLAY - */ -add_test(function test_extended_display() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x07, // type: extended display - 0x12, // length: 18 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74, - 0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E, - 0x66, 0x6F, 0x00, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Extended Info"); - - run_next_test(); -}); - -/** - * Verify decoder for mixed type - */ -add_test(function test_mixed() { - let worker = newWorkerWithParcel([ - 0x02, // two inforemation record - 0x00, // type: display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x31, 0x00, - 0x07, // type: extended display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x32, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Info 1"); - equal(records[1].display, "Test Info 2"); - - run_next_test(); -}); - -/** - * Verify decoder for multiple types - */ -add_test(function test_multiple() { - let worker = newWorkerWithParcel([ - 0x02, // two inforemation record - 0x00, // type: display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x31, 0x00, - 0x00, // type: display - 0x0B, // length: 11 - 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66, - 0x6F, 0x20, 0x32, 0x00]); - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].display, "Test Info 1"); - equal(records[1].display, "Test Info 2"); - - run_next_test(); -}); - -/** - * Verify decoder for Signal Type - */ -add_test(function test_signal() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x04, // type: signal - 0x01, // isPresent: non-zero - 0x00, // signalType: Tone signal (00) - 0x01, // alertPitch: High pitch - 0x03]); // signal: Abbreviated intercept (000011) - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].signal.type, 0x00); - equal(records[0].signal.alertPitch, 0x01); - equal(records[0].signal.signal, 0x03); - - run_next_test(); -}); - -/** - * Verify decoder for Signal Type for Not Presented - */ -add_test(function test_signal_not_present() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x04, // type: signal - 0x00, // isPresent: zero - 0x00, // signalType: Tone signal (00) - 0x01, // alertPitch: High pitch - 0x03]); // signal: Abbreviated intercept (000011) - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records.length, 0); - - run_next_test(); -}); - -/** - * Verify decoder for Line Control - */ -add_test(function test_line_control() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x06, // type: line control - 0x01, // polarity included - 0x00, // not toggled - 0x01, // reversed - 0xFF]); // Power denial timeout: 255 * 5 ms - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].lineControl.polarityIncluded, 1); - equal(records[0].lineControl.toggle, 0); - equal(records[0].lineControl.reverse, 1); - equal(records[0].lineControl.powerDenial, 255); - - run_next_test(); -}); - -/** - * Verify decoder for CLIR Cause - */ -add_test(function test_clir() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x08, // type: clir - 0x01]); // cause: Rejected by user - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].clirCause, 1); - - run_next_test(); -}); - -/** - * Verify decoder for Audio Control - */ -add_test(function test_clir() { - let worker = newWorkerWithParcel([ - 0x01, // one inforemation record - 0x0A, // type: audio control - 0x01, // uplink - 0xFF]); // downlink - let context = worker.ContextPool._contexts[0]; - let helper = context.CdmaPDUHelper; - let records = helper.decodeInformationRecord(); - - equal(records[0].audioControl.upLink, 1); - equal(records[0].audioControl.downLink, 255); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js deleted file mode 100644 index d5645a3cf..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_config.js +++ /dev/null @@ -1,470 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_ril_worker_cellbroadcast_activate() { - let worker = newWorker({ - postRILMessage: function(id, parcel) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let parcelTypes = []; - let org_newParcel = context.Buf.newParcel; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - org_newParcel.apply(this, arguments); - }; - - function setup(isCdma) { - context.RIL._isCdma = isCdma; - context.RIL.cellBroadcastDisabled = false; - context.RIL.mergedCellBroadcastConfig = [1, 2, 4, 7]; // 1, 4-6 - parcelTypes = []; - } - - function test(isCdma, expectedRequest) { - setup(isCdma); - context.RIL.setCellBroadcastDisabled({disabled: true}); - // Makesure that request parcel is sent out. - notEqual(parcelTypes.indexOf(expectedRequest), -1); - equal(context.RIL.cellBroadcastDisabled, true); - } - - test(false, REQUEST_GSM_SMS_BROADCAST_ACTIVATION); - test(true, REQUEST_CDMA_SMS_BROADCAST_ACTIVATION); - - run_next_test(); -}); - -add_test(function test_ril_worker_cellbroadcast_config() { - let currentParcel; - let worker = newWorker({ - postRILMessage: function(id, parcel) { - currentParcel = parcel; - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - function U32ArrayFromParcelArray(pa) { - do_print(pa); - let out = []; - for (let i = 0; i < pa.length; i += 4) { - let data = pa[i] + (pa[i+1] << 8) + (pa[i+2] << 16) + (pa[i+3] << 24); - out.push(data); - } - return out; - } - - function test(isCdma, configs, expected) { - let parcelType = isCdma ? REQUEST_CDMA_SET_BROADCAST_SMS_CONFIG - : REQUEST_GSM_SET_BROADCAST_SMS_CONFIG; - - let found = false; - worker.postRILMessage = function(id, parcel) { - let u32Parcel = U32ArrayFromParcelArray(Array.slice(parcel)); - if (u32Parcel[1] != parcelType) { - return; - } - - found = true; - // Check parcel. Data start from 4th word (32bit) - equal(u32Parcel.slice(3).toString(), expected); - }; - - context.RIL._isCdma = isCdma; - context.RIL.setSmsBroadcastConfig(configs); - - // Makesure that request parcel is sent out. - ok(found); - } - - // (GSM) RIL writes the following data to outgoing parcel: - // nums [(from, to, 0, 0xFF, 1), ... ] - test(false, - [1, 2, 4, 7] /* 1, 4-6 */, - ["2", "1,1,0,255,1", "4,6,0,255,1"].join()); - - // (CDMA) RIL writes the following data to outgoing parcel: - // nums [(id, 0, 1), ... ] - test(true, - [1, 2, 4, 7] /* 1, 4-6 */, - ["4", "1,0,1", "4,0,1", "5,0,1", "6,0,1"].join()); - - run_next_test(); -}); - -add_test(function test_ril_worker_cellbroadcast_merge_config() { - let worker = newWorker({ - postRILMessage: function(id, parcel) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - function test(isCdma, configs, expected) { - context.RIL._isCdma = isCdma; - context.RIL.cellBroadcastConfigs = configs; - context.RIL._mergeAllCellBroadcastConfigs(); - equal(context.RIL.mergedCellBroadcastConfig.toString(), expected); - } - - let configs = { - MMI: [1, 2, 4, 7], // 1, 4-6 - CBMI: [6, 9], // 6-8 - CBMID: [8, 11], // 8-10 - CBMIR: [10, 13] // 10-12 - }; - - test(false, configs, "1,2,4,13"); - test(true, configs, "1,2,4,7"); - - run_next_test(); -}); - -add_test(function test_ril_worker_cellbroadcast_set_search_list() { - let worker = newWorker({ - postRILMessage: function(id, parcel) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - - function test(aIsCdma, aSearchList, aExpected) { - context.RIL._isCdma = aIsCdma; - - let options = { searchList: aSearchList }; - context.RIL.setCellBroadcastSearchList(options); - // Enforce the MMI result to string for comparison. - equal("" + context.RIL.cellBroadcastConfigs.MMI, aExpected); - do_check_eq(options.errorMsg, undefined); - } - - let searchListStr = "1,2,3,4"; - let searchList = { gsm: "1,2,3,4", cdma: "5,6,7,8" }; - - test(false, searchListStr, "1,2,2,3,3,4,4,5"); - test(true, searchListStr, "1,2,2,3,3,4,4,5"); - test(false, searchList, "1,2,2,3,3,4,4,5"); - test(true, searchList, "5,6,6,7,7,8,8,9"); - test(false, null, "null"); - test(true, null, "null"); - - run_next_test(); -}); - -add_test(function test_ril_worker_mergeCellBroadcastConfigs() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - function test(olist, from, to, expected) { - let result = ril._mergeCellBroadcastConfigs(olist, from, to); - equal(JSON.stringify(expected), JSON.stringify(result)); - } - - test(null, 0, 1, [0, 1]); - - test([10, 13], 7, 8, [ 7, 8, 10, 13]); - test([10, 13], 7, 9, [ 7, 9, 10, 13]); - test([10, 13], 7, 10, [ 7, 13]); - test([10, 13], 7, 11, [ 7, 13]); - test([10, 13], 7, 12, [ 7, 13]); - test([10, 13], 7, 13, [ 7, 13]); - test([10, 13], 7, 14, [ 7, 14]); - test([10, 13], 7, 15, [ 7, 15]); - test([10, 13], 7, 16, [ 7, 16]); - test([10, 13], 8, 9, [ 8, 9, 10, 13]); - test([10, 13], 8, 10, [ 8, 13]); - test([10, 13], 8, 11, [ 8, 13]); - test([10, 13], 8, 12, [ 8, 13]); - test([10, 13], 8, 13, [ 8, 13]); - test([10, 13], 8, 14, [ 8, 14]); - test([10, 13], 8, 15, [ 8, 15]); - test([10, 13], 8, 16, [ 8, 16]); - test([10, 13], 9, 10, [ 9, 13]); - test([10, 13], 9, 11, [ 9, 13]); - test([10, 13], 9, 12, [ 9, 13]); - test([10, 13], 9, 13, [ 9, 13]); - test([10, 13], 9, 14, [ 9, 14]); - test([10, 13], 9, 15, [ 9, 15]); - test([10, 13], 9, 16, [ 9, 16]); - test([10, 13], 10, 11, [10, 13]); - test([10, 13], 10, 12, [10, 13]); - test([10, 13], 10, 13, [10, 13]); - test([10, 13], 10, 14, [10, 14]); - test([10, 13], 10, 15, [10, 15]); - test([10, 13], 10, 16, [10, 16]); - test([10, 13], 11, 12, [10, 13]); - test([10, 13], 11, 13, [10, 13]); - test([10, 13], 11, 14, [10, 14]); - test([10, 13], 11, 15, [10, 15]); - test([10, 13], 11, 16, [10, 16]); - test([10, 13], 12, 13, [10, 13]); - test([10, 13], 12, 14, [10, 14]); - test([10, 13], 12, 15, [10, 15]); - test([10, 13], 12, 16, [10, 16]); - test([10, 13], 13, 14, [10, 14]); - test([10, 13], 13, 15, [10, 15]); - test([10, 13], 13, 16, [10, 16]); - test([10, 13], 14, 15, [10, 13, 14, 15]); - test([10, 13], 14, 16, [10, 13, 14, 16]); - test([10, 13], 15, 16, [10, 13, 15, 16]); - - test([10, 13, 14, 17], 7, 8, [ 7, 8, 10, 13, 14, 17]); - test([10, 13, 14, 17], 7, 9, [ 7, 9, 10, 13, 14, 17]); - test([10, 13, 14, 17], 7, 10, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 11, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 12, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 13, [ 7, 13, 14, 17]); - test([10, 13, 14, 17], 7, 14, [ 7, 17]); - test([10, 13, 14, 17], 7, 15, [ 7, 17]); - test([10, 13, 14, 17], 7, 16, [ 7, 17]); - test([10, 13, 14, 17], 7, 17, [ 7, 17]); - test([10, 13, 14, 17], 7, 18, [ 7, 18]); - test([10, 13, 14, 17], 7, 19, [ 7, 19]); - test([10, 13, 14, 17], 8, 9, [ 8, 9, 10, 13, 14, 17]); - test([10, 13, 14, 17], 8, 10, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 11, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 12, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 13, [ 8, 13, 14, 17]); - test([10, 13, 14, 17], 8, 14, [ 8, 17]); - test([10, 13, 14, 17], 8, 15, [ 8, 17]); - test([10, 13, 14, 17], 8, 16, [ 8, 17]); - test([10, 13, 14, 17], 8, 17, [ 8, 17]); - test([10, 13, 14, 17], 8, 18, [ 8, 18]); - test([10, 13, 14, 17], 8, 19, [ 8, 19]); - test([10, 13, 14, 17], 9, 10, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 11, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 12, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 13, [ 9, 13, 14, 17]); - test([10, 13, 14, 17], 9, 14, [ 9, 17]); - test([10, 13, 14, 17], 9, 15, [ 9, 17]); - test([10, 13, 14, 17], 9, 16, [ 9, 17]); - test([10, 13, 14, 17], 9, 17, [ 9, 17]); - test([10, 13, 14, 17], 9, 18, [ 9, 18]); - test([10, 13, 14, 17], 9, 19, [ 9, 19]); - test([10, 13, 14, 17], 10, 11, [10, 13, 14, 17]); - test([10, 13, 14, 17], 10, 12, [10, 13, 14, 17]); - test([10, 13, 14, 17], 10, 13, [10, 13, 14, 17]); - test([10, 13, 14, 17], 10, 14, [10, 17]); - test([10, 13, 14, 17], 10, 15, [10, 17]); - test([10, 13, 14, 17], 10, 16, [10, 17]); - test([10, 13, 14, 17], 10, 17, [10, 17]); - test([10, 13, 14, 17], 10, 18, [10, 18]); - test([10, 13, 14, 17], 10, 19, [10, 19]); - test([10, 13, 14, 17], 11, 12, [10, 13, 14, 17]); - test([10, 13, 14, 17], 11, 13, [10, 13, 14, 17]); - test([10, 13, 14, 17], 11, 14, [10, 17]); - test([10, 13, 14, 17], 11, 15, [10, 17]); - test([10, 13, 14, 17], 11, 16, [10, 17]); - test([10, 13, 14, 17], 11, 17, [10, 17]); - test([10, 13, 14, 17], 11, 18, [10, 18]); - test([10, 13, 14, 17], 11, 19, [10, 19]); - test([10, 13, 14, 17], 12, 13, [10, 13, 14, 17]); - test([10, 13, 14, 17], 12, 14, [10, 17]); - test([10, 13, 14, 17], 12, 15, [10, 17]); - test([10, 13, 14, 17], 12, 16, [10, 17]); - test([10, 13, 14, 17], 12, 17, [10, 17]); - test([10, 13, 14, 17], 12, 18, [10, 18]); - test([10, 13, 14, 17], 12, 19, [10, 19]); - test([10, 13, 14, 17], 13, 14, [10, 17]); - test([10, 13, 14, 17], 13, 15, [10, 17]); - test([10, 13, 14, 17], 13, 16, [10, 17]); - test([10, 13, 14, 17], 13, 17, [10, 17]); - test([10, 13, 14, 17], 13, 18, [10, 18]); - test([10, 13, 14, 17], 13, 19, [10, 19]); - test([10, 13, 14, 17], 14, 15, [10, 13, 14, 17]); - test([10, 13, 14, 17], 14, 16, [10, 13, 14, 17]); - test([10, 13, 14, 17], 14, 17, [10, 13, 14, 17]); - test([10, 13, 14, 17], 14, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 14, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 15, 16, [10, 13, 14, 17]); - test([10, 13, 14, 17], 15, 17, [10, 13, 14, 17]); - test([10, 13, 14, 17], 15, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 15, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 16, 17, [10, 13, 14, 17]); - test([10, 13, 14, 17], 16, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 16, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 17, 18, [10, 13, 14, 18]); - test([10, 13, 14, 17], 17, 19, [10, 13, 14, 19]); - test([10, 13, 14, 17], 18, 19, [10, 13, 14, 17, 18, 19]); - - test([10, 13, 16, 19], 7, 14, [ 7, 14, 16, 19]); - test([10, 13, 16, 19], 7, 15, [ 7, 15, 16, 19]); - test([10, 13, 16, 19], 7, 16, [ 7, 19]); - test([10, 13, 16, 19], 8, 14, [ 8, 14, 16, 19]); - test([10, 13, 16, 19], 8, 15, [ 8, 15, 16, 19]); - test([10, 13, 16, 19], 8, 16, [ 8, 19]); - test([10, 13, 16, 19], 9, 14, [ 9, 14, 16, 19]); - test([10, 13, 16, 19], 9, 15, [ 9, 15, 16, 19]); - test([10, 13, 16, 19], 9, 16, [ 9, 19]); - test([10, 13, 16, 19], 10, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 10, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 10, 16, [10, 19]); - test([10, 13, 16, 19], 11, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 11, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 11, 16, [10, 19]); - test([10, 13, 16, 19], 12, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 12, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 12, 16, [10, 19]); - test([10, 13, 16, 19], 13, 14, [10, 14, 16, 19]); - test([10, 13, 16, 19], 13, 15, [10, 15, 16, 19]); - test([10, 13, 16, 19], 13, 16, [10, 19]); - test([10, 13, 16, 19], 14, 15, [10, 13, 14, 15, 16, 19]); - test([10, 13, 16, 19], 14, 16, [10, 13, 14, 19]); - test([10, 13, 16, 19], 15, 16, [10, 13, 15, 19]); - - run_next_test(); -}); - -add_test(function test_ril_consts_cellbroadcast_misc() { - // Must be 16 for indexing. - equal(CB_DCS_LANG_GROUP_1.length, 16); - equal(CB_DCS_LANG_GROUP_2.length, 16); - - // Array length must be even. - equal(CB_NON_MMI_SETTABLE_RANGES.length & 0x01, 0); - for (let i = 0; i < CB_NON_MMI_SETTABLE_RANGES.length;) { - let from = CB_NON_MMI_SETTABLE_RANGES[i++]; - let to = CB_NON_MMI_SETTABLE_RANGES[i++]; - equal(from < to, true); - } - - run_next_test(); -}); - -add_test(function test_ril_worker_checkCellBroadcastMMISettable() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - function test(from, to, expected) { - equal(expected, ril._checkCellBroadcastMMISettable(from, to)); - } - - test(-2, -1, false); - test(-1, 0, false); - test(0, 1, true); - test(1, 1, false); - test(2, 1, false); - test(65536, 65537, false); - - // We have both [4096, 4224), [4224, 4352), so it's actually [4096, 4352), - // and [61440, 65536), [65535, 65536), so it's actually [61440, 65536). - for (let i = 0; i < CB_NON_MMI_SETTABLE_RANGES.length;) { - let from = CB_NON_MMI_SETTABLE_RANGES[i++]; - let to = CB_NON_MMI_SETTABLE_RANGES[i++]; - if ((from != 4224) && (from != 65535)) { - test(from - 1, from, true); - } - test(from - 1, from + 1, false); - test(from - 1, to, false); - test(from - 1, to + 1, false); - test(from, from + 1, false); - test(from, to, false); - test(from, to + 1, false); - if ((from + 1) < to) { - test(from + 1, to, false); - test(from + 1, to + 1, false); - } - if ((to != 4224) && (to < 65535)) { - test(to, to + 1, true); - test(to + 1, to + 2, true); - } - } - - run_next_test(); -}); - -add_test(function test_ril_worker_CellBroadcastDisabled() { - let count = 0; - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - if (message.rilMessageType == "cellbroadcast-received") { - ok(true, "cellbroadcast-received: " + JSON.stringify(message)); - count++; - } - } - }); - - function buildPdu(aMessageId) { - return "C002" + aMessageId + "011154741914AFA7C76B9058" + - "FEBEBB41E6371EA4AEB7E173D0DB5E96" + - "83E8E832881DD6E741E4F7B9D168341A" + - "8D46A3D168341A8D46A3D168341A8D46" + - "A3D168341A8D46A3D168341A8D46A3D1" + - "68341A8D46A3D100"; - } - - worker.ContextPool._contexts[0].RIL.cellBroadcastDisabled = true; - - let networkAlertIds = [ - "1100", "1107", // ETWS - "1112", "112F", // CMAS - "1130", "18FF", // PWS - ]; - networkAlertIds.forEach(aMessageId => { - worker.onRILMessage( - 0, - newIncomingParcel( - -1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(buildPdu(aMessageId)))); - }); - equal(count, networkAlertIds.length, "Alerts shall not be ignored."); - - count = 0; - let normalMsgIds = [ "0000", "03E7", "1108", "1901" ]; - normalMsgIds.forEach(aMessageId => { - worker.onRILMessage( - 0, - newIncomingParcel( - -1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(buildPdu(aMessageId)))); - }); - equal(count, 0, "Normal messages shall be ignored."); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js deleted file mode 100644 index b08b64135..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_gsm.js +++ /dev/null @@ -1,230 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_ril_worker_GsmPDUHelper_readCbDataCodingScheme() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - function test_dcs(dcs, encoding, language, hasLanguageIndicator, messageClass) { - context.Buf.readUint8 = function() { - return dcs; - }; - - let msg = {}; - context.GsmPDUHelper.readCbDataCodingScheme(msg); - - equal(msg.dcs, dcs); - equal(msg.encoding, encoding); - equal(msg.language, language); - equal(msg.hasLanguageIndicator, hasLanguageIndicator); - equal(msg.messageClass, messageClass); - } - - function test_dcs_throws(dcs) { - context.Buf.readUint8 = function() { - return dcs; - }; - - throws(function() { - context.GsmPDUHelper.readCbDataCodingScheme({}); - }, "Unsupported CBS data coding scheme: " + dcs); - } - - // Group 0000 - for (let i = 0; i < 16; i++) { - test_dcs(i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, CB_DCS_LANG_GROUP_1[i], - false, GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - - // Group 0001 - // 0000 GSM 7 bit default alphabet; message preceded by language indication. - test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, true, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - // 0001 UCS2; message preceded by language indication. - test_dcs(0x11, PDU_DCS_MSG_CODING_16BITS_ALPHABET, null, true, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - - // Group 0010 - // 0000..0100 - for (let i = 0; i < 5; i++) { - test_dcs(0x20 + i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - CB_DCS_LANG_GROUP_2[i], false, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - // 0101..1111 Reserved - for (let i = 5; i < 16; i++) { - test_dcs(0x20 + i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, false, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - - // Group 0100, 0101, 1001 - for (let group of [0x40, 0x50, 0x90]) { - for (let i = 0; i < 16; i++) { - let encoding = i & 0x0C; - if (encoding == 0x0C) { - encoding = PDU_DCS_MSG_CODING_7BITS_ALPHABET; - } - let messageClass = GECKO_SMS_MESSAGE_CLASSES[i & PDU_DCS_MSG_CLASS_BITS]; - test_dcs(group + i, encoding, null, false, messageClass); - } - } - - // Group 1111 - for (let i = 0; i < 16; i ++) { - let encoding = i & 0x04 ? PDU_DCS_MSG_CODING_8BITS_ALPHABET - : PDU_DCS_MSG_CODING_7BITS_ALPHABET; - let messageClass; - switch(i & PDU_DCS_MSG_CLASS_BITS) { - case 0x01: messageClass = PDU_DCS_MSG_CLASS_USER_1; break; - case 0x02: messageClass = PDU_DCS_MSG_CLASS_USER_2; break; - case 0x03: messageClass = PDU_DCS_MSG_CLASS_3; break; - default: messageClass = PDU_DCS_MSG_CLASS_NORMAL; break; - } - test_dcs(0xF0 + i, encoding, null, false, - GECKO_SMS_MESSAGE_CLASSES[messageClass]); - } - - // Group 0011, 1000, 1010, 1011, 1100 - // 0000..1111 Reserved - for (let group of [0x30, 0x80, 0xA0, 0xB0, 0xC0]) { - for (let i = 0; i < 16; i++) { - test_dcs(group + i, PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, false, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - } - } - - // Group 0110, 0111, 1101, 1110 - // TODO: unsupported - for (let group of [0x60, 0x70, 0xD0, 0xE0]) { - for (let i = 0; i < 16; i++) { - test_dcs_throws(group + i); - } - } - - run_next_test(); -}); - -add_test(function test_ril_worker_GsmPDUHelper_readGsmCbData() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - function test_data(options, expected) { - let readIndex = 0; - context.Buf.readUint8 = function() { - return options[3][readIndex++]; - }; - context.Buf.readUint8Array = function(length) { - let array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = this.readUint8(); - } - return array; - }; - - let msg = { - encoding: options[0], - language: options[1], - hasLanguageIndicator: options[2] - }; - context.GsmPDUHelper.readGsmCbData(msg, options[3].length); - - equal(msg.body, expected[0]); - equal(msg.data == null, expected[1] == null); - if (expected[1] != null) { - equal(msg.data.length, expected[1].length); - for (let i = 0; i < expected[1].length; i++) { - equal(msg.data[i], expected[1][i]); - } - } - equal(msg.language, expected[2]); - } - - // We're testing Cell Broadcast message body with all zeros octet stream. As - // shown in 3GPP TS 23.038, septet 0x00 will be decoded as '@' when both - // langTableIndex and langShiftTableIndex equal to - // PDU_DCS_MSG_CODING_7BITS_ALPHABET. - - // PDU_DCS_MSG_CODING_7BITS_ALPHABET - test_data([PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, false, - [0]], - ["@", null, null]); - test_data([PDU_DCS_MSG_CODING_7BITS_ALPHABET, null, true, - [0, 0, 0, 0]], - ["@", null, "@@"]); - test_data([PDU_DCS_MSG_CODING_7BITS_ALPHABET, "@@", false, - [0]], - ["@", null, "@@"]); - - // PDU_DCS_MSG_CODING_8BITS_ALPHABET - test_data([PDU_DCS_MSG_CODING_8BITS_ALPHABET, null, false, - [0]], - [null, [0], null]); - - // PDU_DCS_MSG_CODING_16BITS_ALPHABET - test_data([PDU_DCS_MSG_CODING_16BITS_ALPHABET, null, false, - [0x00, 0x40]], - ["@", null, null]); - test_data([PDU_DCS_MSG_CODING_16BITS_ALPHABET, null, true, - [0x00, 0x00, 0x00, 0x40]], - ["@", null, "@@"]); - test_data([PDU_DCS_MSG_CODING_16BITS_ALPHABET, "@@", false, - [0x00, 0x40]], - ["@", null, "@@"]); - - run_next_test(); -}); - -add_test(function test_ril_worker_Sim_Download_Message() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - ok(message.rilMessageType !== "cellbroadcast-received", - "Data-Download message shall be ignored."); - } - }); - - function buildPdu(aMessageId) { - return "C002" + aMessageId + "011154741914AFA7C76B9058" + - "FEBEBB41E6371EA4AEB7E173D0DB5E96" + - "83E8E832881DD6E741E4F7B9D168341A" + - "8D46A3D168341A8D46A3D168341A8D46" + - "A3D168341A8D46A3D168341A8D46A3D1" + - "68341A8D46A3D100"; - } - - ["1000", "107F", "1080", "10FF"].forEach(aMessageId => { - worker.onRILMessage( - 0, - newIncomingParcel( - -1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(buildPdu(aMessageId)))); - }); - - ok(true, "All Data-Download Messages are ingored."); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js b/dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js deleted file mode 100644 index 0380c4122..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cellbroadcast_umts.js +++ /dev/null @@ -1,105 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -function buildHexStr(aNum, aNumSemiOctets) { - let str = aNum.toString(16); - while (str.length < aNumSemiOctets) { - str = "0" + str; - } - return str; -} - -/** - * Verify GsmPDUHelper#readUmtsCbMessage with numOfPages from 1 to 15. - */ -add_test(function test_GsmPDUHelper_readUmtsCbMessage_MultiParts() { - let CB_UMTS_MESSAGE_PAGE_SIZE = 82; - let CB_MAX_CONTENT_PER_PAGE_7BIT = 93; - let workerHelper = newInterceptWorker(), - worker = workerHelper.worker, - context = worker.ContextPool._contexts[0], - GsmPDUHelper = context.GsmPDUHelper; - - function test_MultiParts(aNumOfPages) { - let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type - + buildHexStr(0, 4) // skip msg_id - + buildHexStr(0, 4) // skip SN - + buildHexStr(0, 2) // skip dcs - + buildHexStr(aNumOfPages, 2); // set num_of_pages - for (let i = 1; i <= aNumOfPages; i++) { - pdu = pdu + buildHexStr(0, CB_UMTS_MESSAGE_PAGE_SIZE * 2) - + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length - } - - worker.onRILMessage(0, newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(pdu))); - - let postedMessage = workerHelper.postedMessage; - equal("cellbroadcast-received", postedMessage.rilMessageType); - equal(postedMessage.fullBody.length, - aNumOfPages * CB_MAX_CONTENT_PER_PAGE_7BIT); - } - - [1, 5, 15].forEach(function(i) { - test_MultiParts(i); - }); - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper#readUmtsCbMessage with 8bit encoded. - */ -add_test(function test_GsmPDUHelper_readUmtsCbMessage_Binary() { - let CB_UMTS_MESSAGE_PAGE_SIZE = 82; - let CB_MAX_CONTENT_PER_PAGE_7BIT = 93; - let TEXT_BINARY = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFF"; - let workerHelper = newInterceptWorker(), - worker = workerHelper.worker, - context = worker.ContextPool._contexts[0], - GsmPDUHelper = context.GsmPDUHelper; - - function test_MultiPartsBinary(aNumOfPages) { - let pdu = buildHexStr(CB_UMTS_MESSAGE_TYPE_CBS, 2) // msg_type - + buildHexStr(0, 4) // skip msg_id - + buildHexStr(0, 4) // skip SN - + buildHexStr(68, 2) // set DCS to 8bit data - + buildHexStr(aNumOfPages, 2); // set num_of_pages - for (let i = 1; i <= aNumOfPages; i++) { - pdu = pdu + TEXT_BINARY - + buildHexStr(CB_UMTS_MESSAGE_PAGE_SIZE, 2); // msg_info_length - } - - worker.onRILMessage(0, newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_BROADCAST_SMS, - hexStringToParcelByteArrayData(pdu))); - - let postedMessage = workerHelper.postedMessage; - equal("cellbroadcast-received", postedMessage.rilMessageType); - equal(postedMessage.fullData.length, - aNumOfPages * CB_UMTS_MESSAGE_PAGE_SIZE); - for (let i = 0; i < postedMessage.fullData.length; i++) { - equal(postedMessage.fullData[i], 255); - } - } - - [1, 5, 15].forEach(function(i) { - test_MultiPartsBinary(i); - }); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cf.js b/dom/system/gonk/tests/test_ril_worker_cf.js deleted file mode 100644 index b8db716b7..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cf.js +++ /dev/null @@ -1,126 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -function toaFromString(number) { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - return context.RIL._toaFromString(number); -} - -add_test(function test_toaFromString_empty() { - let retval = toaFromString(""); - - equal(retval, TOA_UNKNOWN); - - run_next_test(); -}); - -add_test(function test_toaFromString_undefined() { - let retval = toaFromString(); - - equal(retval, TOA_UNKNOWN); - - run_next_test(); -}); - -add_test(function test_toaFromString_unknown() { - let retval = toaFromString("666222333"); - - equal(retval, TOA_UNKNOWN); - - run_next_test(); -}); - -add_test(function test_toaFromString_international() { - let retval = toaFromString("+34666222333"); - - equal(retval, TOA_INTERNATIONAL); - - run_next_test(); -}); - -add_test(function test_setCallForward_unconditional() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallForward = function fakeSetCallForward(options) { - context.RIL[REQUEST_SET_CALL_FORWARD](0, {}); - }; - - context.RIL.setCallForward({ - action: CALL_FORWARD_ACTION_REGISTRATION, - reason: CALL_FORWARD_REASON_UNCONDITIONAL, - serviceClass: ICC_SERVICE_CLASS_VOICE, - number: "666222333", - timeSeconds: 10 - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_queryCallForwardStatus_unconditional() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallForward = function fakeSetCallForward(options) { - context.RIL[REQUEST_SET_CALL_FORWARD](0, {}); - }; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.Buf.readString = function fakeReadString() { - return "+34666222333"; - }; - - context.RIL.queryCallForwardStatus = function fakeQueryCallForward(options) { - context.Buf.int32Array = [ - 0, // rules.timeSeconds - 145, // rules.toa - 49, // rules.serviceClass - CALL_FORWARD_REASON_UNCONDITIONAL, // rules.reason - 1, // rules.active - 1 // rulesLength - ]; - context.RIL[REQUEST_QUERY_CALL_FORWARD_STATUS](1, {}); - }; - - context.RIL.queryCallForwardStatus({ - action: CALL_FORWARD_ACTION_QUERY_STATUS, - reason: CALL_FORWARD_REASON_UNCONDITIONAL, - serviceClass: ICC_SERVICE_CLASS_VOICE, - number: "666222333", - timeSeconds: 10 - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - ok(Array.isArray(postedMessage.rules)); - do_print(postedMessage.rules.length); - equal(postedMessage.rules.length, 1); - ok(postedMessage.rules[0].active); - equal(postedMessage.rules[0].reason, CALL_FORWARD_REASON_UNCONDITIONAL); - equal(postedMessage.rules[0].number, "+34666222333"); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_clip.js b/dom/system/gonk/tests/test_ril_worker_clip.js deleted file mode 100644 index d1ce5f617..000000000 --- a/dom/system/gonk/tests/test_ril_worker_clip.js +++ /dev/null @@ -1,59 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_queryCLIP_provisioned() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCLIP = function fakeQueryCLIP(options) { - context.Buf.int32Array = [ - 1, // CLIP provisioned. - 1 // Length. - ]; - context.RIL[REQUEST_QUERY_CLIP](1, {}); - }; - - context.RIL.queryCLIP({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.provisioned, 1); - run_next_test(); -}); - -add_test(function test_getCLIP_error_generic_failure_invalid_length() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCLIP = function fakeQueryCLIP(options) { - context.Buf.int32Array = [ - 1, // CLIP provisioned. - 0 // Length. - ]; - context.RIL[REQUEST_QUERY_CLIP](1, {}); - }; - - context.RIL.queryCLIP({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_clir.js b/dom/system/gonk/tests/test_ril_worker_clir.js deleted file mode 100644 index 5882a3c4c..000000000 --- a/dom/system/gonk/tests/test_ril_worker_clir.js +++ /dev/null @@ -1,122 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -// Calling line identification restriction constants. - -// Uses subscription default value. -const CLIR_DEFAULT = 0; -// Restricts CLI presentation. -const CLIR_INVOCATION = 1; -// Allows CLI presentation. -const CLIR_SUPPRESSION = 2; - -function run_test() { - run_next_test(); -} - -add_test(function test_setCLIR_success() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCLIR = function fakeSetCLIR(options) { - context.RIL[REQUEST_SET_CLIR](0, { - rilMessageType: "setCLIR" - }); - }; - - context.RIL.setCLIR({ - clirMode: CLIR_DEFAULT - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_setCLIR_generic_failure() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCLIR = function fakeSetCLIR(options) { - context.RIL[REQUEST_SET_CLIR](0, { - rilMessageType: "setCLIR", - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.setCLIR({ - clirMode: CLIR_DEFAULT - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - - run_next_test(); -}); - -add_test(function test_getCLIR_n0_m1() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.getCLIR = function fakeGetCLIR(options) { - context.Buf.int32Array = [ - 1, // Presentation indicator is used according to the subscription - // of the CLIR service. - 0, // CLIR provisioned in permanent mode. - 2 // Length. - ]; - context.RIL[REQUEST_GET_CLIR](1, { - rilMessageType: "setCLIR" - }); - }; - - context.RIL.getCLIR({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.n, 0); - equal(postedMessage.m, 1); - run_next_test(); -}); - -add_test(function test_getCLIR_error_generic_failure_invalid_length() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.getCLIR = function fakeGetCLIR(options) { - context.Buf.int32Array = [ - 1, // Presentation indicator is used according to the subscription - // of the CLIR service. - 0, // CLIR provisioned in permanent mode. - 0 // Length (invalid one). - ]; - context.RIL[REQUEST_GET_CLIR](1, { - rilMessageType: "setCLIR" - }); - }; - - context.RIL.getCLIR({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_cw.js b/dom/system/gonk/tests/test_ril_worker_cw.js deleted file mode 100644 index efa8b5c21..000000000 --- a/dom/system/gonk/tests/test_ril_worker_cw.js +++ /dev/null @@ -1,104 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_setCallWaiting_success() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallWaiting = function fakeSetCallWaiting(options) { - context.RIL[REQUEST_SET_CALL_WAITING](0, {}); - }; - - context.RIL.setCallWaiting({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_setCallWaiting_generic_failure() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setCallWaiting = function fakeSetCallWaiting(options) { - context.RIL[REQUEST_SET_CALL_WAITING](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.setCallWaiting({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - - run_next_test(); -}); - -add_test(function test_queryCallWaiting_success_enabled_true() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) { - context.Buf.int32Array = [ - 1, // serviceClass - 1, // enabled - 2 // length - ]; - context.RIL[REQUEST_QUERY_CALL_WAITING](1, {}); - }; - - context.RIL.queryCallWaiting({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.serviceClass, 1); - run_next_test(); -}); - -add_test(function test_queryCallWaiting_success_enabled_false() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32 = function fakeReadUint32() { - return context.Buf.int32Array.pop(); - }; - - context.RIL.queryCallWaiting = function fakeQueryCallWaiting(options) { - context.Buf.int32Array = [ - 1, // serviceClass - 0, // enabled - 2 // length - ]; - context.RIL[REQUEST_QUERY_CALL_WAITING](1, {}); - }; - - context.RIL.queryCallWaiting({}); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - equal(postedMessage.serviceClass, ICC_SERVICE_CLASS_NONE); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_ecm.js b/dom/system/gonk/tests/test_ril_worker_ecm.js deleted file mode 100644 index d10cba9ec..000000000 --- a/dom/system/gonk/tests/test_ril_worker_ecm.js +++ /dev/null @@ -1,168 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -var timeoutCallback = null; -var timeoutDelayMs = 0; -const TIMER_ID = 1234; -const TIMEOUT_VALUE = 300000; // 5 mins. - -// No window in xpcshell-test. Create our own timer mechanism. - -function setTimeout(callback, timeoutMs) { - timeoutCallback = callback; - timeoutDelayMs = timeoutMs; - equal(timeoutMs, TIMEOUT_VALUE); - return TIMER_ID; -} - -function clearTimeout(timeoutId) { - equal(timeoutId, TIMER_ID); - timeoutCallback = null; -} - -function fireTimeout() { - notEqual(timeoutCallback, null); - if (timeoutCallback) { - timeoutCallback(); - timeoutCallback = null; - } -} - -add_test(function test_enter_emergencyCbMode() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - // Do it twice. Should always send the event. - for (let i = 0; i < 2; ++i) { - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - let postedMessage = workerHelper.postedMessage; - - // Should store the mode. - equal(context.RIL._isInEmergencyCbMode, true); - - // Should notify change. - equal(postedMessage.rilMessageType, "emergencyCbModeChange"); - equal(postedMessage.active, true); - equal(postedMessage.timeoutMs, TIMEOUT_VALUE); - - // Should start timer. - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - } - - run_next_test(); -}); - -add_test(function test_exit_emergencyCbMode() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - context.RIL[UNSOLICITED_EXIT_EMERGENCY_CALLBACK_MODE](); - let postedMessage = workerHelper.postedMessage; - - // Should store the mode. - equal(context.RIL._isInEmergencyCbMode, false); - - // Should notify change. - equal(postedMessage.rilMessageType, "emergencyCbModeChange"); - equal(postedMessage.active, false); - - // Should clear timer. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - run_next_test(); -}); - -add_test(function test_request_exit_emergencyCbMode_when_timeout() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - equal(context.RIL._isInEmergencyCbMode, true); - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - - let parcelTypes = []; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - }; - - // Timeout. - fireTimeout(); - - // Should clear timeout event. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE. - notEqual(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1); - - run_next_test(); -}); - -add_test(function test_request_exit_emergencyCbMode_when_dial() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - equal(context.RIL._isInEmergencyCbMode, true); - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - - let parcelTypes = []; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - }; - - // Dial non-emergency call. - context.RIL.dial({number: "0912345678", - isEmergency: false, - isDialEmergency: false}); - - // Should clear timeout event. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE. - notEqual(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1); - - run_next_test(); -}); - -add_test(function test_request_exit_emergencyCbMode_explicitly() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL[UNSOLICITED_ENTER_EMERGENCY_CALLBACK_MODE](); - equal(context.RIL._isInEmergencyCbMode, true); - equal(context.RIL._exitEmergencyCbModeTimeoutID, TIMER_ID); - - let parcelTypes = []; - context.Buf.newParcel = function(type, options) { - parcelTypes.push(type); - }; - - context.RIL.handleChromeMessage({rilMessageType: "exitEmergencyCbMode"}); - context.RIL[REQUEST_EXIT_EMERGENCY_CALLBACK_MODE](1, { - rilMessageType: "exitEmergencyCbMode" - }); - let postedMessage = workerHelper.postedMessage; - - // Should clear timeout event. - equal(context.RIL._exitEmergencyCbModeTimeoutID, null); - - // Check indeed sent out REQUEST_EXIT_EMERGENCY_CALLBACK_MODE. - notEqual(parcelTypes.indexOf(REQUEST_EXIT_EMERGENCY_CALLBACK_MODE), -1); - - // Send back the response. - equal(postedMessage.rilMessageType, "exitEmergencyCbMode"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js deleted file mode 100644 index 89fcd874d..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_BerTlvHelper.js +++ /dev/null @@ -1,87 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -// Test ICC_COMMAND_GET_RESPONSE with FCP template format. -/** - * Verify transparent structure with FCP template format. - */ -add_test(function test_fcp_template_for_transparent_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - - let tag_test = [ - 0x62, - 0x22, - 0x82, 0x02, 0x41, 0x21, - 0x83, 0x02, 0x2F, 0xE2, - 0xA5, 0x09, 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, - 0x8A, 0x01, 0x05, - 0x8B, 0x03, 0x2F, 0x06, 0x0B, - 0x80, 0x02, 0x00, 0x0A, - 0x88, 0x01, 0x10]; - - for (let i = 0; i < tag_test.length; i++) { - pduHelper.writeHexOctet(tag_test[i]); - } - - let berTlv = berHelper.decode(tag_test.length); - let iter = berTlv.value.values(); - let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter); - equal(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_STRUCTURE_TRANSPARENT]); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); - equal(tlv.value.fileId, 0x2FE2); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); - equal(tlv.value.fileSizeData, 0x0A); - - run_next_test(); -}); - -/** - * Verify linear fixed structure with FCP template format. - */ -add_test(function test_fcp_template_for_linear_fixed_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - - let tag_test = [ - 0x62, - 0x1E, - 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, - 0x83, 0x02, 0x6F, 0x40, - 0xA5, 0x03, 0x92, 0x01, 0x00, - 0x8A, 0x01, 0x07, - 0x8B, 0x03, 0x6F, 0x06, 0x02, - 0x80, 0x02, 0x00, 0x1A, - 0x88, 0x00]; - - for (let i = 0; i < tag_test.length; i++) { - pduHelper.writeHexOctet(tag_test[i]); - } - - let berTlv = berHelper.decode(tag_test.length); - let iter = berTlv.value.values(); - let tlv = berHelper.searchForNextTag(BER_FCP_FILE_DESCRIPTOR_TAG, iter); - equal(tlv.value.fileStructure, UICC_EF_STRUCTURE[EF_STRUCTURE_LINEAR_FIXED]); - equal(tlv.value.recordLength, 0x1A); - equal(tlv.value.numOfRecords, 0x01); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_IDENTIFIER_TAG, iter); - equal(tlv.value.fileId, 0x6F40); - - tlv = berHelper.searchForNextTag(BER_FCP_FILE_SIZE_DATA_TAG, iter); - equal(tlv.value.fileSizeData, 0x1A); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js b/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js deleted file mode 100644 index dc7eb93b9..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_CardLock.js +++ /dev/null @@ -1,282 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify RIL.iccGetCardLockEnabled - */ -add_test(function test_icc_get_card_lock_enabled() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let ril = context.RIL; - ril.aid = "123456789"; - - function do_test(aLock) { - const serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), REQUEST_QUERY_FACILITY_LOCK) - - // Token : we don't care. - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 4); - equal(parcel[0], GECKO_CARDLOCK_TO_FACILITY[aLock]); - equal(parcel[1], ""); - equal(parcel[2], serviceClass.toString()); - equal(parcel[3], ril.aid); - }; - - ril.iccGetCardLockEnabled({lockType: aLock}); - } - - do_test(GECKO_CARDLOCK_PIN) - do_test(GECKO_CARDLOCK_FDN) - - run_next_test(); -}); - -add_test(function test_path_id_for_spid_and_spn() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - }}); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCFileHelper = context.ICCFileHelper; - - // Test SIM - RIL.appType = CARD_APPTYPE_SIM; - equal(ICCFileHelper.getEFPath(ICC_EF_SPDI), - EF_PATH_MF_SIM + EF_PATH_DF_GSM); - equal(ICCFileHelper.getEFPath(ICC_EF_SPN), - EF_PATH_MF_SIM + EF_PATH_DF_GSM); - - // Test USIM - RIL.appType = CARD_APPTYPE_USIM; - equal(ICCFileHelper.getEFPath(ICC_EF_SPDI), - EF_PATH_MF_SIM + EF_PATH_ADF_USIM); - equal(ICCFileHelper.getEFPath(ICC_EF_SPDI), - EF_PATH_MF_SIM + EF_PATH_ADF_USIM); - run_next_test(); -}); - -/** - * Verify RIL.iccSetCardLockEnabled - */ -add_test(function test_icc_set_card_lock_enabled() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let ril = context.RIL; - ril.aid = "123456789"; - - function do_test(aLock, aPassword, aEnabled) { - const serviceClass = ICC_SERVICE_CLASS_VOICE | - ICC_SERVICE_CLASS_DATA | - ICC_SERVICE_CLASS_FAX; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), REQUEST_SET_FACILITY_LOCK); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 5); - equal(parcel[0], GECKO_CARDLOCK_TO_FACILITY[aLock]); - equal(parcel[1], aEnabled ? "1" : "0"); - equal(parcel[2], aPassword); - equal(parcel[3], serviceClass.toString()); - equal(parcel[4], ril.aid); - }; - - ril.iccSetCardLockEnabled({ - lockType: aLock, - enabled: aEnabled, - password: aPassword}); - } - - do_test(GECKO_CARDLOCK_PIN, "1234", true); - do_test(GECKO_CARDLOCK_PIN, "1234", false); - do_test(GECKO_CARDLOCK_FDN, "4321", true); - do_test(GECKO_CARDLOCK_FDN, "4321", false); - - run_next_test(); -}); - -/** - * Verify RIL.iccChangeCardLockPassword - */ -add_test(function test_icc_change_card_lock_password() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let ril = context.RIL; - - - function do_test(aLock, aPassword, aNewPassword) { - let GECKO_CARDLOCK_TO_REQUEST = {}; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN] = REQUEST_CHANGE_SIM_PIN; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN2] = REQUEST_CHANGE_SIM_PIN2; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), GECKO_CARDLOCK_TO_REQUEST[aLock]); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 3); - equal(parcel[0], aPassword); - equal(parcel[1], aNewPassword); - equal(parcel[2], ril.aid); - }; - - ril.iccChangeCardLockPassword({ - lockType: aLock, - password: aPassword, - newPassword: aNewPassword}); - } - - do_test(GECKO_CARDLOCK_PIN, "1234", "4321"); - do_test(GECKO_CARDLOCK_PIN2, "1234", "4321"); - - run_next_test(); -}); - -/** - * Verify RIL.iccUnlockCardLock - PIN - */ -add_test(function test_icc_unlock_card_lock_pin() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - ril.aid = "123456789"; - - function do_test(aLock, aPassword) { - let GECKO_CARDLOCK_TO_REQUEST = {}; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN] = REQUEST_ENTER_SIM_PIN; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PIN2] = REQUEST_ENTER_SIM_PIN2; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), GECKO_CARDLOCK_TO_REQUEST[aLock]); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 2); - equal(parcel[0], aPassword); - equal(parcel[1], ril.aid); - }; - - ril.iccUnlockCardLock({ - lockType: aLock, - password: aPassword - }); - } - - do_test(GECKO_CARDLOCK_PIN, "1234"); - do_test(GECKO_CARDLOCK_PIN2, "1234"); - - run_next_test(); -}); - -/** - * Verify RIL.iccUnlockCardLock - PUK - */ -add_test(function test_icc_unlock_card_lock_puk() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - ril.aid = "123456789"; - - function do_test(aLock, aPassword, aNewPin) { - let GECKO_CARDLOCK_TO_REQUEST = {}; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PUK] = REQUEST_ENTER_SIM_PUK; - GECKO_CARDLOCK_TO_REQUEST[GECKO_CARDLOCK_PUK2] = REQUEST_ENTER_SIM_PUK2; - - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), GECKO_CARDLOCK_TO_REQUEST[aLock]); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 3); - equal(parcel[0], aPassword); - equal(parcel[1], aNewPin); - equal(parcel[2], ril.aid); - }; - - ril.iccUnlockCardLock({ - lockType: aLock, - password: aPassword, - newPin: aNewPin - }); - } - - do_test(GECKO_CARDLOCK_PUK, "12345678", "1234"); - do_test(GECKO_CARDLOCK_PUK2, "12345678", "1234"); - - run_next_test(); -}); - -/** - * Verify RIL.iccUnlockCardLock - Depersonalization - */ -add_test(function test_icc_unlock_card_lock_depersonalization() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - - function do_test(aPassword) { - buf.sendParcel = function fakeSendParcel() { - // Request Type. - equal(this.readInt32(), REQUEST_ENTER_NETWORK_DEPERSONALIZATION_CODE); - - // Token : we don't care - this.readInt32(); - - // Data - let parcel = this.readStringList(); - equal(parcel.length, 1); - equal(parcel[0], aPassword); - }; - - ril.iccUnlockCardLock({ - lockType: GECKO_CARDLOCK_NCK, - password: aPassword - }); - } - - do_test("12345678"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_CardState.js b/dom/system/gonk/tests/test_ril_worker_icc_CardState.js deleted file mode 100644 index 788df5073..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_CardState.js +++ /dev/null @@ -1,210 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_personalization_state() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; - - function testPersonalization(isCdma, cardPersoState, geckoCardState) { - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: (!isCdma) ? 0 : -1, - cdmaSubscriptionAppIndex: (isCdma) ? 0 : -1, - apps: [ - { - app_state: CARD_APPSTATE_SUBSCRIPTION_PERSO, - perso_substate: cardPersoState - }], - }; - - ril._isCdma = isCdma; - ril._processICCStatus(iccStatus); - equal(ril.cardState, geckoCardState); - } - - // Test GSM personalization state. - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK, - Ci.nsIIcc.CARD_STATE_NETWORK_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET, - Ci.nsIIcc.CARD_STATE_NETWORK_SUBSET_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE, - Ci.nsIIcc.CARD_STATE_CORPORATE_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER, - Ci.nsIIcc.CARD_STATE_SERVICE_PROVIDER_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SIM, - Ci.nsIIcc.CARD_STATE_SIM_LOCKED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK_SUBSET_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_CORPORATE_PUK, - Ci.nsIIcc.CARD_STATE_CORPORATE_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK, - Ci.nsIIcc.CARD_STATE_SERVICE_PROVIDER_PUK_REQUIRED); - testPersonalization(false, CARD_PERSOSUBSTATE_SIM_SIM_PUK, - Ci.nsIIcc.CARD_STATE_SIM_PUK_REQUIRED); - - testPersonalization(false, CARD_PERSOSUBSTATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - testPersonalization(false, CARD_PERSOSUBSTATE_IN_PROGRESS, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS); - testPersonalization(false, CARD_PERSOSUBSTATE_READY, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_READY); - - // Test CDMA personalization state. - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1, - Ci.nsIIcc.CARD_STATE_NETWORK1_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2, - Ci.nsIIcc.CARD_STATE_NETWORK2_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD, - Ci.nsIIcc.CARD_STATE_HRPD_NETWORK_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE, - Ci.nsIIcc.CARD_STATE_RUIM_CORPORATE_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER, - Ci.nsIIcc.CARD_STATE_RUIM_SERVICE_PROVIDER_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM, - Ci.nsIIcc.CARD_STATE_RUIM_LOCKED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK1_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK1_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_NETWORK2_PUK, - Ci.nsIIcc.CARD_STATE_NETWORK2_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_HRPD_PUK, - Ci.nsIIcc.CARD_STATE_HRPD_NETWORK_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_CORPORATE_PUK, - Ci.nsIIcc.CARD_STATE_RUIM_CORPORATE_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK, - Ci.nsIIcc.CARD_STATE_RUIM_SERVICE_PROVIDER_PUK_REQUIRED); - testPersonalization(true, CARD_PERSOSUBSTATE_RUIM_RUIM_PUK, - Ci.nsIIcc.CARD_STATE_RUIM_PUK_REQUIRED); - - testPersonalization(true, CARD_PERSOSUBSTATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - testPersonalization(true, CARD_PERSOSUBSTATE_IN_PROGRESS, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_IN_PROGRESS); - testPersonalization(true, CARD_PERSOSUBSTATE_READY, - Ci.nsIIcc.CARD_STATE_PERSONALIZATION_READY); - - run_next_test(); -}); - -/** - * Verify SIM app_state in _processICCStatus - */ -add_test(function test_card_app_state() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; - - function testCardAppState(cardAppState, geckoCardState) { - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: 0, - apps: [ - { - app_state: cardAppState - }], - }; - - ril._processICCStatus(iccStatus); - equal(ril.cardState, geckoCardState); - } - - testCardAppState(CARD_APPSTATE_ILLEGAL, - Ci.nsIIcc.CARD_STATE_ILLEGAL); - testCardAppState(CARD_APPSTATE_PIN, - Ci.nsIIcc.CARD_STATE_PIN_REQUIRED); - testCardAppState(CARD_APPSTATE_PUK, - Ci.nsIIcc.CARD_STATE_PUK_REQUIRED); - testCardAppState(CARD_APPSTATE_READY, - Ci.nsIIcc.CARD_STATE_READY); - testCardAppState(CARD_APPSTATE_UNKNOWN, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - testCardAppState(CARD_APPSTATE_DETECTED, - Ci.nsIIcc.CARD_STATE_UNKNOWN); - - run_next_test(); -}); - -/** - * Verify permanent blocked for ICC. - */ -add_test(function test_icc_permanent_blocked() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() {}; - - function testPermanentBlocked(pin1_replaced, universalPINState, pin1) { - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: 0, - universalPINState: universalPINState, - apps: [ - { - pin1_replaced: pin1_replaced, - pin1: pin1 - }] - }; - - ril._processICCStatus(iccStatus); - equal(ril.cardState, Ci.nsIIcc.CARD_STATE_PERMANENT_BLOCKED); - } - - testPermanentBlocked(1, - CARD_PINSTATE_ENABLED_PERM_BLOCKED, - CARD_PINSTATE_UNKNOWN); - testPermanentBlocked(1, - CARD_PINSTATE_ENABLED_PERM_BLOCKED, - CARD_PINSTATE_ENABLED_PERM_BLOCKED); - testPermanentBlocked(0, - CARD_PINSTATE_UNKNOWN, - CARD_PINSTATE_ENABLED_PERM_BLOCKED); - - run_next_test(); -}); - -/** - * Verify ICC without app index. - */ -add_test(function test_icc_without_app_index() { - const ICCID = "123456789"; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - let iccStatus = { - cardState: CARD_STATE_PRESENT, - gsmUmtsSubscriptionAppIndex: -1, - universalPINState: CARD_PINSTATE_DISABLED, - apps: [ - { - app_state: CARD_APPSTATE_READY - }] - }; - - context.ICCRecordHelper.readICCID = function fakeReadICCID() { - ril.iccInfo.iccid = ICCID; - }; - - ril._processICCStatus(iccStatus); - - // Should read icc id event if the app index is -1. - equal(ril.iccInfo.iccid, ICCID); - // cardState is "unknown" if the app index is -1. - equal(ril.cardState, GECKO_CARDSTATE_UNKNOWN); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js deleted file mode 100644 index 0d074da79..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_GsmPDUHelper.js +++ /dev/null @@ -1,79 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify GsmPDUHelper.writeTimestamp - */ -add_test(function test_write_timestamp() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - - // current date - let dateInput = new Date(); - let dateOutput = new Date(); - helper.writeTimestamp(dateInput); - dateOutput.setTime(helper.readTimestamp()); - - equal(dateInput.getFullYear(), dateOutput.getFullYear()); - equal(dateInput.getMonth(), dateOutput.getMonth()); - equal(dateInput.getDate(), dateOutput.getDate()); - equal(dateInput.getHours(), dateOutput.getHours()); - equal(dateInput.getMinutes(), dateOutput.getMinutes()); - equal(dateInput.getSeconds(), dateOutput.getSeconds()); - equal(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset()); - - // 2034-01-23 12:34:56 -0800 GMT - let time = Date.UTC(2034, 1, 23, 12, 34, 56); - time = time - (8 * 60 * 60 * 1000); - dateInput.setTime(time); - helper.writeTimestamp(dateInput); - dateOutput.setTime(helper.readTimestamp()); - - equal(dateInput.getFullYear(), dateOutput.getFullYear()); - equal(dateInput.getMonth(), dateOutput.getMonth()); - equal(dateInput.getDate(), dateOutput.getDate()); - equal(dateInput.getHours(), dateOutput.getHours()); - equal(dateInput.getMinutes(), dateOutput.getMinutes()); - equal(dateInput.getSeconds(), dateOutput.getSeconds()); - equal(dateInput.getTimezoneOffset(), dateOutput.getTimezoneOffset()); - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper.octectToBCD and GsmPDUHelper.BCDToOctet - */ -add_test(function test_octect_BCD() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - - // 23 - let number = 23; - let octet = helper.BCDToOctet(number); - equal(helper.octetToBCD(octet), number); - - // 56 - number = 56; - octet = helper.BCDToOctet(number); - equal(helper.octetToBCD(octet), number); - - // 0x23 - octet = 0x23; - number = helper.octetToBCD(octet); - equal(helper.BCDToOctet(number), octet); - - // 0x56 - octet = 0x56; - number = helper.octetToBCD(octet); - equal(helper.BCDToOctet(number), octet); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js deleted file mode 100644 index 29b83b76a..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCContactHelper.js +++ /dev/null @@ -1,1042 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Test error message returned in onerror for readICCContacts. - */ -add_test(function test_error_message_read_icc_contact () { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - function do_test(options, expectedErrorMsg) { - ril.sendChromeMessage = function(message) { - equal(message.errorMsg, expectedErrorMsg); - } - ril.readICCContacts(options); - } - - // Error 1, didn't specify correct contactType. - do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); - - // Error 2, specifying a non-supported contactType. - ril.appType = CARD_APPTYPE_USIM; - do_test({contactType: "foo"}, CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - - // Error 3, suppose we update the supported PBR fields in USIM_PBR_FIELDS, - // but forget to add implemenetations for it. - USIM_PBR_FIELDS.push("pbc"); - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN}, - CONTACT_ERR_FIELD_NOT_SUPPORTED); - - run_next_test(); -}); - -/** - * Test error message returned in onerror for updateICCContact. - */ -add_test(function test_error_message_update_icc_contact() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - - const ICCID = "123456789"; - ril.iccInfo.iccid = ICCID; - - function do_test(options, expectedErrorMsg) { - ril.sendChromeMessage = function(message) { - equal(message.errorMsg, expectedErrorMsg); - } - ril.updateICCContact(options); - } - - // Error 1, didn't specify correct contactType. - do_test({}, CONTACT_ERR_REQUEST_NOT_SUPPORTED); - - // Error 2, specifying a correct contactType, but without providing 'contact'. - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN}, - CONTACT_ERR_REQUEST_NOT_SUPPORTED); - - // Error 3, specifying a non-supported contactType. - ril.appType = CARD_APPTYPE_USIM; - do_test({contactType: GECKO_CARDCONTACT_TYPE_SDN, contact: {}}, - CONTACT_ERR_CONTACT_TYPE_NOT_SUPPORTED); - - // Error 4, without supplying pin2. - do_test({contactType: GECKO_CARDCONTACT_TYPE_FDN, - contact: {contactId: ICCID + "1"}}, - GECKO_ERROR_SIM_PIN2); - - // Error 5, No free record found in EF_ADN. - let record = context.ICCRecordHelper; - record.readPBR = function(onsuccess, onerror) { - onsuccess([{adn: {fileId: 0x4f3a}}]); - }; - - let io = context.ICCIOHelper; - io.loadLinearFixedEF = function(options) { - options.totalRecords = 1; - options.p1 = 1; - options.callback(options); - }; - - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, contact: {}}, - CONTACT_ERR_NO_FREE_RECORD_FOUND); - - // Error 6, ICC IO Error. - io.loadLinearFixedEF = function(options) { - ril[REQUEST_SIM_IO](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, - contact: {contactId: ICCID + "1"}}, - GECKO_ERROR_GENERIC_FAILURE); - - // Error 7, suppose we update the supported PBR fields in USIM_PBR_FIELDS, - // but forget to add implemenetations for it. - USIM_PBR_FIELDS.push("pbc"); - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, - contact: {contactId: ICCID + "1"}}, - CONTACT_ERR_FIELD_NOT_SUPPORTED); - - // Error 8, EF_PBR doesn't exist. - record.readPBR = function(onsuccess, onerror) { - onsuccess([]); - }; - - do_test({contactType: GECKO_CARDCONTACT_TYPE_ADN, - contact: {contactId: ICCID + "1"}}, - CONTACT_ERR_CANNOT_ACCESS_PHONEBOOK); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.readICCContacts - */ -add_test(function test_read_icc_contacts() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - let ril = context.RIL; - let test_data = [ - //Record 1. - { - comment: "Test read SIM adn contact", - rawData: { - simType: CARD_APPTYPE_SIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 2. - { - comment: "Test read SIM fdn contact", - rawData: { - simType: CARD_APPTYPE_SIM, - contactType: GECKO_CARDCONTACT_TYPE_FDN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 3. - { - comment: "Test read USIM adn contact", - rawData: { - simType: CARD_APPTYPE_USIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - email: "hello@mail.com", - anr: "123456", - }, - expectedContact: [{ - pbrIndex: 0, - recordId: 1, - alphaId: "name", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }], - }, - //Record 4. - { - comment: "Test read USIM adn contacts", - rawData: { - simType: CARD_APPTYPE_USIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}, - {adn:{fileId: 0x6f3b}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name1", number: "111111"}, - {recordId: 2, alphaId: "name2", number: "222222"}], - email: "hello@mail.com", - anr: "123456", - }, - expectedContact: [ - { - pbrIndex: 0, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 0, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - } - ], - }, - //Record 5. - { - comment: "Test read USIM fdn contact", - rawData: { - simType: CARD_APPTYPE_USIM, - contactType: GECKO_CARDCONTACT_TYPE_FDN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 6. - { - comment: "Test read RUIM adn contact", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 7. - { - comment: "Test read RUIM fdn contact", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_FDN, - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - }, - expectedContact: [{ - recordId: 1, - alphaId: "name", - number: "111111" - }], - }, - //Record 8. - { - comment: "Test read RUIM adn contact with enhanced phone book", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name", number: "111111"}], - email: "hello@mail.com", - anr: "123456", - enhancedPhoneBook: true, - }, - expectedContact: [{ - pbrIndex: 0, - recordId: 1, - alphaId: "name", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }], - }, - //Record 9. - { - comment: "Test read RUIM adn contacts with enhanced phone book", - rawData: { - simType: CARD_APPTYPE_RUIM, - contactType: GECKO_CARDCONTACT_TYPE_ADN, - pbrs: [{adn:{fileId: 0x6f3a}, email: {}, anr0: {}}, - {adn:{fileId: 0x6f3b}, email: {}, anr0: {}}], - adnLike: [{recordId: 1, alphaId: "name1", number: "111111"}, - {recordId: 2, alphaId: "name2", number: "222222"}], - email: "hello@mail.com", - anr: "123456", - enhancedPhoneBook: true, - }, - expectedContact: [ - { - pbrIndex: 0, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 0, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 1, - alphaId: "name1", - number: "111111", - email: "hello@mail.com", - anr: ["123456"] - }, { - pbrIndex: 1, - recordId: 2, - alphaId: "name2", - number: "222222", - email: "hello@mail.com", - anr: ["123456"] - } - ], - }, - ]; - - function do_test(aTestData, aExpectedContact) { - ril.appType = aTestData.simType; - ril._isCdma = (aTestData.simType === CARD_APPTYPE_RUIM); - ril.iccInfoPrivate.cst = (aTestData.enhancedPhoneBook) ? - [0x20, 0x0C, 0x0, 0x0, 0x0]: - [0x20, 0x00, 0x0, 0x0, 0x0]; - - ril.iccInfoPrivate.sst = (aTestData.simType === CARD_APPTYPE_SIM)? - [0x20, 0x0, 0x0, 0x0, 0x0]: - [0x2, 0x0, 0x0, 0x0, 0x0]; - - // Override some functions to test. - contactHelper.getContactFieldRecordId = function(pbr, contact, field, onsuccess, onerror) { - onsuccess(1); - }; - - record.readPBR = function readPBR(onsuccess, onerror) { - onsuccess(JSON.parse(JSON.stringify(aTestData.pbrs))); - }; - - record.readADNLike = function readADNLike(fileId, extFileId, onsuccess, onerror) { - onsuccess(JSON.parse(JSON.stringify(aTestData.adnLike))); - }; - - record.readEmail = function readEmail(fileId, fileType, recordNumber, onsuccess, onerror) { - onsuccess(aTestData.email); - }; - - record.readANR = function readANR(fileId, fileType, recordNumber, onsuccess, onerror) { - onsuccess(aTestData.anr); - }; - - let onsuccess = function onsuccess(contacts) { - for (let i = 0; i < contacts.length; i++) { - do_print("check contacts[" + i + "]:" + JSON.stringify(contacts[i])); - deepEqual(contacts[i], aExpectedContact[i]); - } - }; - - let onerror = function onerror(errorMsg) { - do_print("readICCContacts failed: " + errorMsg); - ok(false); - }; - - contactHelper.readICCContacts(aTestData.simType, aTestData.contactType, onsuccess, onerror); - } - - for (let i = 0; i < test_data.length; i++) { - do_print(test_data[i].comment); - do_test(test_data[i].rawData, test_data[i].expectedContact); - } - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM. - */ -add_test(function test_update_icc_contact() { - const ADN_RECORD_ID = 100; - const ADN_SFI = 1; - const IAP_FILE_ID = 0x4f17; - const EMAIL_FILE_ID = 0x4f50; - const EMAIL_RECORD_ID = 20; - const ANR0_FILE_ID = 0x4f11; - const ANR0_RECORD_ID = 30; - const EXT_RECORD_ID = 0x01; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - let ril = context.RIL; - - function do_test(aSimType, aContactType, aContact, aPin2, aFileType, aHaveIapIndex, aEnhancedPhoneBook) { - ril.appType = aSimType; - ril._isCdma = (aSimType === CARD_APPTYPE_RUIM); - ril.iccInfoPrivate.cst = (aEnhancedPhoneBook) ? [0x20, 0x0C, 0x28, 0x0, 0x20] - : [0x20, 0x0, 0x28, 0x0, 0x20]; - ril.iccInfoPrivate.sst = (aSimType === CARD_APPTYPE_SIM)? - [0x20, 0x0, 0x28, 0x0, 0x20]: - [0x16, 0x0, 0x0, 0x0, 0x0]; - - recordHelper.readPBR = function(onsuccess, onerror) { - if (aFileType === ICC_USIM_TYPE1_TAG) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}, - ext1: {fileId: ICC_EF_EXT1} - - }]); - } else if (aFileType === ICC_USIM_TYPE2_TAG) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN, - sfi: ADN_SFI}, - iap: {fileId: IAP_FILE_ID}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 0}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 1}, - ext1: {fileId: ICC_EF_EXT1} - }]); - } - }; - - recordHelper.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - if (aContactType === GECKO_CARDCONTACT_TYPE_FDN) { - equal(fileId, ICC_EF_FDN); - } else if (aContactType === GECKO_CARDCONTACT_TYPE_ADN) { - equal(fileId, ICC_EF_ADN); - } - - if (aContact.number.length > ADN_MAX_NUMBER_DIGITS) { - equal(extRecordNumber, EXT_RECORD_ID); - } else { - equal(extRecordNumber, 0xff); - } - - equal(pin2, aPin2); - equal(contact.alphaId, aContact.alphaId); - equal(contact.number, aContact.number); - onsuccess({alphaId: contact.alphaId, - number: contact.number.substring(0, ADN_MAX_NUMBER_DIGITS)}); - }; - - recordHelper.getADNLikeExtensionRecordNumber = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess(EXT_RECORD_ID); - }; - - recordHelper.updateExtension = function(fileId, recordNumber, number, onsuccess, onerror) { - onsuccess(); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - onsuccess(EXT_RECORD_ID); - }; - - recordHelper.cleanEFRecord = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess(); - } - - recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess((aHaveIapIndex) ? [EMAIL_RECORD_ID, ANR0_RECORD_ID] - : [0xff, 0xff]); - }; - - recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess(); - }; - - recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { - equal(pbr.email.fileId, EMAIL_FILE_ID); - if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) { - equal(recordNumber, ADN_RECORD_ID); - } else if (pbr.email.fileType === ICC_USIM_TYPE2_TAG) { - equal(recordNumber, EMAIL_RECORD_ID); - } - equal(email, aContact.email); - onsuccess(email); - }; - - recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { - equal(pbr.anr0.fileId, ANR0_FILE_ID); - if (pbr.anr0.fileType === ICC_USIM_TYPE1_TAG) { - equal(recordNumber, ADN_RECORD_ID); - } else if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) { - equal(recordNumber, ANR0_RECORD_ID); - } - if (Array.isArray(aContact.anr)) { - equal(number, aContact.anr[0]); - } - onsuccess(number); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - let recordId = 0; - if (fileId === EMAIL_FILE_ID) { - recordId = EMAIL_RECORD_ID; - } else if (fileId === ANR0_FILE_ID) { - recordId = ANR0_RECORD_ID; - } - onsuccess(recordId); - }; - - let isSuccess = false; - let onsuccess = function onsuccess(updatedContact) { - equal(ADN_RECORD_ID, updatedContact.recordId); - equal(aContact.alphaId, updatedContact.alphaId); - equal(aContact.number.substring(0, ADN_MAX_NUMBER_DIGITS + EXT_MAX_NUMBER_DIGITS), - updatedContact.number); - if ((aSimType == CARD_APPTYPE_USIM || aSimType == CARD_APPTYPE_RUIM) && - (aFileType == ICC_USIM_TYPE1_TAG || aFileType == ICC_USIM_TYPE2_TAG)) { - if (aContact.hasOwnProperty('email')) { - equal(aContact.email, updatedContact.email); - } - - if (aContact.hasOwnProperty('anr')) { - equal(aContact.anr[0], updatedContact.anr[0]); - } - } else { - equal(updatedContact.email, null); - equal(updatedContact.anr, null); - } - - do_print("updateICCContact success"); - isSuccess = true; - }; - - let onerror = function onerror(errorMsg) { - do_print("updateICCContact failed: " + errorMsg); - }; - - contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror); - ok(isSuccess); - } - - let contacts = [ - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test", - number: "123456", - email: "test@mail.com", - anr: ["+654321"] - }, - // a contact without email and anr. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test2", - number: "123456", - }, - // a contact with email but no anr. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test3", - number: "123456", - email: "test@mail.com" - }, - // a contact with anr but no email. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test4", - number: "123456", - anr: ["+654321"] - }, - // a contact number over 20 digits. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test4", - number: "0123456789012345678901234567890123456789", - anr: ["+654321"] - }, - // a contact number over 40 digits. - { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test5", - number: "01234567890123456789012345678901234567890123456789", - anr: ["+654321"] - }]; - - for (let i = 0; i < contacts.length; i++) { - let contact = contacts[i]; - // SIM - do_print("Test update SIM adn contacts"); - do_test(CARD_APPTYPE_SIM, GECKO_CARDCONTACT_TYPE_ADN, contact); - - do_print("Test update SIM fdn contacts"); - do_test(CARD_APPTYPE_SIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234"); - - // USIM - do_print("Test update USIM adn contacts"); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE1_TAG); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, true); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, false); - - do_print("Test update USIM fdn contacts"); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234"); - - // RUIM - do_print("Test update RUIM adn contacts"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact); - - do_print("Test update RUIM fdn contacts"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234"); - - // RUIM with enhanced phone book - do_print("Test update RUIM adn contacts with enhanced phone book"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE1_TAG, null,true); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, true, true); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null, - ICC_USIM_TYPE2_TAG, false, true); - - do_print("Test update RUIM fdn contacts with enhanced phone book"); - do_test(CARD_APPTYPE_RUIM, GECKO_CARDCONTACT_TYPE_FDN, contact, "1234", - null, true); - } - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.updateICCContact with appType is CARD_APPTYPE_USIM and - * insufficient space to store Type 2 USIM contact fields. - */ -add_test(function test_update_icc_contact_full_email_and_anr_field() { - const ADN_RECORD_ID = 100; - const ADN_SFI = 1; - const IAP_FILE_ID = 0x4f17; - const EMAIL_FILE_ID = 0x4f50; - const EMAIL_RECORD_ID = 20; - const ANR0_FILE_ID = 0x4f11; - const ANR0_RECORD_ID = 30; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - let ril = context.RIL; - - function do_test(aSimType, aContactType, aContact, aPin2) { - ril.appType = CARD_APPTYPE_USIM; - ril.iccInfoPrivate.sst = [0x2, 0x0, 0x0, 0x0, 0x0]; - - recordHelper.readPBR = function(onsuccess, onerror) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN, - sfi: ADN_SFI}, - iap: {fileId: IAP_FILE_ID}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 0}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 1} - }]); - }; - - recordHelper.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - if (aContactType === GECKO_CARDCONTACT_TYPE_ADN) { - equal(fileId, ICC_EF_ADN); - } - equal(pin2, aPin2); - equal(contact.alphaId, aContact.alphaId); - equal(contact.number, aContact.number); - onsuccess({alphaId: contact.alphaId, - number: contact.number}); - }; - - recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess([0xff, 0xff]); - }; - - recordHelper.updateIAP = function(fileId, recordNumber, iap, onsuccess, onerror) { - equal(fileId, IAP_FILE_ID); - equal(recordNumber, ADN_RECORD_ID); - onsuccess(); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - let recordId = 0; - // emulate email and anr don't have free record. - if (fileId === EMAIL_FILE_ID || fileId === ANR0_FILE_ID) { - onerror(CONTACT_ERR_NO_FREE_RECORD_FOUND); - } else { - onsuccess(recordId); - } - }; - - let isSuccess = false; - let onsuccess = function onsuccess(updatedContact) { - equal(ADN_RECORD_ID, updatedContact.recordId); - equal(aContact.alphaId, updatedContact.alphaId); - equal(updatedContact.email, null); - equal(updatedContact.anr, null); - - do_print("updateICCContact success"); - isSuccess = true; - }; - - let onerror = function onerror(errorMsg) { - do_print("updateICCContact failed: " + errorMsg); - }; - - contactHelper.updateICCContact(aSimType, aContactType, aContact, aPin2, onsuccess, onerror); - ok(isSuccess); - } - - let contact = { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test", - number: "123456", - email: "test@mail.com", - anr: ["+654321"] - }; - - // USIM - do_print("Test update USIM adn contacts"); - do_test(CARD_APPTYPE_USIM, GECKO_CARDCONTACT_TYPE_ADN, contact, null); - - run_next_test(); -}); - -/** - * Verify updateICCContact with removal of anr and email with File Type 1. - */ -add_test(function test_update_icc_contact_with_remove_type1_attr() { - const ADN_RECORD_ID = 100; - const IAP_FILE_ID = 0x4f17; - const EMAIL_FILE_ID = 0x4f50; - const EMAIL_RECORD_ID = 20; - const ANR0_FILE_ID = 0x4f11; - const ANR0_RECORD_ID = 30; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - - recordHelper.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - onsuccess({alphaId: contact.alphaId, - number: contact.number}); - }; - - let contact = { - pbrIndex: 0, - recordId: ADN_RECORD_ID, - alphaId: "test2", - number: "123456", - }; - - recordHelper.readIAP = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess([EMAIL_RECORD_ID, ANR0_RECORD_ID]); - }; - - recordHelper.updateEmail = function(pbr, recordNumber, email, adnRecordId, onsuccess, onerror) { - ok(email == null); - onsuccess(email); - }; - - recordHelper.updateANR = function(pbr, recordNumber, number, adnRecordId, onsuccess, onerror) { - ok(number == null); - onsuccess(number); - }; - - function do_test(type) { - recordHelper.readPBR = function(onsuccess, onerror) { - if (type == ICC_USIM_TYPE1_TAG) { - onsuccess([{ - adn: {fileId: ICC_EF_ADN}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE1_TAG}}]); - } else { - onsuccess([{ - adn: {fileId: ICC_EF_ADN}, - iap: {fileId: IAP_FILE_ID}, - email: {fileId: EMAIL_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 0}, - anr0: {fileId: ANR0_FILE_ID, - fileType: ICC_USIM_TYPE2_TAG, - indexInIAP: 1}}]); - } - }; - - let successCb = function(updatedContact) { - equal(updatedContact.email, null); - equal(updatedContact.anr, null); - ok(true); - }; - - let errorCb = function(errorMsg) { - do_print(errorMsg); - ok(false); - }; - - contactHelper.updateICCContact(CARD_APPTYPE_USIM, - GECKO_CARDCONTACT_TYPE_ADN, - contact, null, successCb, errorCb); - } - - do_test(ICC_USIM_TYPE1_TAG); - do_test(ICC_USIM_TYPE2_TAG); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.findFreeICCContact in SIM - */ -add_test(function test_find_free_icc_contact_sim() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - // Correct record Id starts with 1, so put a null element at index 0. - let records = [null]; - const MAX_RECORDS = 3; - const PBR_INDEX = 0; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - if (records.length > MAX_RECORDS) { - onerror("No free record found."); - return; - } - - onsuccess(records.length); - }; - - let successCb = function(pbrIndex, recordId) { - equal(pbrIndex, PBR_INDEX); - records[recordId] = {}; - }; - - let errorCb = function(errorMsg) { - do_print(errorMsg); - ok(false); - }; - - for (let i = 0; i < MAX_RECORDS; i++) { - contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, - GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - } - // The 1st element, records[0], is null. - equal(records.length - 1, MAX_RECORDS); - - // Now the EF is full, so finding a free one should result failure. - successCb = function(pbrIndex, recordId) { - ok(false); - }; - - errorCb = function(errorMsg) { - ok(errorMsg === "No free record found."); - }; - contactHelper.findFreeICCContact(CARD_APPTYPE_SIM, GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.findFreeICCContact in USIM - */ -add_test(function test_find_free_icc_contact_usim() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let recordHelper = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - const ADN1_FILE_ID = 0x6f3a; - const ADN2_FILE_ID = 0x6f3b; - const MAX_RECORDS = 3; - - // The adn in the first phonebook set has already two records, which means - // only 1 free record remained. - let pbrs = [{adn: {fileId: ADN1_FILE_ID, records: [null, {}, {}]}}, - {adn: {fileId: ADN2_FILE_ID, records: [null]}}]; - - recordHelper.readPBR = function readPBR(onsuccess, onerror) { - onsuccess(pbrs); - }; - - recordHelper.findFreeRecordId = function(fileId, onsuccess, onerror) { - let pbr = (fileId == ADN1_FILE_ID ? pbrs[0]: pbrs[1]); - if (pbr.adn.records.length > MAX_RECORDS) { - onerror("No free record found."); - return; - } - - onsuccess(pbr.adn.records.length); - }; - - let successCb = function(pbrIndex, recordId) { - equal(pbrIndex, 0); - pbrs[pbrIndex].adn.records[recordId] = {}; - }; - - let errorCb = function(errorMsg) { - ok(false); - }; - - contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, - GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - - // Now the EF_ADN in the 1st phonebook set is full, so the next free contact - // will come from the 2nd phonebook set. - successCb = function(pbrIndex, recordId) { - equal(pbrIndex, 1); - equal(recordId, 1); - } - contactHelper.findFreeICCContact(CARD_APPTYPE_USIM, - GECKO_CARDCONTACT_TYPE_ADN, - successCb, errorCb); - - run_next_test(); -}); - -/** - * Verify ICCContactHelper.updateADNLikeWithExtension - */ -add_test(function test_update_adn_like_with_extension() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let record = context.ICCRecordHelper; - let contactHelper = context.ICCContactHelper; - ril.appType = CARD_APPTYPE_SIM; - // Correct record Id starts from 1, so put a null element at index 0. - // ext_records contains data at index 1, and it only has 1 free record at index 2. - let notFree = 0x01; - let ext_records = [null, notFree, null]; - - function do_test(contact, extRecordNumber, expectedExtRecordNumber, expectedNumber, expectedCleanEFRecord) { - // Override some functions to test. - record.getADNLikeExtensionRecordNumber = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess(extRecordNumber); - } - - record.updateADNLike = function(fileId, extRecordNumber, contact, pin2, onsuccess, onerror) { - equal(extRecordNumber, expectedExtRecordNumber); - onsuccess({alphaId: contact.alphaId, - number: contact.number.substring(0, ADN_MAX_NUMBER_DIGITS)}); - } - - record.updateExtension = function(fileId, recordNumber, number, onsuccess, onerror) { - if (recordNumber > ext_records.length) { - onerror("updateExtension failed."); - return; - } - ext_records[recordNumber] = number; - onsuccess(); - } - - record.findFreeRecordId = function(fileId, onsuccess, onerror) { - for (let i = 1; i < ext_records.length; i++) { - if (!ext_records[i]) { - onsuccess(i); - return; - } - } - - onerror("No free record found."); - } - - let isCleanEFRecord = false; - record.cleanEFRecord = function(fileId, recordNumber, onsuccess, onerror) { - if (recordNumber > ext_records.length) { - onerror("cleanEFRecord failed."); - return; - } - ext_records[recordNumber] = null; - isCleanEFRecord = true; - onsuccess(); - } - - let successCb = function successCb(updatedContact) { - equal(updatedContact.number, expectedNumber); - }; - - let errorCb = function errorCb(errorMsg) { - do_print("updateADNLikeWithExtension failed, msg = " + errorMsg); - ok(false); - }; - - contactHelper.updateADNLikeWithExtension(ICC_EF_ADN, ICC_EF_EXT1, contact, null, successCb, errorCb); - - if (expectedCleanEFRecord) { - ok(isCleanEFRecord); - } - } - - // Update extension record with previous extension record number. - do_test({recordId: 1, alphaId: "test", number: "001122334455667788991234"}, 0x01, 0x01, "001122334455667788991234"); - // Update extension record and find a free record. - do_test({recordId: 1, alphaId: "test", number: "001122334455667788995678"}, 0xff, 0x02, "001122334455667788995678"); - // Update extension record with no free extension record. - do_test({recordId: 1, alphaId: "test", number: "001122334455667788994321"}, 0xff, 0xff, "00112233445566778899"); - // Update extension record with clean previous extension record. - do_test({recordId: 1, alphaId: "test", number: "00112233445566778899"}, 0x01, 0xff, "00112233445566778899", true); - // Update extension record with no extension record and previous extension record. - do_test({recordId: 1, alphaId: "test", number: "00112233445566778899"}, 0xff, 0xff, "00112233445566778899"); - - run_next_test(); -}); \ No newline at end of file diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js deleted file mode 100644 index e690b1206..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCIOHelper.js +++ /dev/null @@ -1,173 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCIOHelper.loadLinearFixedEF with recordSize. - */ -add_test(function test_load_linear_fixed_ef() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let io = context.ICCIOHelper; - - io.getResponse = function fakeGetResponse(options) { - // When recordSize is provided, loadLinearFixedEF should call iccIO directly. - ok(false); - run_next_test(); - }; - - ril.iccIO = function fakeIccIO(options) { - ok(true); - run_next_test(); - }; - - io.loadLinearFixedEF({recordSize: 0x20}); -}); - -/** - * Verify ICCIOHelper.loadLinearFixedEF without recordSize. - */ -add_test(function test_load_linear_fixed_ef() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let io = context.ICCIOHelper; - - io.getResponse = function fakeGetResponse(options) { - ok(true); - run_next_test(); - }; - - ril.iccIO = function fakeIccIO(options) { - // When recordSize is not provided, loadLinearFixedEF should call getResponse. - ok(false); - run_next_test(); - }; - - io.loadLinearFixedEF({}); -}); - -/** - * Verify ICC IO Error. - */ -add_test(function test_process_icc_io_error() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - function do_test(sw1, sw2, expectedErrorMsg) { - let called = false; - function errorCb(errorMsg) { - called = true; - equal(errorMsg, expectedErrorMsg); - } - - // Write sw1 and sw2 to buffer. - buf.writeInt32(sw1); - buf.writeInt32(sw2); - - context.RIL[REQUEST_SIM_IO](0, {fileId: 0xffff, - command: 0xff, - onerror: errorCb}); - - // onerror callback should be triggered. - ok(called); - } - - let TEST_DATA = [ - // [sw1, sw2, expectError] - [ICC_STATUS_ERROR_COMMAND_NOT_ALLOWED, 0xff, GECKO_ERROR_GENERIC_FAILURE], - [ICC_STATUS_ERROR_WRONG_PARAMETERS, 0xff, GECKO_ERROR_GENERIC_FAILURE], - ]; - - for (let i = 0; i < TEST_DATA.length; i++) { - do_test.apply(null, TEST_DATA[i]); - } - - run_next_test(); -}); - -/** - * Verify ICCIOHelper.processICCIOGetResponse for EF_TYPE_TRANSPARENT. - */ -add_test(function test_icc_io_get_response_for_transparent_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let iccioHelper = context.ICCIOHelper; - let pduHelper = context.GsmPDUHelper; - - let responseArray = [ - // SIM response. - [0x00, 0x00, 0x00, 0x0A, 0x2F, 0xE2, 0x04, 0x00, 0x0A, 0xA0, 0xAA, 0x00, - 0x02, 0x00, 0x00], - // USIM response. - [0x62, 0x22, 0x82, 0x02, 0x41, 0x21, 0x83, 0x02, 0x2F, 0xE2, 0xA5, 0x09, - 0xC1, 0x04, 0x40, 0x0F, 0xF5, 0x55, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x05, - 0x8B, 0x03, 0x2F, 0x06, 0x0B, 0x80, 0x02, 0x00, 0x0A, 0x88, 0x01, 0x10] - ]; - - for (let i = 0; i < responseArray.length; i++) { - let strLen = responseArray[i].length * 2; - buf.writeInt32(strLen); - for (let j = 0; j < responseArray[i].length; j++) { - pduHelper.writeHexOctet(responseArray[i][j]); - } - buf.writeStringDelimiter(strLen); - - let options = {fileId: ICC_EF_ICCID, - structure: EF_STRUCTURE_TRANSPARENT}; - iccioHelper.processICCIOGetResponse(options); - - equal(options.fileSize, 0x0A); - } - - run_next_test(); -}); - -/** - * Verify ICCIOHelper.processICCIOGetResponse for EF_TYPE_LINEAR_FIXED. - */ -add_test(function test_icc_io_get_response_for_linear_fixed_structure() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let iccioHelper = context.ICCIOHelper; - let pduHelper = context.GsmPDUHelper; - - let responseArray = [ - // SIM response. - [0x00, 0x00, 0x00, 0x1A, 0x6F, 0x40, 0x04, 0x00, 0x11, 0xA0, 0xAA, 0x00, - 0x02, 0x01, 0x1A], - // USIM response. - [0x62, 0x1E, 0x82, 0x05, 0x42, 0x21, 0x00, 0x1A, 0x01, 0x83, 0x02, 0x6F, - 0x40, 0xA5, 0x03, 0x92, 0x01, 0x00, 0x8A, 0x01, 0x07, 0x8B, 0x03, 0x6F, - 0x06, 0x02, 0x80, 0x02, 0x00, 0x1A, 0x88, 0x00] - ]; - - for (let i = 0; i < responseArray.length; i++) { - let strLen = responseArray[i].length * 2; - buf.writeInt32(strLen); - for (let j = 0; j < responseArray[i].length; j++) { - pduHelper.writeHexOctet(responseArray[i][j]); - } - buf.writeStringDelimiter(strLen); - - let options = {fileId: ICC_EF_MSISDN, - structure: EF_STRUCTURE_LINEAR_FIXED}; - iccioHelper.processICCIOGetResponse(options); - - equal(options.fileSize, 0x1A); - equal(options.recordSize, 0x1A); - equal(options.totalRecords, 0x01); - } - - run_next_test(); -}); - diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js deleted file mode 100644 index 91495b1b7..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCPDUHelper.js +++ /dev/null @@ -1,652 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCPDUHelper#readICCUCS2String() - */ -add_test(function test_read_icc_ucs2_string() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - // 0x80 - let text = "TEST"; - helper.writeUCS2String(text); - // Also write two unused octets. - let ffLen = 2; - for (let i = 0; i < ffLen; i++) { - helper.writeHexOctet(0xff); - } - equal(iccHelper.readICCUCS2String(0x80, (2 * text.length) + ffLen), text); - - // 0x81 - let array = [0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, - 0xff, 0xff]; - let len = array.length; - for (let i = 0; i < len; i++) { - helper.writeHexOctet(array[i]); - } - equal(iccHelper.readICCUCS2String(0x81, len), "Mozilla\u694a"); - - // 0x82 - let array2 = [0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, - 0xca, 0xff, 0xff]; - let len2 = array2.length; - for (let i = 0; i < len2; i++) { - helper.writeHexOctet(array2[i]); - } - equal(iccHelper.readICCUCS2String(0x82, len2), "Mozilla\u694a"); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#writeICCUCS2String() - */ -add_test(function test_write_icc_ucs2_string() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let alphaLen = 18; - let test_data = [ - { - encode: 0x80, - // string only contain one character. - data: "\u82b3" - }, { - encode: 0x80, - // 2 UCS2 character not located in the same half-page. - data: "Fire \u82b3\u8233" - }, { - encode: 0x80, - // 2 UCS2 character not located in the same half-page. - data: "\u694a\u704a" - }, { - encode: 0x81, - // 2 UCS2 character within same half-page. - data: "Fire \u6901\u697f" - }, { - encode: 0x81, - // 2 UCS2 character within same half-page. - data: "Fire \u6980\u69ff" - }, { - encode: 0x82, - // 2 UCS2 character within same half-page, but bit 8 is different. - data: "Fire \u0514\u0593" - }, { - encode: 0x82, - // 2 UCS2 character over 0x81 can encode range. - data: "Fire \u8000\u8001" - }, { - encode: 0x82, - // 2 UCS2 character over 0x81 can encode range. - data: "Fire \ufffd\ufffe" - }]; - - for (let i = 0; i < test_data.length; i++) { - let test = test_data[i]; - let writtenStr = iccHelper.writeICCUCS2String(alphaLen, test.data); - equal(writtenStr, test.data); - equal(helper.readHexOctet(), test.encode); - equal(iccHelper.readICCUCS2String(test.encode, alphaLen - 1), test.data); - } - - // This string use 0x80 encoded and the maximum capacity is 17 octets. - // Each alphabet takes 2 octets, thus the first 8 alphabets can be written. - let str = "Mozilla \u82b3\u8233 On Fire"; - let writtenStr = iccHelper.writeICCUCS2String(alphaLen, str); - equal(writtenStr, str.substring(0, 8)); - equal(helper.readHexOctet(), 0x80); - equal(iccHelper.readICCUCS2String(0x80, alphaLen - 1), str.substring(0, 8)); - - // This string use 0x81 encoded and the maximum capacity is 15 octets. - // Each alphabet takes 1 octets, thus the first 15 alphabets can be written. - str = "Mozilla \u6901\u697f On Fire"; - writtenStr = iccHelper.writeICCUCS2String(alphaLen, str); - equal(writtenStr, str.substring(0, 15)); - equal(helper.readHexOctet(), 0x81); - equal(iccHelper.readICCUCS2String(0x81, alphaLen - 1), str.substring(0, 15)); - - // This string use 0x82 encoded and the maximum capacity is 14 octets. - // Each alphabet takes 1 octets, thus the first 14 alphabets can be written. - str = "Mozilla \u0514\u0593 On Fire"; - writtenStr = iccHelper.writeICCUCS2String(alphaLen, str); - equal(writtenStr, str.substring(0, 14)); - equal(helper.readHexOctet(), 0x82); - equal(iccHelper.readICCUCS2String(0x82, alphaLen - 1), str.substring(0, 14)); - - run_next_test(); -}); -/** - * Verify ICCPDUHelper#readDiallingNumber - */ -add_test(function test_read_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let str = "123456789"; - - helper.readHexOctet = function() { - return 0x81; - }; - - helper.readSwappedNibbleExtendedBcdString = function(len) { - return str.substring(0, len); - }; - - for (let i = 0; i < str.length; i++) { - equal(str.substring(0, i - 1), // -1 for the TON - iccHelper.readDiallingNumber(i)); - } - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#read8BitUnpackedToString - */ -add_test(function test_read_8bit_unpacked_to_string() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - // Test 1: Read GSM alphabets. - // Write alphabets before ESCAPE. - for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) { - helper.writeHexOctet(i); - } - - // Write two ESCAPEs to make it become ' '. - helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - - for (let i = PDU_NL_EXTENDED_ESCAPE + 1; i < langTable.length; i++) { - helper.writeHexOctet(i); - } - - // Also write two unused fields. - let ffLen = 2; - for (let i = 0; i < ffLen; i++) { - helper.writeHexOctet(0xff); - } - - equal(iccHelper.read8BitUnpackedToString(PDU_NL_EXTENDED_ESCAPE), - langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)); - equal(iccHelper.read8BitUnpackedToString(2), " "); - equal(iccHelper.read8BitUnpackedToString(langTable.length - - PDU_NL_EXTENDED_ESCAPE - 1 + ffLen), - langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1)); - - // Test 2: Read GSM extended alphabets. - for (let i = 0; i < langShiftTable.length; i++) { - helper.writeHexOctet(PDU_NL_EXTENDED_ESCAPE); - helper.writeHexOctet(i); - } - - // Read string before RESERVED_CONTROL. - equal(iccHelper.read8BitUnpackedToString(PDU_NL_RESERVED_CONTROL * 2), - langShiftTable.substring(0, PDU_NL_RESERVED_CONTROL)); - // ESCAPE + RESERVED_CONTROL will become ' '. - equal(iccHelper.read8BitUnpackedToString(2), " "); - // Read string between RESERVED_CONTROL and EXTENDED_ESCAPE. - equal(iccHelper.read8BitUnpackedToString( - (PDU_NL_EXTENDED_ESCAPE - PDU_NL_RESERVED_CONTROL - 1) * 2), - langShiftTable.substring(PDU_NL_RESERVED_CONTROL + 1, - PDU_NL_EXTENDED_ESCAPE)); - // ESCAPE + ESCAPE will become ' '. - equal(iccHelper.read8BitUnpackedToString(2), " "); - // Read remaining string. - equal(iccHelper.read8BitUnpackedToString( - (langShiftTable.length - PDU_NL_EXTENDED_ESCAPE - 1) * 2), - langShiftTable.substring(PDU_NL_EXTENDED_ESCAPE + 1)); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#writeStringTo8BitUnpacked. - * - * Test writing GSM 8 bit alphabets. - */ -add_test(function test_write_string_to_8bit_unpacked() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - // Length of trailing 0xff. - let ffLen = 2; - let str; - - // Test 1, write GSM alphabets. - let writtenStr = iccHelper.writeStringTo8BitUnpacked(langTable.length + ffLen, langTable); - equal(writtenStr, langTable); - - for (let i = 0; i < langTable.length; i++) { - equal(helper.readHexOctet(), i); - } - - for (let i = 0; i < ffLen; i++) { - equal(helper.readHexOctet(), 0xff); - } - - // Test 2, write GSM extended alphabets. - str = "\u000c\u20ac"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(4, str); - equal(writtenStr, str); - equal(iccHelper.read8BitUnpackedToString(4), str); - - // Test 3, write GSM and GSM extended alphabets. - // \u000c, \u20ac are from gsm extended alphabets. - // \u00a3 is from gsm alphabet. - str = "\u000c\u20ac\u00a3"; - - // 2 octets * 2 = 4 octets for 2 gsm extended alphabets, - // 1 octet for 1 gsm alphabet, - // 2 octes for trailing 0xff. - // "Totally 7 octets are to be written." - writtenStr = iccHelper.writeStringTo8BitUnpacked(7, str); - equal(writtenStr, str); - equal(iccHelper.read8BitUnpackedToString(7), str); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper#writeStringTo8BitUnpacked with maximum octets written. - */ -add_test(function test_write_string_to_8bit_unpacked_with_max_octets_written() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - // The maximum of the number of octets that can be written is 3. - // Only 3 characters shall be written even the length of the string is 4. - let writtenStr = iccHelper.writeStringTo8BitUnpacked(3, langTable.substring(0, 4)); - equal(writtenStr, langTable.substring(0, 3)); - helper.writeHexOctet(0xff); // dummy octet. - for (let i = 0; i < 3; i++) { - equal(helper.readHexOctet(), i); - } - ok(helper.readHexOctet() != 4); - - // \u000c is GSM extended alphabet, 2 octets. - // \u00a3 is GSM alphabet, 1 octet. - let str = "\u000c\u00a3"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(3, str); - equal(writtenStr, str.substring(0, 2)); - equal(iccHelper.read8BitUnpackedToString(3), str); - - str = "\u00a3\u000c"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(3, str); - equal(writtenStr, str.substring(0, 2)); - equal(iccHelper.read8BitUnpackedToString(3), str); - - // 2 GSM extended alphabets cost 4 octets, but maximum is 3, so only the 1st - // alphabet can be written. - str = "\u000c\u000c"; - writtenStr = iccHelper.writeStringTo8BitUnpacked(3, str); - helper.writeHexOctet(0xff); // dummy octet. - equal(writtenStr, str.substring(0, 1)); - equal(iccHelper.read8BitUnpackedToString(4), str.substring(0, 1)); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.readAlphaIdentifier - */ -add_test(function test_read_alpha_identifier() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - // UCS2: 0x80 - let text = "TEST"; - helper.writeHexOctet(0x80); - helper.writeUCS2String(text); - // Also write two unused octets. - let ffLen = 2; - for (let i = 0; i < ffLen; i++) { - helper.writeHexOctet(0xff); - } - equal(iccHelper.readAlphaIdentifier(1 + (2 * text.length) + ffLen), text); - - // UCS2: 0x81 - let array = [0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff]; - for (let i = 0; i < array.length; i++) { - helper.writeHexOctet(array[i]); - } - equal(iccHelper.readAlphaIdentifier(array.length), "Mozilla\u694a"); - - // UCS2: 0x82 - let array2 = [0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff]; - for (let i = 0; i < array2.length; i++) { - helper.writeHexOctet(array2[i]); - } - equal(iccHelper.readAlphaIdentifier(array2.length), "Mozilla\u694a"); - - // GSM 8 Bit Unpacked - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - for (let i = 0; i < PDU_NL_EXTENDED_ESCAPE; i++) { - helper.writeHexOctet(i); - } - equal(iccHelper.readAlphaIdentifier(PDU_NL_EXTENDED_ESCAPE), - langTable.substring(0, PDU_NL_EXTENDED_ESCAPE)); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeAlphaIdentifier - */ -add_test(function test_write_alpha_identifier() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - // Length of trailing 0xff. - let ffLen = 2; - - // Removal - let writenAlphaId = iccHelper.writeAlphaIdentifier(10, null); - equal(writenAlphaId, ""); - equal(iccHelper.readAlphaIdentifier(10), ""); - - // GSM 8 bit - let str = "Mozilla"; - writenAlphaId = iccHelper.writeAlphaIdentifier(str.length + ffLen, str); - equal(writenAlphaId , str); - equal(iccHelper.readAlphaIdentifier(str.length + ffLen), str); - - // UCS2 - str = "Mozilla\u8000"; - writenAlphaId = iccHelper.writeAlphaIdentifier(str.length * 2 + ffLen, str); - equal(writenAlphaId , str); - // * 2 for each character will be encoded to UCS2 alphabets. - equal(iccHelper.readAlphaIdentifier(str.length * 2 + ffLen), str); - - // Test with maximum octets written. - // 1 coding scheme (0x80) and 1 UCS2 character, total 3 octets. - str = "\u694a"; - writenAlphaId = iccHelper.writeAlphaIdentifier(3, str); - equal(writenAlphaId , str); - equal(iccHelper.readAlphaIdentifier(3), str); - - // 1 coding scheme (0x80) and 2 UCS2 characters, total 5 octets. - // numOctets is limited to 4, so only 1 UCS2 character can be written. - str = "\u694a\u69ca"; - writenAlphaId = iccHelper.writeAlphaIdentifier(4, str); - helper.writeHexOctet(0xff); // dummy octet. - equal(writenAlphaId , str.substring(0, 1)); - equal(iccHelper.readAlphaIdentifier(5), str.substring(0, 1)); - - // Write 0 octet. - writenAlphaId = iccHelper.writeAlphaIdentifier(0, "1"); - helper.writeHexOctet(0xff); // dummy octet. - equal(writenAlphaId, ""); - equal(iccHelper.readAlphaIdentifier(1), ""); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.readAlphaIdDiallingNumber - */ -add_test(function test_read_alpha_id_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let buf = context.Buf; - const recordSize = 32; - - function testReadAlphaIdDiallingNumber(contact) { - iccHelper.readAlphaIdentifier = function() { - return contact.alphaId; - }; - - iccHelper.readNumberWithLength = function() { - return contact.number; - }; - - let strLen = recordSize * 2; - buf.writeInt32(strLen); // fake length - helper.writeHexOctet(0xff); // fake CCP - helper.writeHexOctet(0xff); // fake EXT1 - buf.writeStringDelimiter(strLen); - - let contactR = iccHelper.readAlphaIdDiallingNumber(recordSize); - if (contact.alphaId == "" && contact.number == "") { - equal(contactR, null); - } else { - equal(contactR.alphaId, contact.alphaId); - equal(contactR.number, contact.number); - } - } - - testReadAlphaIdDiallingNumber({alphaId: "AlphaId", number: "0987654321"}); - testReadAlphaIdDiallingNumber({alphaId: "", number: ""}); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeAlphaIdDiallingNumber - */ -add_test(function test_write_alpha_id_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.ICCPDUHelper; - const recordSize = 32; - - // Write a normal contact. - let contactW = { - alphaId: "Mozilla", - number: "1234567890" - }; - - let writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - contactW.alphaId, - contactW.number, 0xff); - - let contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - // Write a contact with alphaId encoded in UCS2 and number has '+'. - let contactUCS2 = { - alphaId: "火狐", - number: "+1234567890" - }; - - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - contactUCS2.alphaId, - contactUCS2.number, 0xff); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - // Write a null contact (Removal). - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(contactR, null); - equal(writtenContact.alphaId, ""); - equal(writtenContact.number, ""); - - // Write a longer alphaId/dialling number - // Dialling Number : Maximum 20 digits(10 octets). - // Alpha Identifier: 32(recordSize) - 14 (10 octets for Dialling Number, 1 - // octet for TON/NPI, 1 for number length octet, and 2 for - // Ext) = Maximum 18 octets. - let longContact = { - alphaId: "AAAAAAAAABBBBBBBBBCCCCCCCCC", - number: "123456789012345678901234567890", - }; - - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - longContact.alphaId, - longContact.number, 0xff); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - // Add '+' to number and test again. - longContact.number = "+123456789012345678901234567890"; - writtenContact = helper.writeAlphaIdDiallingNumber(recordSize, - longContact.alphaId, - longContact.number, 0xff); - contactR = helper.readAlphaIdDiallingNumber(recordSize); - equal(writtenContact.alphaId, contactR.alphaId); - equal(writtenContact.number, contactR.number); - equal(0xff, contactR.extRecordNumber); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeDiallingNumber - */ -add_test(function test_write_dialling_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.ICCPDUHelper; - - // with + - let number = "+123456"; - let len = 4; - helper.writeDiallingNumber(number); - equal(helper.readDiallingNumber(len), number); - - // without + - number = "987654"; - len = 4; - helper.writeDiallingNumber(number); - equal(helper.readDiallingNumber(len), number); - - number = "9876543"; - len = 5; - helper.writeDiallingNumber(number); - equal(helper.readDiallingNumber(len), number); - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.readNumberWithLength - */ -add_test(function test_read_number_with_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - let numbers = [ - { - number: "123456789", - expectedNumber: "123456789" - }, - { - number: "", - expectedNumber: "" - }, - // Invalid length of BCD number/SSC contents - { - number: "12345678901234567890123", - expectedNumber: "" - }, - ]; - - // To avoid obtaining wrong buffer content. - context.Buf.seekIncoming = function(offset) { - }; - - function do_test(aNumber, aExpectedNumber) { - iccHelper.readDiallingNumber = function(numLen) { - return aNumber.substring(0, numLen); - }; - - if (aNumber) { - helper.writeHexOctet(aNumber.length + 1); - } else { - helper.writeHexOctet(0xff); - } - - equal(iccHelper.readNumberWithLength(), aExpectedNumber); - } - - for (let i = 0; i < numbers.length; i++) { - do_test(numbers[i].number, numbers[i].expectedNumber); - } - - run_next_test(); -}); - -/** - * Verify ICCPDUHelper.writeNumberWithLength - */ -add_test(function test_write_number_with_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - function test(number, expectedNumber) { - expectedNumber = expectedNumber || number; - let writeNumber = iccHelper.writeNumberWithLength(number); - equal(writeNumber, expectedNumber); - let numLen = helper.readHexOctet(); - equal(expectedNumber, iccHelper.readDiallingNumber(numLen)); - for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES - numLen); i++) { - equal(0xff, helper.readHexOctet()); - } - } - - // without + - test("123456789"); - - // with + - test("+987654321"); - - // extended BCD coding - test("1*2#3,4*5#6,"); - - // with + and extended BCD coding - test("+1*2#3,4*5#6,"); - - // non-supported characters should not be written. - test("(1)23-456+789", "123456789"); - - test("++(01)2*3-4#5,6+7(8)9*0#1,", "+012*34#5,6789*0#1,"); - - // over maximum 20 digits should be truncated. - test("012345678901234567890123456789", "01234567890123456789"); - - // null - iccHelper.writeNumberWithLength(null); - for (let i = 0; i < (ADN_MAX_BCD_NUMBER_BYTES + 1); i++) { - equal(0xff, helper.readHexOctet()); - } - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js deleted file mode 100644 index 00c55873d..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCRecordHelper.js +++ /dev/null @@ -1,1080 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCRecordHelper.readPBR - */ -add_test(function test_read_pbr() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let pbr_1 = [ - 0xa8, 0x05, 0xc0, 0x03, 0x4f, 0x3a, 0x01 - ]; - - // Write data size - buf.writeInt32(pbr_1.length * 2); - - // Write pbr - for (let i = 0; i < pbr_1.length; i++) { - helper.writeHexOctet(pbr_1[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(pbr_1.length * 2); - - options.totalRecords = 2; - if (options.callback) { - options.callback(options); - } - }; - - io.loadNextRecord = function fakeLoadNextRecord(options) { - let pbr_2 = [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff - ]; - - options.p1++; - if (options.callback) { - options.callback(options); - } - }; - - let successCb = function successCb(pbrs) { - equal(pbrs[0].adn.fileId, 0x4f3a); - equal(pbrs.length, 1); - }; - - let errorCb = function errorCb(errorMsg) { - do_print("Reading EF_PBR failed, msg = " + errorMsg); - ok(false); - }; - - record.readPBR(successCb, errorCb); - - // Check cache pbrs when 2nd call - let ifLoadEF = false; - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - ifLoadEF = true; - } - record.readPBR(successCb, errorCb); - ok(!ifLoadEF); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.readEmail - */ -add_test(function test_read_email() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let recordSize; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let email_1 = [ - 0x65, 0x6D, 0x61, 0x69, 0x6C, - 0x00, 0x6D, 0x6F, 0x7A, 0x69, - 0x6C, 0x6C, 0x61, 0x2E, 0x63, - 0x6F, 0x6D, 0x02, 0x23]; - - // Write data size - buf.writeInt32(email_1.length * 2); - - // Write email - for (let i = 0; i < email_1.length; i++) { - helper.writeHexOctet(email_1[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(email_1.length * 2); - - recordSize = email_1.length; - options.recordSize = recordSize; - if (options.callback) { - options.callback(options); - } - }; - - function doTestReadEmail(type, expectedResult) { - let fileId = 0x6a75; - let recordNumber = 1; - - // fileId and recordNumber are dummy arguments. - record.readEmail(fileId, type, recordNumber, function(email) { - equal(email, expectedResult); - }); - }; - - doTestReadEmail(ICC_USIM_TYPE1_TAG, "email@mozilla.com$#"); - doTestReadEmail(ICC_USIM_TYPE2_TAG, "email@mozilla.com"); - equal(record._emailRecordSize, recordSize); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateEmail - */ -add_test(function test_update_email() { - const recordSize = 0x20; - const recordNumber = 1; - const fileId = 0x4f50; - const NUM_TESTS = 2; - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let pbr = {email: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG}, - adn: {sfi: 1}}; - let count = 0; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(pbr, expectedEmail, expectedAdnRecordId) { - buf.sendParcel = function() { - count++; - - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - - // p1. - equal(this.readInt32(), recordNumber); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - let email; - if (pbr.email.fileType === ICC_USIM_TYPE1_TAG) { - email = iccHelper.read8BitUnpackedToString(recordSize); - } else { - email = iccHelper.read8BitUnpackedToString(recordSize - 2); - equal(pduHelper.readHexOctet(), pbr.adn.sfi); - equal(pduHelper.readHexOctet(), expectedAdnRecordId); - } - this.readStringDelimiter(strLen); - equal(email, expectedEmail); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - - if (count == NUM_TESTS) { - run_next_test(); - } - }; - recordHelper.updateEmail(pbr, recordNumber, expectedEmail, expectedAdnRecordId); - } - - do_test(pbr, "test@mail.com"); - pbr.email.fileType = ICC_USIM_TYPE2_TAG; - do_test(pbr, "test@mail.com", 1); -}); - -/** - * Verify ICCRecordHelper.readANR - */ -add_test(function test_read_anr() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let recordSize; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let anr_1 = [ - 0x01, 0x05, 0x81, 0x10, 0x32, - 0x54, 0xF6, 0xFF, 0xFF]; - - // Write data size - buf.writeInt32(anr_1.length * 2); - - // Write anr - for (let i = 0; i < anr_1.length; i++) { - helper.writeHexOctet(anr_1[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(anr_1.length * 2); - - recordSize = anr_1.length; - options.recordSize = recordSize; - if (options.callback) { - options.callback(options); - } - }; - - function doTestReadAnr(fileType, expectedResult) { - let fileId = 0x4f11; - let recordNumber = 1; - - // fileId and recordNumber are dummy arguments. - record.readANR(fileId, fileType, recordNumber, function(anr) { - equal(anr, expectedResult); - }); - }; - - doTestReadAnr(ICC_USIM_TYPE1_TAG, "0123456"); - equal(record._anrRecordSize, recordSize); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateANR - */ -add_test(function test_update_anr() { - const recordSize = 0x20; - const recordNumber = 1; - const fileId = 0x4f11; - const NUM_TESTS = 2; - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let pbr = {anr0: {fileId: fileId, fileType: ICC_USIM_TYPE1_TAG}, - adn: {sfi: 1}}; - let count = 0; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(pbr, expectedANR, expectedAdnRecordId) { - buf.sendParcel = function() { - count++; - - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - - // p1. - equal(this.readInt32(), recordNumber); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - // EF_AAS, ignore. - pduHelper.readHexOctet(); - equal(iccHelper.readNumberWithLength(), expectedANR); - // EF_CCP, ignore. - pduHelper.readHexOctet(); - // EF_EXT1, ignore. - pduHelper.readHexOctet(); - if (pbr.anr0.fileType === ICC_USIM_TYPE2_TAG) { - equal(pduHelper.readHexOctet(), pbr.adn.sfi); - equal(pduHelper.readHexOctet(), expectedAdnRecordId); - } - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - - if (count == NUM_TESTS) { - run_next_test(); - } - }; - recordHelper.updateANR(pbr, recordNumber, expectedANR, expectedAdnRecordId); - } - - do_test(pbr, "+123456789"); - pbr.anr0.fileType = ICC_USIM_TYPE2_TAG; - do_test(pbr, "123456789", 1); -}); - -/** - * Verify ICCRecordHelper.readIAP - */ -add_test(function test_read_iap() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let recordSize; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let iap_1 = [0x01, 0x02]; - - // Write data size/ - buf.writeInt32(iap_1.length * 2); - - // Write iap. - for (let i = 0; i < iap_1.length; i++) { - helper.writeHexOctet(iap_1[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(iap_1.length * 2); - - recordSize = iap_1.length; - options.recordSize = recordSize; - if (options.callback) { - options.callback(options); - } - }; - - function doTestReadIAP(expectedIAP) { - const fileId = 0x4f17; - const recordNumber = 1; - - let successCb = function successCb(iap) { - for (let i = 0; i < iap.length; i++) { - equal(expectedIAP[i], iap[i]); - } - run_next_test(); - }.bind(this); - - let errorCb = function errorCb(errorMsg) { - do_print(errorMsg); - ok(false); - run_next_test(); - }.bind(this); - - record.readIAP(fileId, recordNumber, successCb, errorCb); - }; - - doTestReadIAP([1, 2]); -}); - -/** - * Verify ICCRecordHelper.updateIAP - */ -add_test(function test_update_iap() { - const recordSize = 2; - const recordNumber = 1; - const fileId = 0x4f17; - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let count = 0; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(expectedIAP) { - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - - // p1. - equal(this.readInt32(), recordNumber); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - for (let i = 0; i < recordSize; i++) { - equal(expectedIAP[i], pduHelper.readHexOctet()); - } - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - - run_next_test(); - }; - recordHelper.updateIAP(fileId, recordNumber, expectedIAP); - } - - do_test([1, 2]); -}); - -/** - * Verify ICCRecordHelper.readADNLike. - */ -add_test(function test_read_adn_like() { - const RECORD_SIZE = 0x20; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let ril = context.RIL; - - function do_test(extFileId, rawEF, expectedExtRecordNumber, expectedNumber) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(rawEF.length * 2); - - // Write adn - for (let i = 0; i < rawEF.length; i += 2) { - helper.writeHexOctet(parseInt(rawEF.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawEF.length * 2); - - options.p1 = 1; - options.recordSize = RECORD_SIZE; - options.totalRecords = 1; - if (options.callback) { - options.callback(options); - } - }; - - record.readExtension = function(fileId, recordNumber, onsuccess, onerror) { - onsuccess("1234"); - } - - let successCb = function successCb(contacts) { - ok(contacts[0].number == expectedNumber); - }; - - let errorCb = function errorCb(errorMsg) { - do_print("Reading ADNLike failed, msg = " + errorMsg); - ok(false); - }; - - record.readADNLike(ICC_EF_ADN, extFileId, successCb, errorCb); - } - - ril.appType = CARD_APPTYPE_SIM; - // Valid extension - do_test(ICC_EF_EXT1,"436f6e74616374303031ffffffffffffffff0b8199887766554433221100ff01", - 0x01,"998877665544332211001234"); - // Empty extension - do_test(ICC_EF_EXT1,"436f6e74616374303031ffffffffffffffff0b8199887766554433221100ffff", - 0xff, "99887766554433221100"); - // Unsupport extension - do_test(null,"436f6e74616374303031ffffffffffffffff0b8199887766554433221100ffff", - 0xff, "99887766554433221100"); - // Empty dialling number contact - do_test(null,"436f6e74616374303031ffffffffffffffffffffffffffffffffffffffffffff", - 0xff, ""); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateADNLike. - */ -add_test(function test_update_adn_like() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let record = context.ICCRecordHelper; - let io = context.ICCIOHelper; - let pdu = context.ICCPDUHelper; - let buf = context.Buf; - - ril.appType = CARD_APPTYPE_SIM; - const recordSize = 0x20; - let fileId; - - // Override. - io.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - equal(this.readString(), EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); - - // p1. - equal(this.readInt32(), 1); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), 0x20); - - // data. - let contact = pdu.readAlphaIdDiallingNumber(0x20); - equal(contact.alphaId, "test"); - equal(contact.number, "123456"); - equal(contact.extRecordNumber, "0xff"); - - // pin2. - if (fileId == ICC_EF_ADN) { - equal(this.readString(), null); - } else { - equal(this.readString(), "1111"); - } - - // AID. Ignore because it's from modem. - this.readInt32(); - - if (fileId == ICC_EF_FDN) { - run_next_test(); - } - }; - - fileId = ICC_EF_ADN; - record.updateADNLike(fileId, 0xff, - {recordId: 1, alphaId: "test", number: "123456"}); - - fileId = ICC_EF_FDN; - record.updateADNLike(fileId, 0xff, - {recordId: 1, alphaId: "test", number: "123456"}, - "1111"); -}); - -/** - * Verify ICCRecordHelper.findFreeRecordId. - */ -add_test(function test_find_free_record_id() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let ril = context.RIL; - - function writeRecord(record) { - // Write data size - buf.writeInt32(record.length * 2); - - for (let i = 0; i < record.length; i++) { - pduHelper.writeHexOctet(record[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(record.length * 2); - } - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Some random data. - let record = [0x12, 0x34, 0x56, 0x78, 0x90]; - options.p1 = 1; - options.totalRecords = 2; - writeRecord(record); - if (options.callback) { - options.callback(options); - } - }; - - ril.iccIO = function fakeIccIO(options) { - // Unused bytes. - let record = [0xff, 0xff, 0xff, 0xff, 0xff]; - writeRecord(record); - if (options.callback) { - options.callback(options); - } - }; - - let fileId = 0x0000; // Dummy. - recordHelper.findFreeRecordId( - fileId, - function(recordId) { - equal(recordId, 2); - run_next_test(); - }.bind(this), - function(errorMsg) { - do_print(errorMsg); - ok(false); - run_next_test(); - }.bind(this)); -}); - -/** - * Verify ICCRecordHelper.fetchICCRecords. - */ -add_test(function test_fetch_icc_recodes() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let iccRecord = context.ICCRecordHelper; - let simRecord = context.SimRecordHelper; - let ruimRecord = context.RuimRecordHelper; - let fetchTag = 0x00; - - simRecord.fetchSimRecords = function() { - fetchTag = 0x01; - }; - - ruimRecord.fetchRuimRecords = function() { - fetchTag = 0x02; - }; - - RIL.appType = CARD_APPTYPE_SIM; - iccRecord.fetchICCRecords(); - equal(fetchTag, 0x01); - - RIL.appType = CARD_APPTYPE_RUIM; - iccRecord.fetchICCRecords(); - equal(fetchTag, 0x02); - - RIL.appType = CARD_APPTYPE_USIM; - iccRecord.fetchICCRecords(); - equal(fetchTag, 0x01); - - run_next_test(); -}); - -/** - * Verify reading EF_ICCID. - */ -add_test(function test_handling_iccid() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.ICCRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - ril.reportStkServiceIsRunning = function fakeReportStkServiceIsRunning() { - }; - - function do_test(rawICCID, expectedICCID) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(rawICCID.length); - - // Write data - for (let i = 0; i < rawICCID.length; i += 2) { - helper.writeHexOctet(parseInt(rawICCID.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawICCID.length); - - if (options.callback) { - options.callback(options); - } - }; - - record.readICCID(); - - equal(ril.iccInfo.iccid, expectedICCID); - } - - // Invalid value 0xE at high nibbile + low nibbile contains 0xF. - do_test("9868002E90909F001519", "89860020909"); - // Invalid value 0xD at low nibbile. - do_test("986800D2909090001519", "8986002090909005191"); - // Invalid value 0xC at low nibbile. - do_test("986800C2909090001519", "8986002090909005191"); - // Invalid value 0xB at low nibbile. - do_test("986800B2909090001519", "8986002090909005191"); - // Invalid value 0xA at low nibbile. - do_test("986800A2909090001519", "8986002090909005191"); - // Valid ICCID. - do_test("98101430121181157002", "89014103211118510720"); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.readExtension - */ -add_test(function test_read_extension() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test(rawExtension, expectedExtensionNumber) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(rawExtension.length * 2); - - // Write ext - for (let i = 0; i < rawExtension.length; i += 2) { - helper.writeHexOctet(parseInt(rawExtension.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawExtension.length); - - if (options.callback) { - options.callback(options); - } - }; - - let successCb = function successCb(number) { - do_print("extension number:" + number); - equal(number, expectedExtensionNumber); - }; - - let errorCb = function errorCb() { - ok(expectedExtensionNumber == null); - }; - - record.readExtension(0x6f4a, 1, successCb, errorCb); - } - - // Test unsupported record type 0x01 - do_test("010a10325476981032547698ff", ""); - // Test invalid length 0xc1 - do_test("020c10325476981032547698ff", null); - // Test extension chain which we don't support - do_test("020a1032547698103254769802", "01234567890123456789"); - // Test valid Extension - do_test("020a10325476981032547698ff", "01234567890123456789"); - // Test valid Extension - do_test("0209103254769810325476ffff", "012345678901234567"); - // Test empty Extension - do_test("02ffffffffffffffffffffffff", ""); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.updateExtension - */ -add_test(function test_update_extension() { - const RECORD_SIZE = 13; - const RECORD_NUMBER = 1; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = RECORD_SIZE; - ril.iccIO(options); - }; - - function do_test(fileId, number, expectedNumber) { - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - if (ril.appType == CARD_APPTYPE_SIM || ril.appType == CARD_APPTYPE_RUIM) { - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); - } else{ - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - } - - // p1. - equal(this.readInt32(), RECORD_NUMBER); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), RECORD_SIZE); - - // data. - let strLen = this.readInt32(); - // Extension record - let recordType = pduHelper.readHexOctet(); - - equal(recordType, 0x02); - equal(pduHelper.readHexOctet(), 10); - equal( - pduHelper.readSwappedNibbleExtendedBcdString(EXT_MAX_NUMBER_DIGITS - 1), - expectedNumber); - - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - }; - - recordHelper.updateExtension(fileId, RECORD_NUMBER, number); - } - - ril.appType = CARD_APPTYPE_SIM; - do_test(ICC_EF_EXT1, "01234567890123456789", "01234567890123456789"); - // We don't support extension chain. - do_test(ICC_EF_EXT1, "012345678901234567891234", "01234567890123456789"); - - ril.appType = CARD_APPTYPE_USIM; - do_test(ICC_EF_EXT1, "01234567890123456789", "01234567890123456789"); - - ril.appType = CARD_APPTYPE_RUIM; - do_test(ICC_EF_EXT1, "01234567890123456789", "01234567890123456789"); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.cleanEFRecord - */ -add_test(function test_clean_ef_record() { - const RECORD_SIZE = 13; - const RECORD_NUMBER = 1; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let recordHelper = context.ICCRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - - // Override. - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = RECORD_SIZE; - ril.iccIO(options); - }; - - function do_test(fileId) { - buf.sendParcel = function() { - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), fileId); - - // pathId. - if (ril.appType == CARD_APPTYPE_SIM || ril.appType == CARD_APPTYPE_RUIM) { - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM); - } else{ - equal(this.readString(), - EF_PATH_MF_SIM + EF_PATH_DF_TELECOM + EF_PATH_DF_PHONEBOOK); - } - - // p1. - equal(this.readInt32(), RECORD_NUMBER); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), RECORD_SIZE); - - // data. - let strLen = this.readInt32(); - // Extension record - for (let i = 0; i < RECORD_SIZE; i++) { - equal(pduHelper.readHexOctet(), 0xff); - } - - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - }; - - recordHelper.cleanEFRecord(fileId, RECORD_NUMBER); - } - - ril.appType = CARD_APPTYPE_SIM; - do_test(ICC_EF_EXT1); - - run_next_test(); -}); - -/** - * Verify ICCRecordHelper.getADNLikeExtensionRecordNumber - */ -add_test(function test_get_adn_like_extension_record_number() { - const RECORD_SIZE = 0x20; - - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let record = context.ICCRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test(rawEF, expectedRecordNumber) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(rawEF.length * 2); - - // Write ext - for (let i = 0; i < rawEF.length; i += 2) { - helper.writeHexOctet(parseInt(rawEF.substr(i, 2), 16)); - } - - // Write string delimiter - buf.writeStringDelimiter(rawEF.length); - options.recordSize = RECORD_SIZE; - if (options.callback) { - options.callback(options); - } - }; - - let isSuccess = false; - let successCb = function successCb(number) { - equal(number, expectedRecordNumber); - isSuccess = true; - }; - - let errorCb = function errorCb(errorMsg) { - do_print("Reading ADNLike failed, msg = " + errorMsg); - ok(false); - }; - - record.getADNLikeExtensionRecordNumber(ICC_EF_ADN, 1, successCb, errorCb); - ok(isSuccess); - } - - // Valid Extension, Alpha Id(Encoded with GSM 8 bit): "Contact001", - // Dialling Number: 99887766554433221100, Ext1: 0x01 - do_test("436f6e74616374303031ffffffffffffffff0b8199887766554433221100ff01", 0x01); - // Empty Extension, Alpha Id(Encoded with GSM 8 bit): "Contact001", Ext1: 0xff - do_test("436f6e74616374303031ffffffffffffffffffffffffffffffffffffffffffff", 0xff); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js deleted file mode 100644 index b23d0b598..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_ICCUtilsHelper.js +++ /dev/null @@ -1,326 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify ICCUtilsHelper.isICCServiceAvailable. - */ -add_test(function test_is_icc_service_available() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ICCUtilsHelper = context.ICCUtilsHelper; - let RIL = context.RIL; - - function test_table(sst, geckoService, simEnabled, usimEnabled) { - RIL.iccInfoPrivate.sst = sst; - RIL.appType = CARD_APPTYPE_SIM; - equal(ICCUtilsHelper.isICCServiceAvailable(geckoService), simEnabled); - RIL.appType = CARD_APPTYPE_USIM; - equal(ICCUtilsHelper.isICCServiceAvailable(geckoService), usimEnabled); - } - - test_table([0x08], "ADN", true, false); - test_table([0x08], "FDN", false, false); - test_table([0x08], "SDN", false, true); - - run_next_test(); -}); - -/** - * Verify ICCUtilsHelper.isGsm8BitAlphabet - */ -add_test(function test_is_gsm_8bit_alphabet() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ICCUtilsHelper = context.ICCUtilsHelper; - const langTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - const langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - - equal(ICCUtilsHelper.isGsm8BitAlphabet(langTable), true); - equal(ICCUtilsHelper.isGsm8BitAlphabet(langShiftTable), true); - equal(ICCUtilsHelper.isGsm8BitAlphabet("\uaaaa"), false); - - run_next_test(); -}); - -/** - * Verify ICCUtilsHelper.parsePbrTlvs - */ -add_test(function test_parse_pbr_tlvs() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - let pbrTlvs = [ - {tag: ICC_USIM_TYPE1_TAG, - length: 0x0F, - value: [{tag: ICC_USIM_EFADN_TAG, - length: 0x03, - value: [0x4F, 0x3A, 0x02]}, - {tag: ICC_USIM_EFIAP_TAG, - length: 0x03, - value: [0x4F, 0x25, 0x01]}, - {tag: ICC_USIM_EFPBC_TAG, - length: 0x03, - value: [0x4F, 0x09, 0x04]}] - }, - {tag: ICC_USIM_TYPE2_TAG, - length: 0x05, - value: [{tag: ICC_USIM_EFEMAIL_TAG, - length: 0x03, - value: [0x4F, 0x50, 0x0B]}, - {tag: ICC_USIM_EFANR_TAG, - length: 0x03, - value: [0x4F, 0x11, 0x02]}, - {tag: ICC_USIM_EFANR_TAG, - length: 0x03, - value: [0x4F, 0x12, 0x03]}] - }, - {tag: ICC_USIM_TYPE3_TAG, - length: 0x0A, - value: [{tag: ICC_USIM_EFCCP1_TAG, - length: 0x03, - value: [0x4F, 0x3D, 0x0A]}, - {tag: ICC_USIM_EFEXT1_TAG, - length: 0x03, - value: [0x4F, 0x4A, 0x03]}] - }, - ]; - - let pbr = context.ICCUtilsHelper.parsePbrTlvs(pbrTlvs); - equal(pbr.adn.fileId, 0x4F3a); - equal(pbr.iap.fileId, 0x4F25); - equal(pbr.pbc.fileId, 0x4F09); - equal(pbr.email.fileId, 0x4F50); - equal(pbr.anr0.fileId, 0x4f11); - equal(pbr.anr1.fileId, 0x4f12); - equal(pbr.ccp1.fileId, 0x4F3D); - equal(pbr.ext1.fileId, 0x4F4A); - - run_next_test(); -}); - -/** - * Verify MCC and MNC parsing - */ -add_test(function test_mcc_mnc_parsing() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.ICCUtilsHelper; - - function do_test(imsi, mncLength, expectedMcc, expectedMnc) { - let result = helper.parseMccMncFromImsi(imsi, mncLength); - - if (!imsi) { - equal(result, null); - return; - } - - equal(result.mcc, expectedMcc); - equal(result.mnc, expectedMnc); - } - - // Test the imsi is null. - do_test(null, null, null, null); - - // Test MCC is Taiwan - do_test("466923202422409", 0x02, "466", "92"); - do_test("466923202422409", 0x03, "466", "923"); - do_test("466923202422409", null, "466", "92"); - - // Test MCC is US - do_test("310260542718417", 0x02, "310", "26"); - do_test("310260542718417", 0x03, "310", "260"); - do_test("310260542718417", null, "310", "260"); - - run_next_test(); -}); - -add_test(function test_get_network_name_from_icc() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCUtilsHelper = context.ICCUtilsHelper; - - function testGetNetworkNameFromICC(operatorData, expectedResult) { - let result = ICCUtilsHelper.getNetworkNameFromICC(operatorData.mcc, - operatorData.mnc, - operatorData.lac); - - if (expectedResult == null) { - equal(result, expectedResult); - } else { - equal(result.fullName, expectedResult.longName); - equal(result.shortName, expectedResult.shortName); - } - } - - // Before EF_OPL and EF_PNN have been loaded. - testGetNetworkNameFromICC({mcc: "123", mnc: "456", lac: 0x1000}, null); - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x2000}, null); - - // Set HPLMN - RIL.iccInfo.mcc = "123"; - RIL.iccInfo.mnc = "456"; - - RIL.voiceRegistrationState = { - cell: { - gsmLocationAreaCode: 0x1000 - } - }; - RIL.operator = {}; - - // Set EF_PNN - RIL.iccInfoPrivate = { - PNN: [ - {"fullName": "PNN1Long", "shortName": "PNN1Short"}, - {"fullName": "PNN2Long", "shortName": "PNN2Short"}, - {"fullName": "PNN3Long", "shortName": "PNN3Short"}, - {"fullName": "PNN4Long", "shortName": "PNN4Short"}, - {"fullName": "PNN5Long", "shortName": "PNN5Short"}, - {"fullName": "PNN6Long", "shortName": "PNN6Short"}, - {"fullName": "PNN7Long", "shortName": "PNN7Short"}, - {"fullName": "PNN8Long", "shortName": "PNN8Short"} - ] - }; - - // EF_OPL isn't available - ICCUtilsHelper.isICCServiceAvailable = function fakeIsICCServiceAvailable(service) { - return false; - }; - - // EF_OPL isn't available and current isn't in HPLMN, - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x1000}, null); - - // EF_OPL isn't available and current is in HPLMN, - // the first record of PNN should be returned. - testGetNetworkNameFromICC({mcc: "123", mnc: "456", lac: 0x1000}, - {longName: "PNN1Long", shortName: "PNN1Short"}); - - // EF_OPL is available - ICCUtilsHelper.isICCServiceAvailable = function fakeIsICCServiceAvailable(service) { - return service === "OPL"; - }; - - // Set EF_OPL - RIL.iccInfoPrivate.OPL = [ - { - "mcc": "123", - "mnc": "456", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 4 - }, - { - "mcc": "321", - "mnc": "654", - "lacTacStart": 0, - "lacTacEnd": 0x0010, - "pnnRecordId": 3 - }, - { - "mcc": "321", - "mnc": "654", - "lacTacStart": 0x0100, - "lacTacEnd": 0x1010, - "pnnRecordId": 2 - }, - { - "mcc": ";;;", - "mnc": "01", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 5 - }, - { - "mcc": "00;", - "mnc": "02", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 6 - }, - { - "mcc": "001", - "mnc": ";;", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 7 - }, - { - "mcc": "002", - "mnc": "0;", - "lacTacStart": 0, - "lacTacEnd": 0xFFFE, - "pnnRecordId": 8 - } - ]; - - // Both EF_PNN and EF_OPL are presented, and current PLMN is HPLMN, - testGetNetworkNameFromICC({mcc: "123", mnc: "456", lac: 0x1000}, - {longName: "PNN4Long", shortName: "PNN4Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the second PNN record. - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x1000}, - {longName: "PNN2Long", shortName: "PNN2Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the thrid PNN record. - testGetNetworkNameFromICC({mcc: "321", mnc: "654", lac: 0x0001}, - {longName: "PNN3Long", shortName: "PNN3Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 5th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "001", mnc: "01", lac: 0x0001}, - {longName: "PNN5Long", shortName: "PNN5Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 6th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "001", mnc: "02", lac: 0x0001}, - {longName: "PNN6Long", shortName: "PNN6Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 7th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "001", mnc: "03", lac: 0x0001}, - {longName: "PNN7Long", shortName: "PNN7Short"}); - - // Current PLMN is not HPLMN, and according to LAC, we should get - // the 8th PNN record after wild char (ie: ';') handling. - testGetNetworkNameFromICC({mcc: "002", mnc: "03", lac: 0x0001}, - {longName: "PNN8Long", shortName: "PNN8Short"}); - - run_next_test(); -}); - -/** - * Verify ICCUtilsHelper.isCphsServiceAvailable. - */ -add_test(function test_is_cphs_service_available() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ICCUtilsHelper = context.ICCUtilsHelper; - let RIL = context.RIL; - RIL.iccInfoPrivate.cphsSt = new Uint8Array(2); - - function test_table(cphsSt, geckoService) { - RIL.iccInfoPrivate.cphsSt.set(cphsSt); - - for (let service in GECKO_ICC_SERVICES.cphs) { - equal(ICCUtilsHelper.isCphsServiceAvailable(service), - geckoService == service); - } - } - - test_table([0x03, 0x00], "CSP"); - test_table([0x0C, 0x00], "SST"); - test_table([0x30, 0x00], "MBN"); - test_table([0xC0, 0x00], "ONSF"); - test_table([0x00, 0x03], "INFO_NUM"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js b/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js deleted file mode 100644 index 8bcd26ffe..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_IconLoader.js +++ /dev/null @@ -1,771 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify IconLoader.loadIcons with recordNumbers array length being 1. - * Query images of one record at a time. - */ -add_test(function test_load_icon_basic() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let iconLoader = context.IconLoader; - let simRecordHelper = context.SimRecordHelper; - - let test_data = [ - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - expected: [ - {width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}]}, - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x10, - height: 0x10, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0xcc, 0xfc, 0xcc, - 0xcf, 0xcf, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, - 0xcc, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcc, - 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, - 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, 0xcf, - 0xfc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcf, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99], - clut: [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, - 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, - 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff]}], - expected: [ - {width: 0x10, - height: 0x10, - pixels: [0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff]}]}, - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x03, - height: 0x03, - bitsPerImgPoint: 0x05, - numOfClutEntries: 0x20, - body: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f]}, - {codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - expected: [ - {width: 0x03, - height: 0x03, - pixels: [0x000102ff, 0x060708ff, 0x0c0d0eff, 0x121314ff, 0x18191aff, - 0x1e1f20ff, 0x242526ff, 0x2a2b2cff, 0x333435ff]}, - {width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}]}, - {rawData: [ - {codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - width: 0x04, - height: 0x04, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f]}], - expected: [ - {width: 0x04, - height: 0x04, - pixels: [0x00000000, 0x00000000, 0x2a2b2cff, 0x2a2b2cff, 0x272829ff, - 0x272829ff, 0x242526ff, 0x242526ff, 0x212223ff, 0x212223ff, - 0x1e1f20ff, 0x1e1f20ff, 0x1b1c1dff, 0x1b1c1dff, 0x18191aff, - 0x18191aff]}]}]; - - function do_test(test_data, expected) { - simRecordHelper.readIMG = function fakeReadIMG(recordNumber, onsuccess, onerror) { - onsuccess(test_data); - }; - - let onsuccess = function(icons) { - // Query one record at a time. - equal(icons.length, 1); - equal(icons[0].length, expected.length); - for (let i = 0; i < icons[0].length; i++) { - // Read the i_th image of the record. - let icon = icons[0][i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.pixels.length, exp.pixels.length); - for (let j = 0; j < icon.pixels.length; j++) { - equal(icon.pixels[j], exp.pixels[j]); - } - } - }; - - iconLoader.loadIcons([0], onsuccess); - } - - for (let i = 0; i < test_data.length; i++) { - do_test(test_data[i].rawData, test_data[i].expected); - } - - run_next_test(); -}); - -/** - * Verify IconLoader.loadIcons. - */ -add_test(function test_load_icons() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let iconLoader = context.IconLoader; - let simRecordHelper = context.SimRecordHelper; - - let test_data = { - rawData: [ - // Record 1. - [{codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - // Record 2. - [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x10, - height: 0x10, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xcf, 0xfc, 0xcc, 0xfc, 0xcc, - 0xcf, 0xcf, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, - 0xcc, 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcc, - 0xfc, 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, - 0xcf, 0xcf, 0xff, 0xfc, 0xff, 0xcf, 0xcf, 0xcc, 0xcf, - 0xfc, 0xcc, 0xfc, 0xcc, 0xcf, 0xcf, 0xfc, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, - 0xaa, 0xaa, 0xaa, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, - 0x99, 0x99], - clut: [0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x00, - 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x80, - 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, - 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, - 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, - 0xff, 0xff, 0xff]}], - // Record 3. - [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - width: 0x03, - height: 0x03, - bitsPerImgPoint: 0x05, - numOfClutEntries: 0x20, - body: [0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, - 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, - 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f]}, - {codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - width: 0x10, - height: 0x10, - body: [0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x9d, 0xe9, 0xa1, 0x2d, 0xa1, 0x2d, 0xa1, 0x2b, - 0xa1, 0x2b, 0x9d, 0xe9, 0x00, 0x00, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0xff, 0xff]}], - // Record 4. - [{codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - width: 0x04, - height: 0x04, - bitsPerImgPoint: 0x04, - numOfClutEntries: 0x10, - body: [0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88], - clut: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, - 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, - 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, - 0x2d, 0x2e, 0x2f]}]], - expected: [ - // Record 1. - [{width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}], - // Record 2. - [{width: 0x10, - height: 0x10, - pixels: [0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, - 0xffffffff, 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0x0000ffff, 0x0000ffff, - 0x0000ffff, 0xffffffff, 0x0000ffff, 0xffffffff, 0xffffffff, - 0x0000ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, - 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, - 0xff0000ff]}], - // Record 3. - [{width: 0x03, - height: 0x03, - pixels: [0x000102ff, 0x060708ff, 0x0c0d0eff, 0x121314ff, 0x18191aff, - 0x1e1f20ff, 0x242526ff, 0x2a2b2cff, 0x333435ff]}, - {width: 0x10, - height: 0x10, - pixels: [/* 1st byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 2nd byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 3rd byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 4th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 5th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 6th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 7th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 8th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 9th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 10th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 11th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 12th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 13th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 14th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 15th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 16th byte of body: 0x2d */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 17th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 18th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 19th byte of body: 0xa1 */ - 0xffffffff, 0x000000ff, 0xffffffff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 20th byte of body: 0x2b */ - 0x000000ff, 0x000000ff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0xffffffff, 0xffffffff, - /* 21th byte of body: 0x9d */ - 0xffffffff, 0x000000ff, 0x000000ff, 0xffffffff, 0xffffffff, - 0xffffffff, 0x000000ff, 0xffffffff, - /* 22th byte of body: 0xe9 */ - 0xffffffff, 0xffffffff, 0xffffffff, 0x000000ff, 0xffffffff, - 0x000000ff, 0x000000ff, 0xffffffff, - /* 23th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 24th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 25th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 26th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 27th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 28th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 29th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 30th byte of body: 0x00 */ - 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff, - 0x000000ff, 0x000000ff, 0x000000ff, - /* 31th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff, - /* 32th byte of body: 0xff */ - 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, - 0xffffffff, 0xffffffff, 0xffffffff]}], - // Record 4. - [{width: 0x04, - height: 0x04, - pixels: [0x00000000, 0x00000000, 0x2a2b2cff, 0x2a2b2cff, 0x272829ff, - 0x272829ff, 0x242526ff, 0x242526ff, 0x212223ff, 0x212223ff, - 0x1e1f20ff, 0x1e1f20ff, 0x1b1c1dff, 0x1b1c1dff, 0x18191aff, - 0x18191aff]}]]}; - - function do_test() { - simRecordHelper.readIMG = function fakeReadIMG(recordNumber, onsuccess, onerror) { - onsuccess(test_data.rawData[recordNumber]); - }; - - let onsuccess = function(icons) { - equal(icons.length, test_data.expected.length); - for (let i = 0; i < icons.length; i++) { - for (let j = 0; j < icons[i].length; j++) { - // Read the j_th image from the i_th record. - let icon = icons[i][j]; - let expected = test_data.expected[i][j]; - equal(icon.width, expected.width); - equal(icon.height, expected.height); - equal(icon.pixels.length, expected.pixels.length); - for (let k = 0; k < icon.pixels.length; k++) { - equal(icon.pixels[k], expected.pixels[k]); - } - } - } - }; - - let recordNumbers = [0, 1, 2, 3]; - iconLoader.loadIcons(recordNumbers, onsuccess); - } - - do_test(); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js b/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js deleted file mode 100644 index 6500cc663..000000000 --- a/dom/system/gonk/tests/test_ril_worker_icc_SimRecordHelper.js +++ /dev/null @@ -1,1648 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify reading EF_AD and parsing MCC/MNC - */ -add_test(function test_reading_ad_and_parsing_mcc_mnc() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test(mncLengthInEf, imsi, expectedMcc, expectedMnc) { - ril.iccInfoPrivate.imsi = imsi; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - let ad = [0x00, 0x00, 0x00]; - if (typeof mncLengthInEf === 'number') { - ad.push(mncLengthInEf); - } - - // Write data size - buf.writeInt32(ad.length * 2); - - // Write data - for (let i = 0; i < ad.length; i++) { - helper.writeHexOctet(ad[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(ad.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readAD(); - - equal(ril.iccInfo.mcc, expectedMcc); - equal(ril.iccInfo.mnc, expectedMnc); - } - - do_test(undefined, "466923202422409", "466", "92" ); - do_test(0x00, "466923202422409", "466", "92" ); - do_test(0x01, "466923202422409", "466", "92" ); - do_test(0x02, "466923202422409", "466", "92" ); - do_test(0x03, "466923202422409", "466", "923"); - do_test(0x04, "466923202422409", "466", "92" ); - do_test(0xff, "466923202422409", "466", "92" ); - - do_test(undefined, "310260542718417", "310", "260"); - do_test(0x00, "310260542718417", "310", "260"); - do_test(0x01, "310260542718417", "310", "260"); - do_test(0x02, "310260542718417", "310", "26" ); - do_test(0x03, "310260542718417", "310", "260"); - do_test(0x04, "310260542718417", "310", "260"); - do_test(0xff, "310260542718417", "310", "260"); - - run_next_test(); -}); - -add_test(function test_reading_optional_efs() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let gsmPdu = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function buildSST(supportedEf) { - let sst = []; - let len = supportedEf.length; - for (let i = 0; i < len; i++) { - let index, bitmask, iccService; - if (ril.appType === CARD_APPTYPE_SIM) { - iccService = GECKO_ICC_SERVICES.sim[supportedEf[i]]; - iccService -= 1; - index = Math.floor(iccService / 4); - bitmask = 2 << ((iccService % 4) << 1); - } else if (ril.appType === CARD_APPTYPE_USIM){ - iccService = GECKO_ICC_SERVICES.usim[supportedEf[i]]; - iccService -= 1; - index = Math.floor(iccService / 8); - bitmask = 1 << ((iccService % 8) << 0); - } - - if (sst) { - sst[index] |= bitmask; - } - } - return sst; - } - - ril.updateCellBroadcastConfig = function fakeUpdateCellBroadcastConfig() { - // Ignore updateCellBroadcastConfig after reading SST - }; - - function do_test(sst, supportedEf) { - // Clone supportedEf to local array for testing - let testEf = supportedEf.slice(0); - - record.readMSISDN = function fakeReadMSISDN() { - testEf.splice(testEf.indexOf("MSISDN"), 1); - }; - - record.readMBDN = function fakeReadMBDN() { - testEf.splice(testEf.indexOf("MDN"), 1); - }; - - record.readMWIS = function fakeReadMWIS() { - testEf.splice(testEf.indexOf("MWIS"), 1); - }; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(sst.length * 2); - - // Write data - for (let i = 0; i < sst.length; i++) { - gsmPdu.writeHexOctet(sst[i] || 0); - } - - // Write string delimiter - buf.writeStringDelimiter(sst.length * 2); - - if (options.callback) { - options.callback(options); - } - - if (testEf.length !== 0) { - do_print("Un-handled EF: " + JSON.stringify(testEf)); - ok(false); - } - }; - - record.readSST(); - } - - // TODO: Add all necessary optional EFs eventually - let supportedEf = ["MSISDN", "MDN", "MWIS"]; - ril.appType = CARD_APPTYPE_SIM; - do_test(buildSST(supportedEf), supportedEf); - ril.appType = CARD_APPTYPE_USIM; - do_test(buildSST(supportedEf), supportedEf); - - run_next_test(); -}); - -/** - * Verify fetchSimRecords. - */ -add_test(function test_fetch_sim_records() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let iccRecord = context.ICCRecordHelper; - let simRecord = context.SimRecordHelper; - - function testFetchSimRecordes(expectCalled, expectCphsSuccess) { - let ifCalled = []; - - RIL.getIMSI = function() { - ifCalled.push("getIMSI"); - }; - - simRecord.readAD = function() { - ifCalled.push("readAD"); - }; - - simRecord.readCphsInfo = function(onsuccess, onerror) { - ifCalled.push("readCphsInfo"); - if (expectCphsSuccess) { - onsuccess(); - } else { - onerror(); - } - }; - - simRecord.readSST = function() { - ifCalled.push("readSST"); - }; - - simRecord.fetchSimRecords(); - - for (let i = 0; i < expectCalled.length; i++ ) { - if (ifCalled[i] != expectCalled[i]) { - do_print(expectCalled[i] + " is not called."); - ok(false); - } - } - } - - let expectCalled = ["getIMSI", "readAD", "readCphsInfo", "readSST"]; - testFetchSimRecordes(expectCalled, true); - testFetchSimRecordes(expectCalled, false); - - run_next_test(); -}); - -/** - * Verify SimRecordHelper.readMWIS - */ -add_test(function test_read_mwis() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let mwisData; - let postedMessage; - - worker.postMessage = function fakePostMessage(message) { - postedMessage = message; - }; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - if (mwisData) { - // Write data size - buf.writeInt32(mwisData.length * 2); - - // Write MWIS - for (let i = 0; i < mwisData.length; i++) { - helper.writeHexOctet(mwisData[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(mwisData.length * 2); - - options.recordSize = mwisData.length; - if (options.callback) { - options.callback(options); - } - } else { - do_print("mwisData[] is not set."); - } - }; - - function buildMwisData(isActive, msgCount) { - if (msgCount < 0 || msgCount === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) { - msgCount = 0; - } else if (msgCount > 255) { - msgCount = 255; - } - - mwisData = [ (isActive) ? 0x01 : 0x00, - msgCount, - 0xFF, 0xFF, 0xFF ]; - } - - function do_test(isActive, msgCount) { - buildMwisData(isActive, msgCount); - recordHelper.readMWIS(); - - equal("iccmwis", postedMessage.rilMessageType); - equal(isActive, postedMessage.mwi.active); - equal((isActive) ? msgCount : 0, postedMessage.mwi.msgCount); - } - - do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN); - do_test(true, 1); - do_test(true, 255); - - do_test(false, 0); - do_test(false, 255); // Test the corner case when mwi is disable with incorrect msgCount. - - run_next_test(); -}); - -/** - * Verify SimRecordHelper.updateMWIS - */ -add_test(function test_update_mwis() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - ril.appType = CARD_APPTYPE_USIM; - ril.iccInfoPrivate.mwis = [0x00, 0x00, 0x00, 0x00, 0x00]; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let ioHelper = context.ICCIOHelper; - let recordSize = ril.iccInfoPrivate.mwis.length; - let recordNum = 1; - - ioHelper.updateLinearFixedEF = function(options) { - options.pathId = context.ICCFileHelper.getEFPath(options.fileId); - options.command = ICC_COMMAND_UPDATE_RECORD; - options.p1 = options.recordNumber; - options.p2 = READ_RECORD_ABSOLUTE_MODE; - options.p3 = recordSize; - ril.iccIO(options); - }; - - function do_test(isActive, count) { - let mwis = ril.iccInfoPrivate.mwis; - let isUpdated = false; - - function buildMwisData() { - let result = mwis.slice(0); - result[0] = isActive? (mwis[0] | 0x01) : (mwis[0] & 0xFE); - result[1] = (count === GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN) ? 0 : count; - - return result; - } - - buf.sendParcel = function() { - isUpdated = true; - - // Request Type. - equal(this.readInt32(), REQUEST_SIM_IO); - - // Token : we don't care - this.readInt32(); - - // command. - equal(this.readInt32(), ICC_COMMAND_UPDATE_RECORD); - - // fileId. - equal(this.readInt32(), ICC_EF_MWIS); - - // pathId. - equal(this.readString(), - EF_PATH_MF_SIM + ((ril.appType === CARD_APPTYPE_USIM) ? EF_PATH_ADF_USIM : EF_PATH_DF_GSM)); - - // p1. - equal(this.readInt32(), recordNum); - - // p2. - equal(this.readInt32(), READ_RECORD_ABSOLUTE_MODE); - - // p3. - equal(this.readInt32(), recordSize); - - // data. - let strLen = this.readInt32(); - equal(recordSize * 2, strLen); - let expectedMwis = buildMwisData(); - for (let i = 0; i < recordSize; i++) { - equal(expectedMwis[i], pduHelper.readHexOctet()); - } - this.readStringDelimiter(strLen); - - // pin2. - equal(this.readString(), null); - - // AID. Ignore because it's from modem. - this.readInt32(); - }; - - ok(!isUpdated); - - recordHelper.updateMWIS({ active: isActive, - msgCount: count }); - - ok((ril.iccInfoPrivate.mwis) ? isUpdated : !isUpdated); - } - - do_test(true, GECKO_VOICEMAIL_MESSAGE_COUNT_UNKNOWN); - do_test(true, 1); - do_test(true, 255); - - do_test(false, 0); - - // Test if Path ID is correct for SIM. - ril.appType = CARD_APPTYPE_SIM; - do_test(false, 0); - - // Test if loadLinearFixedEF() is not invoked in updateMWIS() when - // EF_MWIS is not loaded/available. - delete ril.iccInfoPrivate.mwis; - do_test(false, 0); - - run_next_test(); -}); - -/** - * Verify the call flow of receiving Class 2 SMS stored in SIM: - * 1. UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM. - * 2. SimRecordHelper.readSMS(). - * 3. sendChromeMessage() with rilMessageType == "sms-received". - */ -add_test(function test_read_new_sms_on_sim() { - // Instead of reusing newUint8Worker defined in this file, - // we define our own worker to fake the methods in WorkerBuffer dynamically. - function newSmsOnSimWorkerHelper() { - let _postedMessage; - let _worker = newWorker({ - postRILMessage: function(data) { - }, - postMessage: function(message) { - _postedMessage = message; - } - }); - - _worker.debug = do_print; - - return { - get postedMessage() { - return _postedMessage; - }, - get worker() { - return _worker; - }, - fakeWokerBuffer: function() { - let context = _worker.ContextPool._contexts[0]; - let index = 0; // index for read - let buf = []; - context.Buf.writeUint8 = function(value) { - buf.push(value); - }; - context.Buf.readUint8 = function() { - return buf[index++]; - }; - context.Buf.seekIncoming = function(offset) { - index += offset; - }; - context.Buf.getReadAvailable = function() { - return buf.length - index; - }; - } - }; - } - - let workerHelper = newSmsOnSimWorkerHelper(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.ICCIOHelper.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // SimStatus: Unread, SMSC:+0123456789, Sender: +9876543210, Text: How are you? - let SimSmsPduHex = "0306911032547698040A9189674523010000208062917314080CC8F71D14969741F977FD07" - // In 4.2.25 EF_SMS Short Messages of 3GPP TS 31.102: - // 1. Record length == 176 bytes. - // 2. Any bytes in the record following the TPDU shall be filled with 'FF'. - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" - + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; - - workerHelper.fakeWokerBuffer(); - - context.Buf.writeString(SimSmsPduHex); - - options.recordSize = 176; // Record length is fixed to 176 bytes. - if (options.callback) { - options.callback(options); - } - }; - - function newSmsOnSimParcel() { - let data = new Uint8Array(4 + 4); // Int32List with 1 element. - let offset = 0; - - function writeInt(value) { - data[offset++] = value & 0xFF; - data[offset++] = (value >> 8) & 0xFF; - data[offset++] = (value >> 16) & 0xFF; - data[offset++] = (value >> 24) & 0xFF; - } - - writeInt(1); // Length of Int32List - writeInt(1); // RecordNum = 1. - - return newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_SMS_ON_SIM, - data); - } - - function do_test() { - worker.onRILMessage(0, newSmsOnSimParcel()); - - let postedMessage = workerHelper.postedMessage; - - equal("sms-received", postedMessage.rilMessageType); - equal("+0123456789", postedMessage.SMSC); - equal("+9876543210", postedMessage.sender); - equal("How are you?", postedMessage.body); - } - - do_test(); - - run_next_test(); -}); - -/** - * Verify the result of updateDisplayCondition after reading EF_SPDI | EF_SPN. - */ -add_test(function test_update_display_condition() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function do_test_spdi() { - // No EF_SPN, but having EF_SPDI. - // It implies "ril.iccInfoPrivate.spnDisplayCondition = undefined;". - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // PLMN lists are : 234-136 and 466-92. - let spdi = [0xA3, 0x0B, 0x80, 0x09, 0x32, 0x64, 0x31, 0x64, 0x26, 0x9F, - 0xFF, 0xFF, 0xFF]; - - // Write data size. - buf.writeInt32(spdi.length * 2); - - // Write data. - for (let i = 0; i < spdi.length; i++) { - helper.writeHexOctet(spdi[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(spdi.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readSPDI(); - - equal(ril.iccInfo.isDisplayNetworkNameRequired, true); - equal(ril.iccInfo.isDisplaySpnRequired, false); - } - - function do_test_spn(displayCondition, - expectedPlmnNameDisplay, - expectedSpnDisplay) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // "Android" as Service Provider Name. - let spn = [0x41, 0x6E, 0x64, 0x72, 0x6F, 0x69, 0x64]; - if (typeof displayCondition === 'number') { - spn.unshift(displayCondition); - } - - // Write data size. - buf.writeInt32(spn.length * 2); - - // Write data. - for (let i = 0; i < spn.length; i++) { - helper.writeHexOctet(spn[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(spn.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readSPN(); - - equal(ril.iccInfo.isDisplayNetworkNameRequired, expectedPlmnNameDisplay); - equal(ril.iccInfo.isDisplaySpnRequired, expectedSpnDisplay); - } - - // Create empty operator object. - ril.operator = {}; - // Setup SIM MCC-MNC to 310-260 as home network. - ril.iccInfo.mcc = 310; - ril.iccInfo.mnc = 260; - - do_test_spdi(); - - // No network. - do_test_spn(0x00, true, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, true, false); - do_test_spn(0x03, true, false); - - // Home network. - ril.operator.mcc = 310; - ril.operator.mnc = 260; - do_test_spn(0x00, false, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, false, true); - do_test_spn(0x03, true, true); - - // Not HPLMN but in PLMN list. - ril.iccInfoPrivate.SPDI = [{"mcc":"234","mnc":"136"},{"mcc":"466","mnc":"92"}]; - ril.operator.mcc = 466; - ril.operator.mnc = 92; - do_test_spn(0x00, false, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, false, true); - do_test_spn(0x03, true, true); - ril.iccInfoPrivate.SPDI = null; // reset SPDI to null; - - // Non-Home network. - ril.operator.mcc = 466; - ril.operator.mnc = 01; - do_test_spn(0x00, true, true); - do_test_spn(0x01, true, true); - do_test_spn(0x02, true, false); - do_test_spn(0x03, true, false); - - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with ICC_IMG_CODING_SCHEME_BASIC - */ -add_test(function test_reading_img_basic() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06], - iidf: [ - [/* Header */ - 0x05, 0x05, - /* Image body */ - 0x11, 0x33, 0x55, 0xfe]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x11, 0x33, 0x55, 0xfe]}]}, - {img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06, - /* Padding */ - 0xff, 0xff], - iidf: [ - [/* Header */ - 0x05, 0x05, - /* Image body */ - 0x11, 0x33, 0x55, 0xfe]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x11, 0x33, 0x55, 0xfe]}]}, - {img: [0x02, 0x10, 0x01, 0x11, 0x4f, 0x04, 0x00, 0x05, 0x00, 0x04, 0x10, - 0x01, 0x11, 0x4f, 0x05, 0x00, 0x05, 0x00, 0x04], - iidf: [ - [/* Data offset */ - 0xff, 0xff, 0xff, 0xff, 0xff, - /* Header */ - 0x10, 0x01, - /* Image body */ - 0x11, 0x99, - /* Trailing data */ - 0xff, 0xff, 0xff], - [/* Data offset */ - 0xff, 0xff, 0xff, 0xff, 0xff, - /* Header */ - 0x10, 0x01, - /* Image body */ - 0x99, 0x11]], - expected: [ - {width: 0x10, - height: 0x01, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x11, 0x99]}, - {width: 0x10, - height: 0x01, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x99, 0x11]}]}, - {img: [0x01, 0x28, 0x20, 0x11, 0x4f, 0xac, 0x00, 0x0b, 0x00, 0xa2], - iidf: [ - [/* Data offset */ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - /* Header */ - 0x28, 0x20, - /* Image body */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, - 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, - 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, - 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x01, 0x02, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, - 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, - 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f]], - expected: [ - {width: 0x28, - height: 0x20, - codingScheme: ICC_IMG_CODING_SCHEME_BASIC, - body: [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, - 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, - 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, - 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, - 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x01, 0x02, 0x03, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, - 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, - 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, - 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, - 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f]}]}]; - - function do_test(img, iidf, expected) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let instanceIndex = 0; - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf[instanceIndex].length * 2); - - // Write data - for (let i = 0; i < iidf[instanceIndex].length; i++) { - helper.writeHexOctet(iidf[instanceIndex][i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf[instanceIndex].length * 2); - - instanceIndex++; - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function(icons) { - equal(icons.length, expected.length); - for (let i = 0; i < icons.length; i++) { - let icon = icons[i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.codingScheme, exp.codingScheme); - - equal(icon.body.length, exp.body.length); - for (let j = 0; j < icon.body.length; j++) { - equal(icon.body[j], exp.body[j]); - } - } - }; - record.readIMG(0, onsuccess); - } - - for (let i = 0; i< test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with the case data length is not enough - */ -add_test(function test_reading_img_length_error() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {/* Offset length not enough, should be 4. */ - img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x04, 0x00, 0x06], - iidf: [0xff, 0xff, 0xff, // Offset. - 0x05, 0x05, 0x11, 0x22, 0x33, 0xfe]}, - {/* iidf data length not enough, should be 6. */ - img: [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06], - iidf: [0x05, 0x05, 0x11, 0x22, 0x33]}]; - - function do_test(img, iidf) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf.length * 2); - - // Write data - for (let i = 0; i < iidf.length; i++) { - helper.writeHexOctet(iidf[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function() { - do_print("onsuccess shouldn't be called."); - ok(false); - }; - - let onerror = function() { - do_print("onerror called as expected."); - ok(true); - }; - - record.readIMG(0, onsuccess, onerror); - } - - for (let i = 0; i < test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with an invalid fileId - */ -add_test(function test_reading_img_invalid_fileId() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - // Test invalid fileId: 0x5f00. - let img_test = [0x01, 0x05, 0x05, 0x11, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x06]; - let iidf_test = [0x05, 0x05, 0x11, 0x22, 0x33, 0xfe]; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img_test.length * 2); - - // Write data - for (let i = 0; i < img_test.length; i++) { - helper.writeHexOctet(img_test[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img_test.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf_test.length * 2); - - // Write data - for (let i = 0; i < iidf_test.length; i++) { - helper.writeHexOctet(iidf_test[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf_test.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function() { - do_print("onsuccess shouldn't be called."); - ok(false); - }; - - let onerror = function() { - do_print("onerror called as expected."); - ok(true); - }; - - record.readIMG(0, onsuccess, onerror); - - run_next_test(); -}); - -/** - * Verify reading EF_IMG with a wrong record length - */ -add_test(function test_reading_img_wrong_record_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - [0x01, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00], - [0x02, 0x05, 0x05, 0x11, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x06]]; - - function do_test(img) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function() { - do_print("onsuccess shouldn't be called."); - ok(false); - }; - - let onerror = function() { - do_print("onerror called as expected."); - ok(true); - }; - - record.readIMG(0, onsuccess, onerror); - } - - for (let i = 0; i < test_data.length; i++) { - do_test(test_data[i]); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with ICC_IMG_CODING_SCHEME_COLOR - */ -add_test(function test_reading_img_color() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {img: [0x01, 0x05, 0x05, 0x21, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x13], - iidf: [ - [/* Header */ - 0x05, 0x05, 0x03, 0x08, 0x00, 0x13, - /* Image body */ - 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, - 0xb0, 0xc0, 0xd0, - /* Clut entries */ - 0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - bitsPerImgPoint: 0x03, - numOfClutEntries: 0x08, - body: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, - 0xc0, 0xd0], - clut: [0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]}]}, - {img: [0x02, 0x01, 0x06, 0x21, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08, 0x01, - 0x06, 0x21, 0x4f, 0x44, 0x00, 0x02, 0x00, 0x08], - iidf: [ - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x40, 0x50, - /* Clut offset */ - 0xaa, 0xbb, 0xcc, - /* Clut entries */ - 0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65], - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x4f, 0x5f, - /* Clut offset */ - 0xaa, 0xbb, 0xcc, - /* Clut entries */ - 0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]], - expected: [ - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x40, 0x50], - clut: [0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}, - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x4f, 0x5f], - clut: [0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}]}]; - - function do_test(img, iidf, expected) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let instanceIndex = 0; - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf[instanceIndex].length * 2); - - // Write data - for (let i = 0; i < iidf[instanceIndex].length; i++) { - helper.writeHexOctet(iidf[instanceIndex][i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf[instanceIndex].length * 2); - - instanceIndex++; - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function(icons) { - equal(icons.length, expected.length); - for (let i = 0; i < icons.length; i++) { - let icon = icons[i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.codingScheme, exp.codingScheme); - - equal(icon.body.length, exp.body.length); - for (let j = 0; j < icon.body.length; j++) { - equal(icon.body[j], exp.body[j]); - } - - equal(icon.clut.length, exp.clut.length); - for (let j = 0; j < icon.clut.length; j++) { - equal(icon.clut[j], exp.clut[j]); - } - } - }; - - record.readIMG(0, onsuccess); - } - - for (let i = 0; i< test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected); - } - run_next_test(); -}); - -/** - * Verify reading EF_IMG and EF_IIDF with - * ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY - */ -add_test(function test_reading_img_color() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let helper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [ - {img: [0x01, 0x05, 0x05, 0x22, 0x4f, 0x11, 0x00, 0x00, 0x00, 0x13], - iidf: [ - [/* Header */ - 0x05, 0x05, 0x03, 0x08, 0x00, 0x13, - /* Image body */ - 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, - 0xb0, 0xc0, 0xd0, - /* Clut entries */ - 0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]], - expected: [ - {width: 0x05, - height: 0x05, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - bitsPerImgPoint: 0x03, - numOfClutEntries: 0x08, - body: [0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, - 0xa0, 0xb0, 0xc0, 0xd0], - clut: [0x00, 0x01, 0x02, - 0x10, 0x11, 0x12, - 0x20, 0x21, 0x22, - 0x30, 0x31, 0x32, - 0x40, 0x41, 0x42, - 0x50, 0x51, 0x52, - 0x60, 0x61, 0x62, - 0x70, 0x71, 0x72]}]}, - {img: [0x02, 0x01, 0x06, 0x22, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08, 0x01, - 0x06, 0x22, 0x4f, 0x33, 0x00, 0x02, 0x00, 0x08], - iidf: [ - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x40, 0x50, - /* Clut offset */ - 0x0a, 0x0b, 0x0c, - /* Clut entries */ - 0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65], - [/* Data offset */ - 0xff, 0xff, - /* Header */ - 0x01, 0x06, 0x02, 0x04, 0x00, 0x0d, - /* Image body */ - 0x4f, 0x5f, - /* Clut offset */ - 0x0a, 0x0b, 0x0c, - /* Clut entries */ - 0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]], - expected: [ - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x40, 0x50], - clut: [0x01, 0x03, 0x05, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}, - {width: 0x01, - height: 0x06, - codingScheme: ICC_IMG_CODING_SCHEME_COLOR_TRANSPARENCY, - bitsPerImgPoint: 0x02, - numOfClutEntries: 0x04, - body: [0x4f, 0x5f], - clut: [0x11, 0x13, 0x15, - 0x21, 0x23, 0x25, - 0x41, 0x43, 0x45, - 0x61, 0x63, 0x65]}]}]; - - function do_test(img, iidf, expected) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size - buf.writeInt32(img.length * 2); - - // Write data - for (let i = 0; i < img.length; i++) { - helper.writeHexOctet(img[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(img.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - let instanceIndex = 0; - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(iidf[instanceIndex].length * 2); - - // Write data - for (let i = 0; i < iidf[instanceIndex].length; i++) { - helper.writeHexOctet(iidf[instanceIndex][i]); - } - - // Write string delimiter - buf.writeStringDelimiter(iidf[instanceIndex].length * 2); - - instanceIndex++; - - if (options.callback) { - options.callback(options); - } - }; - - let onsuccess = function(icons) { - equal(icons.length, expected.length); - for (let i = 0; i < icons.length; i++) { - let icon = icons[i]; - let exp = expected[i]; - equal(icon.width, exp.width); - equal(icon.height, exp.height); - equal(icon.codingScheme, exp.codingScheme); - - equal(icon.body.length, exp.body.length); - for (let j = 0; j < icon.body.length; j++) { - equal(icon.body[j], exp.body[j]); - } - - equal(icon.clut.length, exp.clut.length); - for (let j = 0; j < icon.clut.length; j++) { - equal(icon.clut[j], exp.clut[j]); - } - } - }; - - record.readIMG(0, onsuccess); - } - - for (let i = 0; i< test_data.length; i++) { - do_test(test_data[i].img, test_data[i].iidf, test_data[i].expected); - } - run_next_test(); -}); - -/** - * Verify SimRecordHelper.readCphsInfo - */ -add_test(function test_read_cphs_info() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let cphsPDU = new Uint8Array(3); - - io.loadTransparentEF = function(options) { - if (cphsPDU) { - // Write data size - buf.writeInt32(cphsPDU.length * 2); - - // Write CPHS INFO - for (let i = 0; i < cphsPDU.length; i++) { - pduHelper.writeHexOctet(cphsPDU[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(cphsPDU.length * 2); - - if (options.callback) { - options.callback(options); - } - } else { - do_print("cphsPDU[] is not set."); - } - }; - - function do_test(cphsInfo, cphsSt) { - let onsuccess = false; - let onerror = false; - - delete RIL.iccInfoPrivate.cphsSt; - cphsPDU.set(cphsInfo); - recordHelper.readCphsInfo(() => { onsuccess = true; }, - () => { onerror = true; }); - - ok((cphsSt) ? onsuccess : onerror); - ok(!((cphsSt) ? onerror : onsuccess)); - if (cphsSt) { - equal(RIL.iccInfoPrivate.cphsSt.length, cphsSt.length); - for (let i = 0; i < cphsSt.length; i++) { - equal(RIL.iccInfoPrivate.cphsSt[i], cphsSt[i]); - } - } else { - equal(RIL.iccInfoPrivate.cphsSt, cphsSt); - } - } - - do_test([ - 0x01, // Phase 1 - 0xFF, // All available & activated - 0x03 // All available & activated - ], - [ - 0x3F, // All services except ONSF(bit 8-7) are available and activated. - 0x00 // INFO_NUM shall not be available & activated. - ]); - - do_test([ - 0x02, // Phase 2 - 0xFF, // All available & activated - 0x03 // All available & activated - ], - [ - 0xF3, // All services except ONSF are available and activated. - 0x03 // INFO_NUM shall not be available & activated. - ]); - - do_test([ - 0x03, // Phase 3 - 0xFF, // All available & activated - 0x03 // All available & activated - ], - undefined); // RIL.iccInfoPrivate.cphsSt shall be remained as 'undefined'. - - run_next_test(); -}); - -/** - * Verify SimRecordHelper.readMBDN/SimRecordHelper.readCphsMBN - */ -add_test(function test_read_voicemail_number() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - let postedMessage; - - worker.postMessage = function(message) { - postedMessage = message; - }; - - io.loadLinearFixedEF = function(options) { - let mbnData = [ - 0x56, 0x6F, 0x69, 0x63, 0x65, 0x6D, 0x61, 0x69, - 0x6C, 0xFF, // Alpha Identifier: Voicemail - 0x03, // Length of BCD number: 3 - 0x80, // TOA: Unknown - 0x11, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, // Dialing Number: 111 - 0xFF, // Capability/Configuration Record Identifier - 0xFF // Extension Record Identifier - ]; - - // Write data size - buf.writeInt32(mbnData.length * 2); - - // Write MBN - for (let i = 0; i < mbnData.length; i++) { - pduHelper.writeHexOctet(mbnData[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(mbnData.length * 2); - - options.recordSize = mbnData.length; - if (options.callback) { - options.callback(options); - } - }; - - function do_test(funcName, msgCount) { - postedMessage = null; - delete RIL.iccInfoPrivate.mbdn; - recordHelper[funcName](); - - equal("iccmbdn", postedMessage.rilMessageType); - equal("Voicemail", postedMessage.alphaId); - equal("111", postedMessage.number); - } - - do_test("readMBDN"); - do_test("readCphsMBN"); - - run_next_test(); -}); - -/** - * Verify the recovery from SimRecordHelper.readCphsMBN() if MBDN is not valid - * or is empty after SimRecordHelper.readMBDN(). - */ -add_test(function test_read_mbdn_recovered_from_cphs_mbn() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let pduHelper = context.GsmPDUHelper; - let recordHelper = context.SimRecordHelper; - let iccUtilsHelper = context.ICCUtilsHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - io.loadLinearFixedEF = function(options) { - let mbnData = [ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF - ]; - - // Write data size - buf.writeInt32(mbnData.length * 2); - - // Write MBN - for (let i = 0; i < mbnData.length; i++) { - pduHelper.writeHexOctet(mbnData[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(mbnData.length * 2); - - options.recordSize = mbnData.length; - if (options.callback) { - options.callback(options); - } - }; - - iccUtilsHelper.isCphsServiceAvailable = function(geckoService) { - return geckoService == "MBN"; - }; - - let isRecovered = false; - recordHelper.readCphsMBN = function(onComplete) { - isRecovered = true; - }; - - recordHelper.readMBDN(); - - equal(RIL.iccInfoPrivate.mbdn, undefined); - ok(isRecovered); - - run_next_test(); -}); - -/** - * Verify reading EF_PNN with different coding scheme. - */ -add_test(function test_pnn_with_different_coding_scheme() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [{ - // Cell Broadcast data coding scheme - "Test1" - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x1E, 0x03], - expectedResult: "Test1" - },{ - // UCS2 with 0x80 - "Test1" - pnn: [0x43, 0x0C, 0x90, 0x80, 0x00, 0x54, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31], - expectedResult: "Test1" - },{ - // UCS2 with 0x81 - "Mozilla\u694a" - pnn: [0x43, 0x0E, 0x90, 0x81, 0x08, 0xd2, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff], - expectedResult: "Mozilla\u694a" - },{ - // UCS2 with 0x82 - "Mozilla\u694a" - pnn: [0x43, 0x0F, 0x90, 0x82, 0x08, 0x69, 0x00, 0x4d, 0x6f, 0x7a, 0x69, 0x6c, 0x6c, 0x61, 0xca, 0xff, 0xff], - expectedResult: "Mozilla\u694a" - }]; - - function do_test_pnn(pnn, expectedResult) { - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - // Write data size. - buf.writeInt32(pnn.length * 2); - - // Write data. - for (let i = 0; i < pnn.length; i++) { - pduHelper.writeHexOctet(pnn[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(pnn.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - record.readPNN(); - - equal(ril.iccInfoPrivate.PNN[0].fullName, expectedResult); - // Reset PNN info for next test - ril.iccInfoPrivate.PNN = null; - } - - ril.appType = CARD_APPTYPE_SIM; - for (let i = 0; i < test_data.length; i++) { - do_test_pnn(test_data[i].pnn, test_data[i].expectedResult); - } - - run_next_test(); -}); - -/** - * Verify reading EF_PNN with different content. - */ -add_test(function test_pnn_with_different_content() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let record = context.SimRecordHelper; - let pduHelper = context.GsmPDUHelper; - let ril = context.RIL; - let buf = context.Buf; - let io = context.ICCIOHelper; - - let test_data = [{ - // [0]: {"fullName":"Test1","shortName":"Test1"} - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x1E, 0x03, - 0x45, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x1E, 0x03], - expectedResult: {"fullName": "Test1","shortName": "Test1"} - },{ - // [1]: {"fullName":"Test2"} - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x2E, 0x03], - expectedResult: {"fullName": "Test2"} - },{ - // [2]: undefined - pnn: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], - },{ - // [3]: {"fullName": "Test4"} - pnn: [0x43, 0x06, 0x85, 0xD4, 0xF2, 0x9C, 0x4E, 0x03], - expectedResult: {"fullName": "Test4"} - },{ - // [4]: undefined - pnn: [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], - }]; - - function do_test_pnn() { - ril.iccIO = function fakeIccIO(options) { - let index = options.p1 - 1; - let pnn = test_data[index].pnn; - - // Write data size. - buf.writeInt32(pnn.length * 2); - - // Write data. - for (let i = 0; i < pnn.length; i++) { - pduHelper.writeHexOctet(pnn[i]); - } - - // Write string delimiter. - buf.writeStringDelimiter(pnn.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - options.p1 = 1; - options.totalRecords = test_data.length; - - ril.iccIO(options); - }; - - record.readPNN(); - - equal(test_data.length, ril.iccInfoPrivate.PNN.length); - for (let i = 0; i < test_data.length; i++) { - if (test_data[i].expectedResult) { - equal(test_data[i].expectedResult.fullName, - ril.iccInfoPrivate.PNN[i].fullName); - equal(test_data[i].expectedResult.shortName, - ril.iccInfoPrivate.PNN[i].shortName); - } else { - equal(test_data[i].expectedResult, ril.iccInfoPrivate.PNN[i]); - } - } - } - - ril.appType = CARD_APPTYPE_SIM; - do_test_pnn(); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_ruim.js b/dom/system/gonk/tests/test_ril_worker_ruim.js deleted file mode 100644 index 0ddc10f29..000000000 --- a/dom/system/gonk/tests/test_ril_worker_ruim.js +++ /dev/null @@ -1,328 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify RUIM Service. - */ -add_test(function test_is_ruim_service_available() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - context.RIL._isCdma = true; - context.RIL.appType = CARD_APPTYPE_RUIM; - - function test_table(cst, geckoService, enabled) { - context.RIL.iccInfoPrivate.cst = cst; - equal(context.ICCUtilsHelper.isICCServiceAvailable(geckoService), - enabled); - } - - test_table([0x0, 0x0, 0x0, 0x0, 0x03], "SPN", true); - test_table([0x0, 0x0, 0x0, 0x03, 0x0], "SPN", false); - test_table([0x0, 0x0C, 0x0, 0x0, 0x0], "ENHANCED_PHONEBOOK", true); - test_table([0x0, 0x0, 0x0, 0x0, 0x0], "ENHANCED_PHONEBOOK", false); - - run_next_test(); -}); - -/** - * Verify EF_PATH for RUIM file. - */ -add_test(function test_ruim_file_path_id() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCFileHelper = context.ICCFileHelper; - - RIL.appType = CARD_APPTYPE_RUIM; - equal(ICCFileHelper.getEFPath(ICC_EF_CSIM_CST), - EF_PATH_MF_SIM + EF_PATH_DF_CDMA); - - run_next_test(); -}); - -add_test(function test_fetch_ruim_recodes() { - let worker = newWorker(); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ruimHelper = context.RuimRecordHelper; - - function testFetchRuimRecordes(expectCalled) { - let ifCalled = []; - - ruimHelper.getIMSI_M = function() { - ifCalled.push("getIMSI_M"); - }; - - ruimHelper.readCST = function() { - ifCalled.push("readCST"); - }; - - ruimHelper.readCDMAHome = function() { - ifCalled.push("readCDMAHome"); - }; - - RIL.getCdmaSubscription = function() { - ifCalled.push("getCdmaSubscription"); - }; - - ruimHelper.fetchRuimRecords(); - - for (let i = 0; i < expectCalled.length; i++ ) { - if (ifCalled[i] != expectCalled[i]) { - do_print(expectCalled[i] + " is not called."); - ok(false); - } - } - } - - let expectCalled = ["getIMSI_M", "readCST", "readCDMAHome", - "getCdmaSubscription"]; - testFetchRuimRecordes(expectCalled); - - run_next_test(); -}); - -/** - * Verify RuimRecordHelper.decodeIMSIValue - */ -add_test(function test_decode_imsi_value() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - - function testDecodeImsiValue(encoded, length, expect) { - let decoded = context.RuimRecordHelper.decodeIMSIValue(encoded, length); - - equal(expect, decoded); - } - - testDecodeImsiValue( 99, 2, "00"); - testDecodeImsiValue( 90, 2, "01"); - testDecodeImsiValue( 19, 2, "20"); - testDecodeImsiValue( 23, 2, "34"); - testDecodeImsiValue(999, 3, "000"); - testDecodeImsiValue(990, 3, "001"); - testDecodeImsiValue(909, 3, "010"); - testDecodeImsiValue( 99, 3, "100"); - testDecodeImsiValue(901, 3, "012"); - testDecodeImsiValue( 19, 3, "120"); - testDecodeImsiValue( 91, 3, "102"); - testDecodeImsiValue(199, 3, "200"); - testDecodeImsiValue(123, 3, "234"); - testDecodeImsiValue(578, 3, "689"); - - run_next_test(); -}); - -/** - * Verify RuimRecordHelper.getIMSI_M - */ -add_test(function test_get_imsi_m() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function testDecodeImsi(encodedImsi, expectedImsi) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(encodedImsi.length * 2); - - // Write imsi - for (let i = 0; i < encodedImsi.length; i++) { - helper.writeHexOctet(encodedImsi[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(encodedImsi.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - context.RuimRecordHelper.getIMSI_M(); - let imsi = context.RIL.iccInfoPrivate.imsi; - - equal(expectedImsi, imsi) - } - - let imsi_1 = "466050081062861"; - testDecodeImsi([0x0, 0xe5, 0x03, 0xee, 0xca, 0x17, 0x5e, 0x80, 0x63, 0x01], imsi_1); - - let imsi_2 = "460038351175976"; - testDecodeImsi([0x0, 0xd4, 0x02, 0x61, 0x97, 0x01, 0x5c, 0x80, 0x67, 0x01], imsi_2); - - run_next_test(); -}); - -/** - * Verify RuimRecordHelper.readCDMAHome - */ -add_test(function test_read_cdmahome() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - io.loadLinearFixedEF = function fakeLoadLinearFixedEF(options) { - let cdmaHome = [0xc1, 0x34, 0xff, 0xff, 0x00]; - - // Write data size - buf.writeInt32(cdmaHome.length * 2); - - // Write cdma home file. - for (let i = 0; i < cdmaHome.length; i++) { - helper.writeHexOctet(cdmaHome[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(cdmaHome.length * 2); - - // We just have 1 test record. - - options.totalRecords = 1; - if (options.callback) { - options.callback(options); - } - }; - - function testCdmaHome(expectedSystemIds, expectedNetworkIds) { - context.RuimRecordHelper.readCDMAHome(); - let cdmaHome = context.RIL.cdmaHome; - for (let i = 0; i < expectedSystemIds.length; i++) { - equal(cdmaHome.systemId[i], expectedSystemIds[i]); - equal(cdmaHome.networkId[i], expectedNetworkIds[i]); - } - equal(cdmaHome.systemId.length, expectedSystemIds.length); - equal(cdmaHome.networkId.length, expectedNetworkIds.length); - } - - testCdmaHome([13505], [65535]); - - run_next_test(); -}); - -/** - * Verify reading CDMA EF_SPN - */ -add_test(function test_read_cdmaspn() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - let io = context.ICCIOHelper; - - function testReadSpn(file, expectedSpn, expectedDisplayCondition) { - io.loadTransparentEF = function fakeLoadTransparentEF(options) { - // Write data size - buf.writeInt32(file.length * 2); - - // Write file. - for (let i = 0; i < file.length; i++) { - helper.writeHexOctet(file[i]); - } - - // Write string delimiter - buf.writeStringDelimiter(file.length * 2); - - if (options.callback) { - options.callback(options); - } - }; - - context.RuimRecordHelper.readSPN(); - equal(context.RIL.iccInfo.spn, expectedSpn); - equal(context.RIL.iccInfoPrivate.spnDisplayCondition, - expectedDisplayCondition); - } - - testReadSpn([0x01, 0x04, 0x06, 0x4e, 0x9e, 0x59, 0x2a, 0x96, - 0xfb, 0x4f, 0xe1, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff], - String.fromCharCode(0x4e9e) + - String.fromCharCode(0x592a) + - String.fromCharCode(0x96fb) + - String.fromCharCode(0x4fe1), - 0x1); - - // Test when there's no tailing 0xff in spn string. - testReadSpn([0x01, 0x04, 0x06, 0x4e, 0x9e, 0x59, 0x2a, 0x96, - 0xfb, 0x4f, 0xe1], - String.fromCharCode(0x4e9e) + - String.fromCharCode(0x592a) + - String.fromCharCode(0x96fb) + - String.fromCharCode(0x4fe1), - 0x1); - - run_next_test(); -}); - -/** - * Verify display condition for CDMA. - */ -add_test(function test_cdma_spn_display_condition() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - let RIL = context.RIL; - let ICCUtilsHelper = context.ICCUtilsHelper; - - // Set cdma. - RIL._isCdma = true; - - // Test updateDisplayCondition runs before any of SIM file is ready. - equal(ICCUtilsHelper.updateDisplayCondition(), true); - equal(RIL.iccInfo.isDisplayNetworkNameRequired, true); - equal(RIL.iccInfo.isDisplaySpnRequired, false); - - // Test with value. - function testDisplayCondition(ruimDisplayCondition, - homeSystemIds, homeNetworkIds, - currentSystemId, currentNetworkId, - expectUpdateDisplayCondition, - expectIsDisplaySPNRequired) { - RIL.iccInfoPrivate.spnDisplayCondition = ruimDisplayCondition; - RIL.cdmaHome = { - systemId: homeSystemIds, - networkId: homeNetworkIds - }; - RIL.voiceRegistrationState.cell = { - cdmaSystemId: currentSystemId, - cdmaNetworkId: currentNetworkId - }; - - equal(ICCUtilsHelper.updateDisplayCondition(), expectUpdateDisplayCondition); - equal(RIL.iccInfo.isDisplayNetworkNameRequired, false); - equal(RIL.iccInfo.isDisplaySpnRequired, expectIsDisplaySPNRequired); - }; - - // SPN is not required when ruimDisplayCondition is false. - testDisplayCondition(0x0, [123], [345], 123, 345, true, false); - - // System id and network id are all match. - testDisplayCondition(0x1, [123], [345], 123, 345, true, true); - - // Network is 65535, we should only need to match system id. - testDisplayCondition(0x1, [123], [65535], 123, 345, false, true); - - // Not match. - testDisplayCondition(0x1, [123], [456], 123, 345, true, false); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms.js b/dom/system/gonk/tests/test_ril_worker_sms.js deleted file mode 100644 index 7c1b972a7..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms.js +++ /dev/null @@ -1,273 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gSmsSegmentHelper", function() { - let ns = {}; - Cu.import("resource://gre/modules/SmsSegmentHelper.jsm", ns); - return ns.SmsSegmentHelper; -}); - -const ESCAPE = "\uffff"; -const RESCTL = "\ufffe"; - -function run_test() { - run_next_test(); -} - -/** - * Verify receiving SMS-DELIVERY messages - */ - -function hexToNibble(nibble) { - nibble &= 0x0f; - if (nibble < 10) { - nibble += 48; // ASCII '0' - } else { - nibble += 55; // ASCII 'A' - } - return nibble; -} - -function pduToParcelData(pdu) { - let dataLength = 4 + pdu.length * 4 + 4; - let data = new Uint8Array(dataLength); - let offset = 0; - - // String length - data[offset++] = pdu.length & 0xFF; - data[offset++] = (pdu.length >> 8) & 0xFF; - data[offset++] = (pdu.length >> 16) & 0xFF; - data[offset++] = (pdu.length >> 24) & 0xFF; - - // PDU data - for (let i = 0; i < pdu.length; i++) { - let hi = (pdu[i] >>> 4) & 0x0F; - let lo = pdu[i] & 0x0F; - - data[offset++] = hexToNibble(hi); - data[offset++] = 0; - data[offset++] = hexToNibble(lo); - data[offset++] = 0; - } - - // String delimitor - data[offset++] = 0; - data[offset++] = 0; - data[offset++] = 0; - data[offset++] = 0; - - return data; -} - -function compose7bitPdu(lst, sst, data, septets) { - if ((lst == 0) && (sst == 0)) { - return [0x00, // SMSC - PDU_MTI_SMS_DELIVER, // firstOctet - 1, 0x00, 0, // senderAddress - 0x00, // protocolIdentifier - PDU_DCS_MSG_CODING_7BITS_ALPHABET, // dataCodingScheme - 0, 0, 0, 0, 0, 0, 0, // y m d h m s tz - septets] // userDataLength - .concat(data); - } - - return [0x00, // SMSC - PDU_MTI_SMS_DELIVER | PDU_UDHI, // firstOctet - 1, 0x00, 0, // senderAddress - 0x00, // protocolIdentifier - PDU_DCS_MSG_CODING_7BITS_ALPHABET, // dataCodingScheme - 0, 0, 0, 0, 0, 0, 0, // y m d h m s tz - 8 + septets, // userDataLength - 6, // user data header length - PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT, 1, lst, // PDU_IEI_NATIONAL_LANGUAGE_LOCKING_SHIFT - PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT, 1, sst] // PDU_IEI_NATIONAL_LANGUAGE_SINGLE_SHIFT - .concat(data); -} - -function composeUcs2Pdu(rawBytes) { - return [0x00, // SMSC - PDU_MTI_SMS_DELIVER, // firstOctet - 1, 0x00, 0, // senderAddress - 0x00, // protocolIdentifier - PDU_DCS_MSG_CODING_16BITS_ALPHABET, // dataCodingScheme - 0, 0, 0, 0, 0, 0, 0, // y m d h m s tz - rawBytes.length] // userDataLength - .concat(rawBytes); -} - -function newSmsParcel(pdu) { - return newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_NEW_SMS, - pduToParcelData(pdu)); -} - -function removeSpecialChar(str, needle) { - for (let i = 0; i < needle.length; i++) { - let pos; - while ((pos = str.indexOf(needle[i])) >= 0) { - str = str.substring(0, pos) + str.substring(pos + 1); - } - } - return str; -} - -function newWriteHexOctetAsUint8Worker() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - context.GsmPDUHelper.writeHexOctet = function(value) { - context.Buf.writeUint8(value); - }; - - return worker; -} - -function add_test_receiving_sms(expected, pdu) { - add_test(function test_receiving_sms() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - do_print("fullBody: " + message.fullBody); - equal(expected, message.fullBody) - } - }); - - do_print("expect: " + expected); - do_print("pdu: " + pdu); - worker.onRILMessage(0, newSmsParcel(pdu)); - - run_next_test(); - }); -} - -var test_receiving_7bit_alphabets__worker; -function test_receiving_7bit_alphabets(lst, sst) { - if (!test_receiving_7bit_alphabets__worker) { - test_receiving_7bit_alphabets__worker = newWriteHexOctetAsUint8Worker(); - } - let worker = test_receiving_7bit_alphabets__worker; - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = context.Buf; - - function get7bitRawBytes(expected) { - buf.outgoingIndex = 0; - helper.writeStringAsSeptets(expected, 0, lst, sst); - - let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex); - return Array.slice(subArray); - } - - let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst]; - let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst]; - - let text = removeSpecialChar(langTable + langShiftTable, ESCAPE + RESCTL); - for (let i = 0; i < text.length;) { - let len = Math.min(70, text.length - i); - let expected = text.substring(i, i + len); - let septets = - gSmsSegmentHelper.countGsm7BitSeptets(expected, langTable, langShiftTable); - let rawBytes = get7bitRawBytes(expected); - let pdu = compose7bitPdu(lst, sst, rawBytes, septets); - add_test_receiving_sms(expected, pdu); - - i += len; - } -} - -function test_receiving_ucs2_alphabets(text) { - let worker = test_receiving_7bit_alphabets__worker; - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - - function getUCS2RawBytes(expected) { - buf.outgoingIndex = 0; - context.GsmPDUHelper.writeUCS2String(expected); - - let subArray = buf.outgoingBytes.subarray(0, buf.outgoingIndex); - return Array.slice(subArray); - } - - for (let i = 0; i < text.length;) { - let len = Math.min(70, text.length - i); - let expected = text.substring(i, i + len); - let rawBytes = getUCS2RawBytes(expected); - let pdu = composeUcs2Pdu(rawBytes); - add_test_receiving_sms(expected, pdu); - - i += len; - } -} - -var ucs2str = ""; -for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) { - ucs2str += PDU_NL_LOCKING_SHIFT_TABLES[lst]; - for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) { - test_receiving_7bit_alphabets(lst, sst); - - if (lst == 0) { - ucs2str += PDU_NL_SINGLE_SHIFT_TABLES[sst]; - } - } -} -test_receiving_ucs2_alphabets(ucs2str); - -// Bug 820220: B2G SMS: wrong order and truncated content in multi-part messages -add_test(function test_sendSMS_UCS2_without_langIndex_langShiftIndex_defined() { - let worker = newWriteHexOctetAsUint8Worker(); - let context = worker.ContextPool._contexts[0]; - - context.Buf.sendParcel = function() { - // Each sendParcel() call represents one outgoing segment of a multipart - // SMS message. Here, we have the first segment send, so it's "Hello " - // only. - // - // 4(parcel size) + 4(request type) + 4(token) - // + 4(two messages) + 4(null SMSC) + 4(message string length) - // + 1(first octet) + 1(message reference) - // + 2(DA len, TOA) + 4(addr) - // + 1(pid) + 1(dcs) - // + 1(UDL) + 6(UDHL, type, len, ref, max, seq) - // + 12(2 * strlen("Hello ")) - // + 4(two delimitors) = 57 - // - // If we have additional 6(type, len, langIndex, type len, langShiftIndex) - // octets here, then bug 809553 is not fixed. - equal(this.outgoingIndex, 57); - - run_next_test(); - }; - - context.RIL.sendSMS({ - number: "1", - segmentMaxSeq: 2, - fullBody: "Hello World!", - dcs: PDU_DCS_MSG_CODING_16BITS_ALPHABET, - segmentRef16Bit: false, - userDataHeaderLength: 5, - requestStatusReport: true, - segments: [ - { - body: "Hello ", - encodedBodyLength: 12, - }, { - body: "World!", - encodedBodyLength: 12, - } - ], - }); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js b/dom/system/gonk/tests/test_ril_worker_sms_cdma.js deleted file mode 100644 index 85d0b6e0c..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_cdma.js +++ /dev/null @@ -1,298 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/* - * Helper function to covert a HEX string to a byte array. - * - * @param hexString - * A hexadecimal string of which the length is even. - */ -function hexStringToBytes(hexString) { - let bytes = []; - - let length = hexString.length; - - for (let i = 0; i < length; i += 2) { - bytes.push(Number.parseInt(hexString.substr(i, 2), 16)); - } - - return bytes; -} - -/* - * Helper function to covert a byte array to a HEX string. - * - * @param bytes - * Could be a regular byte array or Uint8Array. - */ -function bytesToHexString(bytes) { - let hexString = ""; - let hex; - - for (let i = 0; i < bytes.length; i++) { - hex = bytes[i].toString(16).toUpperCase(); - if (hex.length === 1) { - hexString += "0"; - } - hexString += hex; - } - - return hexString; -} - -/* - * Helper function to ecode Opaque UserData - * - * @param msg_type - * PDU_CDMA_MSG_TYPE_SUBMIT or PDU_CDMA_MSG_TYPE_DELIVER - * @param data - * The byte array of opaque data to be encoded. - */ -function encodeOpaqueUserData(bitBufferHelper, options) { - let bearerDataBuffer = []; - bitBufferHelper.startWrite(bearerDataBuffer); - - // Msg-Id - bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_MSG_ID, 8); - bitBufferHelper.writeBits(3, 8); - bitBufferHelper.writeBits(options.msg_type, 4); // MSG_TYPE - bitBufferHelper.writeBits(1, 16); // MSG_ID - bitBufferHelper.flushWithPadding(); // HEADER_IND (1) + RESERVED (3) - - // User Data - bitBufferHelper.writeBits(PDU_CDMA_MSG_USERDATA_BODY, 8); - let dataLength = options.data.length; - bitBufferHelper.writeBits(2 + dataLength, 8); // 2 bytes for MSG_ENCODING, NUM_FIELDS - bitBufferHelper.writeBits(PDU_CDMA_MSG_CODING_OCTET, 5); //MSG_ENCODING - // MSG_TYPE is omitted if MSG_ENCODING is CODING_OCTET - bitBufferHelper.writeBits(dataLength, 8); // NUM_FIELDS - for (let i = 0; i < dataLength; i++) { // CHARi - bitBufferHelper.writeBits(options.data[i], 8); - } - bitBufferHelper.flushWithPadding(); // RESERVED (3 filling bits) - - return bearerDataBuffer; -} - -function newSmsParcel(cdmaPduHelper, pdu) { - return newIncomingParcel(-1, - RESPONSE_TYPE_UNSOLICITED, - UNSOLICITED_RESPONSE_CDMA_NEW_SMS, - pduToParcelData(cdmaPduHelper, pdu)); -} - -/* - * Helper function to encode PDU into Parcel. - * See ril_cdma_sms.h for the structure definition of RIL_CDMA_SMS_Message - * - * @param teleservice - * The Teleservice-Id of this PDU. - * See PDU_CDMA_MSG_TELESERIVCIE_ID_XXX in ril_const.js. - * @param address - * The Orginating or Destinating address. - * @param bearerData - * The byte array of the encoded bearer data. - */ -function pduToParcelData(cdmaPduHelper, pdu) { - - let addrInfo = cdmaPduHelper.encodeAddr(pdu.address); - // Teleservice, isServicePresent, ServiceCategory, - // addrInfo {digitMode, numberMode, numberType, numberPlan, address.length, address} - // Sub Address - // bearerData length, bearerData. - let dataLength = 4 + 4 + 4 - + (5 + addrInfo.address.length) * 4 - + 3 * 4 - + 4 + pdu.bearerData.length * 4; - - let data = new Uint8Array(dataLength); - let offset = 0; - - function writeInt(value) { - data[offset++] = value & 0xFF; - data[offset++] = (value >> 8) & 0xFF; - data[offset++] = (value >> 16) & 0xFF; - data[offset++] = (value >> 24) & 0xFF; - } - - function writeByte(value) { - data[offset++] = value & 0xFF; - data[offset++] = 0; - data[offset++] = 0; - data[offset++] = 0; - } - - // Teleservice - writeInt(pdu.teleservice); - - // isServicePresent - writeByte(0); - - // ServiceCategory - writeInt(PDU_CDMA_MSG_CATEGORY_UNSPEC); - - // AddrInfo - writeByte(addrInfo.digitMode); - writeByte(addrInfo.numberMode); - writeByte(addrInfo.numberType); - writeByte(addrInfo.numberPlan); - let addressLength = addrInfo.address.length; - writeByte(addressLength); - for (let i = 0; i < addressLength; i++) { - writeByte(addrInfo.address[i]); - } - - // Subaddress - writeByte(0); - writeByte(0); - writeByte(0); - - // Bearer Data Length - dataLength = pdu.bearerData.length; - writeByte(dataLength); - - // Bearer Data - for (let i = 0; i < dataLength; i++) { - writeByte(pdu.bearerData[i]); - } - - return data; -} - -/** - * Verify CDMA SMS Delivery ACK Message. - */ -add_test(function test_processCdmaSmsStatusReport() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - function test_StatusReport(errorClass, msgStatus) { - let msgId = 0; - let sentSmsMap = context.RIL._pendingSentSmsMap; - - sentSmsMap[msgId] = {}; - - let message = { - SMSC: "", - mti: 0, - udhi: 0, - sender: "0987654321", - recipient: null, - pid: PDU_PID_DEFAULT, - epid: PDU_PID_DEFAULT, - dcs: 0, - mwi: null, - replace: false, - header: null, - body: "Status: Sent, Dest: 0987654321", - data: null, - timestamp: new Date().valueOf(), - language: null, - status: null, - scts: null, - dt: null, - encoding: PDU_CDMA_MSG_CODING_7BITS_ASCII, - messageClass: GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - messageType: PDU_CDMA_MSG_TYPE_P2P, - serviceCategory: 0, - subMsgType: PDU_CDMA_MSG_TYPE_DELIVER_ACK, - msgId: msgId, - errorClass: errorClass, - msgStatus: msgStatus - }; - - context.RIL._processCdmaSmsStatusReport(message); - - let postedMessage = workerHelper.postedMessage; - - // Check if pending token is removed. - ok((errorClass === 2) ? !!sentSmsMap[msgId] : !sentSmsMap[msgId]); - - // Check the response message accordingly. - if (errorClass === -1) { - // Check if the report is treated as normal incoming SMS - equal("sms-received", postedMessage.rilMessageType); - } else if (errorClass === 2) { - // Do nothing. - } else { - // Check Delivery Status - if (errorClass === 0) { - equal(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_SUCCESS); - } else { - equal(postedMessage.deliveryStatus, GECKO_SMS_DELIVERY_STATUS_ERROR); - } - } - } - - test_StatusReport(-1, -1); // Message Status Sub-parameter is absent. - test_StatusReport(0, 0); // 00|000000: no error|Message accepted - test_StatusReport(2, 4); // 10|000100: temporary condition|Network congestion - test_StatusReport(3, 5); // 11|000101: permanent condition|Network error - - run_next_test(); -}); - -/** - * Verify WAP Push over CDMA SMS Message. - */ -add_test(function test_processCdmaSmsWapPush() { - let workerHelper = newInterceptWorker(), - worker = workerHelper.worker, - context = worker.ContextPool._contexts[0], - bitBufferHelper = context.BitBufferHelper, - cdmaPduHelper = context.CdmaPDUHelper; - - function test_CdmaSmsWapPdu(wdpData, reversed) { - let orig_address = "0987654321", - hexString, - fullDataHexString = ""; - - for (let i = 0; i < wdpData.length; i++) { - let dataIndex = (reversed) ? (wdpData.length - i - 1) : i; - hexString = "00"; // MSG_TYPE - hexString += bytesToHexString([wdpData.length]); // TOTAL_SEG - hexString += bytesToHexString([dataIndex]); // SEG_NUM (zero-based) - if ((dataIndex === 0)) { - hexString += "23F00B84"; // SOURCE_PORT, DEST_PORT for 1st segment - } - hexString += wdpData[dataIndex]; // WDP DATA - - do_print("hexString: " + hexString); - - fullDataHexString += wdpData[i]; - - let pdu = { - teleservice: PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, - address: orig_address, - bearerData: encodeOpaqueUserData(bitBufferHelper, - { msg_type: PDU_CDMA_MSG_TYPE_DELIVER, - data: hexStringToBytes(hexString) }) - }; - - worker.onRILMessage(0, newSmsParcel(cdmaPduHelper, pdu)); - } - - let postedMessage = workerHelper.postedMessage; - - do_print("fullDataHexString: " + fullDataHexString); - - equal("sms-received", postedMessage.rilMessageType); - equal(PDU_CDMA_MSG_TELESERIVCIE_ID_WAP, postedMessage.teleservice); - equal(orig_address, postedMessage.sender); - equal(0x23F0, postedMessage.header.originatorPort); - equal(0x0B84, postedMessage.header.destinationPort); - equal(fullDataHexString, bytesToHexString(postedMessage.data)); - } - - // Verify Single WAP PDU - test_CdmaSmsWapPdu(["000102030405060708090A0B0C0D0E0F"]); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js b/dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js deleted file mode 100644 index 276728f2f..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_cdmapduhelper.js +++ /dev/null @@ -1,210 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify CdmaPDUHelper#encodeUserDataReplyOption. - */ -add_test(function test_CdmaPDUHelper_encodeUserDataReplyOption() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let testDataBuffer = []; - context.BitBufferHelper.startWrite(testDataBuffer); - - let helper = context.CdmaPDUHelper; - helper.encodeUserDataReplyOption({requestStatusReport: true}); - - let expectedDataBuffer = [PDU_CDMA_MSG_USERDATA_REPLY_OPTION, 0x01, 0x40]; - - equal(testDataBuffer.length, expectedDataBuffer.length); - - for (let i = 0; i < expectedDataBuffer.length; i++) { - equal(testDataBuffer[i], expectedDataBuffer[i]); - } - - run_next_test(); -}); - -/** - * Verify CdmaPDUHelper#cdma_decodeUserDataMsgStatus. - */ -add_test(function test_CdmaPDUHelper_decodeUserDataMsgStatus() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let helper = context.CdmaPDUHelper; - function test_MsgStatus(octet) { - let testDataBuffer = [octet]; - context.BitBufferHelper.startRead(testDataBuffer); - let result = helper.decodeUserDataMsgStatus(); - - equal(result.errorClass, octet >>> 6); - equal(result.msgStatus, octet & 0x3F); - } - - // 00|000000: no error|Message accepted - test_MsgStatus(0x00); - - // 10|000100: temporary condition|Network congestion - test_MsgStatus(0x84); - - // 11|000101: permanent condition|Network error - test_MsgStatus(0xC5); - - run_next_test(); -}); - -/** - * Verify CdmaPDUHelper#decodeCdmaPDUMsg. - * - encoding by shift-jis - */ -add_test(function test_CdmaPDUHelper_decodeCdmaPDUMsg_Shift_jis() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - let context = worker.ContextPool._contexts[0]; - - let helper = context.CdmaPDUHelper; - function test_decodePDUMsg(testDataBuffer, expected, encoding, msgType, msgBodySize) { - context.BitBufferHelper.startRead(testDataBuffer); - let result = helper.decodeCdmaPDUMsg(encoding, msgType, msgBodySize); - equal(result, expected); - } - - // Shift-JIS has 1 byte and 2 byte code for one character and has some types of characters: - // Hiragana, Kanji, Katakana(fullwidth, halfwidth)... - // This test is a combination of 1 byte and 2 byte code and types of characters. - - // test case 1 - let testDataBuffer1 = [0x82, 0x58, 0x33, 0x41, 0x61, 0x33, 0x82, 0x60, - 0x82, 0x81, 0x33, 0xB1, 0xAF, 0x33, 0x83, 0x41, - 0x83, 0x96, 0x33, 0x82, 0xA0, 0x33, 0x93, 0xFA, - 0x33, 0x3A, 0x3C, 0x33, 0x81, 0x80, 0x81, 0x8E, - 0x33, 0x31, 0x82, 0x51, 0x41, 0x61, 0x82, 0x51, - 0x82, 0x60, 0x82, 0x81, 0x82, 0x51, 0xB1, 0xAF, - 0x82, 0x51, 0x83, 0x41, 0x83, 0x96, 0x82, 0x51, - 0x82, 0xA0, 0x82, 0x51, 0x93, 0xFA, 0x82, 0x51, - 0x3A, 0x3C, 0x82, 0x51, 0x81, 0x80, 0x81, 0x8E, - 0x82, 0x51]; - - test_decodePDUMsg( - testDataBuffer1, - "\uFF19\u0033\u0041\u0061\u0033\uFF21\uFF41\u0033\uFF71\uFF6F\u0033\u30A2\u30F6\u0033\u3042\u0033\u65E5\u0033\u003A\u003C\u0033\u00F7\u2103\u0033\u0031\uFF12\u0041\u0061\uFF12\uFF21\uFF41\uFF12\uFF71\uFF6F\uFF12\u30A2\u30F6\uFF12\u3042\uFF12\u65E5\uFF12\u003A\u003C\uFF12\u00F7\u2103\uFF12", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer1.length - ); - - // test case 2 - let testDataBuffer2 = [0x31, 0x51, 0x63, 0x82, 0x58, 0x51, 0x63, 0x82, - 0x60, 0x82, 0x81, 0x51, 0x63, 0xB1, 0xAF, 0x51, - 0x63, 0x83, 0x41, 0x83, 0x96, 0x51, 0x63, 0x82, - 0xA0, 0x51, 0x63, 0x93, 0xFA, 0x51, 0x63, 0x3A, - 0x3C, 0x51, 0x63, 0x81, 0x80, 0x81, 0x8E, 0x51, - 0x63, 0x31, 0x82, 0x70, 0x82, 0x85, 0x82, 0x58, - 0x82, 0x70, 0x82, 0x85, 0x41, 0x61, 0x82, 0x70, - 0x82, 0x85, 0xB1, 0xAF, 0x82, 0x70, 0x82, 0x85, - 0x83, 0x41, 0x83, 0x96, 0x82, 0x70, 0x82, 0x85, - 0x82, 0xA0, 0x82, 0x70, 0x82, 0x85, 0x93, 0xFA, - 0x82, 0x70, 0x82, 0x85, 0x3A, 0x3C, 0x82, 0x70, - 0x82, 0x85, 0x81, 0x80, 0x81, 0x8E, 0x82, 0x70, - 0x82, 0x85]; - - test_decodePDUMsg( - testDataBuffer2, - "\u0031\u0051\u0063\uFF19\u0051\u0063\uFF21\uFF41\u0051\u0063\uFF71\uFF6F\u0051\u0063\u30A2\u30F6\u0051\u0063\u3042\u0051\u0063\u65E5\u0051\u0063\u003A\u003C\u0051\u0063\u00F7\u2103\u0051\u0063\u0031\uFF31\uFF45\uFF19\uFF31\uFF45\u0041\u0061\uFF31\uFF45\uFF71\uFF6F\uFF31\uFF45\u30A2\u30F6\uFF31\uFF45\u3042\uFF31\uFF45\u65E5\uFF31\uFF45\u003A\u003C\uFF31\uFF45\u00F7\u2103\uFF31\uFF45", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer2.length - ); - - // test case 3 - let testDataBuffer3 = [0x31, 0xC2, 0xDF, 0x82, 0x58, 0xC2, 0xDF, 0x41, - 0x61, 0xC2, 0xDF, 0x82, 0x60, 0x82, 0x81, 0xC2, - 0xDF, 0x83, 0x41, 0x83, 0x96, 0xC2, 0xDF, 0x82, - 0xA0, 0xC2, 0xDF, 0x93, 0xFA, 0xC2, 0xDF, 0x3A, - 0x3C, 0xC2, 0xDF, 0x81, 0x80, 0x81, 0x8E, 0xC2, - 0xDF, 0x31, 0x83, 0x51, 0x83, 0x87, 0x82, 0x58, - 0x83, 0x51, 0x83, 0x87, 0x41, 0x61, 0x83, 0x51, - 0x83, 0x87, 0x82, 0x60, 0x82, 0x81, 0x83, 0x51, - 0x83, 0x87, 0xB1, 0xAF, 0x83, 0x51, 0x83, 0x87, - 0x82, 0xA0, 0x83, 0x51, 0x83, 0x87, 0x93, 0xFA, - 0x83, 0x51, 0x83, 0x87, 0x3A, 0x3C, 0x83, 0x51, - 0x83, 0x87, 0x81, 0x80, 0x81, 0x8E, 0x83, 0x51, - 0x83, 0x87]; - - test_decodePDUMsg( - testDataBuffer3, - "\u0031\uFF82\uFF9F\uFF19\uFF82\uFF9F\u0041\u0061\uFF82\uFF9F\uFF21\uFF41\uFF82\uFF9F\u30A2\u30F6\uFF82\uFF9F\u3042\uFF82\uFF9F\u65E5\uFF82\uFF9F\u003A\u003C\uFF82\uFF9F\u00F7\u2103\uFF82\uFF9F\u0031\u30B2\u30E7\uFF19\u30B2\u30E7\u0041\u0061\u30B2\u30E7\uFF21\uFF41\u30B2\u30E7\uFF71\uFF6F\u30B2\u30E7\u3042\u30B2\u30E7\u65E5\u30B2\u30E7\u003A\u003C\u30B2\u30E7\u00F7\u2103\u30B2\u30E7", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer3.length - ); - - // test case 4 - let testDataBuffer4 = [0x31, 0x82, 0xB0, 0x82, 0x58, 0x82, 0xB0, 0x41, - 0x61, 0x82, 0xB0, 0x82, 0x60, 0x82, 0x81, 0x82, - 0xB0, 0xB1, 0xAF, 0x82, 0xB0, 0x83, 0x41, 0x83, - 0x96, 0x82, 0xB0, 0x93, 0xFA, 0x82, 0xB0, 0x3A, - 0x3C, 0x82, 0xB0, 0x81, 0x80, 0x81, 0x8E, 0x82, - 0xB0, 0x31, 0x88, 0xA4, 0x82, 0x58, 0x88, 0xA4, - 0x41, 0x61, 0x88, 0xA4, 0x82, 0x60, 0x82, 0x81, - 0x88, 0xA4, 0xB1, 0xAF, 0x88, 0xA4, 0x83, 0x41, - 0x83, 0x96, 0x88, 0xA4, 0x82, 0xA0, 0x88, 0xA4, - 0x3A, 0x3C, 0x88, 0xA4, 0x81, 0x80, 0x81, 0x8E, - 0x88, 0xA4]; - - test_decodePDUMsg( - testDataBuffer4, - "\u0031\u3052\uFF19\u3052\u0041\u0061\u3052\uFF21\uFF41\u3052\uFF71\uFF6F\u3052\u30A2\u30F6\u3052\u65E5\u3052\u003A\u003C\u3052\u00F7\u2103\u3052\u0031\u611B\uFF19\u611B\u0041\u0061\u611B\uFF21\uFF41\u611B\uFF71\uFF6F\u611B\u30A2\u30F6\u611B\u3042\u611B\u003A\u003C\u611B\u00F7\u2103\u611B", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer4.length - ); - - // test case 5 - let testDataBuffer5 = [0x31, 0x40, 0x82, 0x58, 0x40, 0x41, 0x61, 0x40, - 0x82, 0x60, 0x82, 0x81, 0x40, 0xB1, 0xAF, 0x40, - 0x83, 0x41, 0x83, 0x96, 0x40, 0x82, 0xA0, 0x40, - 0x93, 0xFA, 0x40, 0x81, 0x80, 0x81, 0x8E, 0x40, - 0x31, 0x81, 0x9B, 0x82, 0x58, 0x81, 0x9B, 0x41, - 0x61, 0x81, 0x9B, 0x82, 0x60, 0x82, 0x81, 0x81, - 0x9B, 0xB1, 0xAF, 0x81, 0x9B, 0x83, 0x41, 0x83, - 0x96, 0x81, 0x9B, 0x82, 0xA0, 0x81, 0x9B, 0x93, - 0xFA, 0x81, 0x9B, 0x3A, 0x3C, 0x81, 0x9B]; - - test_decodePDUMsg( - testDataBuffer5, - "\u0031\u0040\uFF19\u0040\u0041\u0061\u0040\uFF21\uFF41\u0040\uFF71\uFF6F\u0040\u30A2\u30F6\u0040\u3042\u0040\u65E5\u0040\u00F7\u2103\u0040\u0031\u25CB\uFF19\u25CB\u0041\u0061\u25CB\uFF21\uFF41\u25CB\uFF71\uFF6F\u25CB\u30A2\u30F6\u25CB\u3042\u25CB\u65E5\u25CB\u003A\u003C\u25CB", - PDU_CDMA_MSG_CODING_SHIFT_JIS, - undefined, - testDataBuffer5.length - ); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js b/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js deleted file mode 100644 index f52c64cf8..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_gsmpduhelper.js +++ /dev/null @@ -1,282 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Verify GsmPDUHelper#readDataCodingScheme. - */ -add_test(function test_GsmPDUHelper_readDataCodingScheme() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - function test_dcs(dcs, encoding, messageClass, mwi) { - helper.readHexOctet = function() { - return dcs; - } - - let msg = {}; - helper.readDataCodingScheme(msg); - - equal(msg.dcs, dcs); - equal(msg.encoding, encoding); - equal(msg.messageClass, messageClass); - equal(msg.mwi == null, mwi == null); - if (mwi != null) { - equal(msg.mwi.active, mwi.active); - equal(msg.mwi.discard, mwi.discard); - equal(msg.mwi.msgCount, mwi.msgCount); - } - } - - // Group 00xx - // Bit 3 and 2 indicate the character set being used. - test_dcs(0x00, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x04, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x08, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x0C, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - // Bit 4, if set to 0, indicates that bits 1 to 0 are reserved and have no - // message class meaning. - test_dcs(0x01, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x02, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x03, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - // Bit 4, if set to 1, indicates that bits 1 to 0 have a message class meaning. - test_dcs(0x10, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - test_dcs(0x11, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]); - test_dcs(0x12, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]); - test_dcs(0x13, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]); - - // Group 01xx - test_dcs(0x50, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - - // Group 1000..1011: reserved - test_dcs(0x8F, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0x9F, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0xAF, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - test_dcs(0xBF, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL]); - - // Group 1100: Message Waiting Indication Group: Discard Message - // Bit 3 indicates Indication Sense: - test_dcs(0xC0, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: false, discard: true, msgCount: 0}); - test_dcs(0xC8, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: true, msgCount: -1}); - // Bit 2 is reserved, and set to 0: - test_dcs(0xCC, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: true, msgCount: -1}); - - // Group 1101: Message Waiting Indication Group: Store Message - // Bit 3 indicates Indication Sense: - test_dcs(0xD0, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: false, discard: false, msgCount: 0}); - test_dcs(0xD8, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - // Bit 2 is reserved, and set to 0: - test_dcs(0xDC, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - - // Group 1110: Message Waiting Indication Group: Store Message, UCS2 - // Bit 3 indicates Indication Sense: - test_dcs(0xE0, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: false, discard: false, msgCount: 0}); - test_dcs(0xE8, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - // Bit 2 is reserved, and set to 0: - test_dcs(0xEC, PDU_DCS_MSG_CODING_16BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_NORMAL], - {active: true, discard: false, msgCount: -1}); - - // Group 1111 - test_dcs(0xF0, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - test_dcs(0xF1, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]); - test_dcs(0xF2, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]); - test_dcs(0xF3, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]); - test_dcs(0xF4, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - test_dcs(0xF5, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_1]); - test_dcs(0xF6, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_2]); - test_dcs(0xF7, PDU_DCS_MSG_CODING_8BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_3]); - // Bit 3 is reserved and should be set to 0, but if it doesn't we should - // ignore it. - test_dcs(0xF8, PDU_DCS_MSG_CODING_7BITS_ALPHABET, - GECKO_SMS_MESSAGE_CLASSES[PDU_DCS_MSG_CLASS_0]); - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper#writeStringAsSeptets() padding bits handling. - */ -add_test(function test_GsmPDUHelper_writeStringAsSeptets() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - helper.resetOctetWritten = function() { - helper.octetsWritten = 0; - }; - helper.writeHexOctet = function() { - helper.octetsWritten++; - }; - - let base = "AAAAAAAA"; // Base string of 8 characters long - for (let len = 0; len < 8; len++) { - let str = base.substring(0, len); - - for (let paddingBits = 0; paddingBits < 8; paddingBits++) { - do_print("Verifying GsmPDUHelper.writeStringAsSeptets(" - + str + ", " + paddingBits + ", , )"); - helper.resetOctetWritten(); - helper.writeStringAsSeptets(str, paddingBits, PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT); - equal(Math.ceil(((len * 7) + paddingBits) / 8), - helper.octetsWritten); - } - } - - run_next_test(); -}); - -/** - * Verify that encoding with Spanish locking shift table generates the same - * septets as with GSM default alphabet table. - * - * Bug 1138841 - Incorrect Spanish national language locking shift table - * definition. - */ -add_test(function test_GsmPDUHelper_writeStringAsSeptets_spanish_fallback() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - let buf = []; - helper.writeHexOctet = function(octet) { - buf.push(octet); - } - - // Simple message string which is covered by GSM default alphabet. - let msg = "The quick brown fox jumps over the lazy dog"; - - // Encoded with GSM default alphabet. - helper.writeStringAsSeptets(msg, 0 /* paddingBits */, - PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT); - let octetsWithDefaultTable = buf; - buf = []; - - // Encoded with Spanish locking shift table. - helper.writeStringAsSeptets(msg, 0 /* paddingBits */, - PDU_NL_IDENTIFIER_SPANISH, PDU_NL_IDENTIFIER_SPANISH); - - // The length and content should be equal to what encoded with GSM default - // alphabet. - equal(octetsWithDefaultTable.length, buf.length); - for (let i = 0; i < buf.length; i++) { - equal(octetsWithDefaultTable[i], buf[i]); - } - - run_next_test(); -}); - -/** - * Verify GsmPDUHelper#readAddress - */ -add_test(function test_GsmPDUHelper_readAddress() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - function test_address(addrHex, addrString) { - let uint16Array = []; - let ix = 0; - for (let i = 0; i < addrHex.length; ++i) { - uint16Array[i] = addrHex[i].charCodeAt(); - } - - context.Buf.readUint16 = function(){ - if(ix >= uint16Array.length) { - do_throw("out of range in uint16Array"); - } - return uint16Array[ix++]; - } - let length = helper.readHexOctet(); - let parsedAddr = helper.readAddress(length); - equal(parsedAddr, addrString); - } - - // For AlphaNumeric - test_address("04D01100", "_@"); - test_address("04D01000", "\u0394@"); - - // Direct prepand - test_address("0B914151245584F6", "+14154255486"); - test_address("0E914151245584B633", "+14154255486#33"); - - // PDU_TOA_NATIONAL - test_address("0BA14151245584F6", "14154255486"); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js b/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js deleted file mode 100644 index 32bc5dc2a..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_nl_tables.js +++ /dev/null @@ -1,77 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -const ESCAPE = "\uffff"; -const RESCTL = "\ufffe"; -const LF = "\n"; -const CR = "\r"; -const SP = " "; -const FF = "\u000c"; - -function run_test() { - run_next_test(); -} - -/** - * Verify validity of the national language tables - */ -add_test(function test_nl_locking_shift_tables_validity() { - for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) { - do_print("Verifying PDU_NL_LOCKING_SHIFT_TABLES[" + lst + "]"); - - let table = PDU_NL_LOCKING_SHIFT_TABLES[lst]; - - // Make sure table length is 128, or it will break table lookup algorithm. - equal(table.length, 128); - - // Make sure special values are preserved. - equal(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE); - equal(table[PDU_NL_LINE_FEED], LF); - equal(table[PDU_NL_CARRIAGE_RETURN], CR); - equal(table[PDU_NL_SPACE], SP); - } - - run_next_test(); -}); - -add_test(function test_nl_single_shift_tables_validity() { - for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) { - do_print("Verifying PDU_NL_SINGLE_SHIFT_TABLES[" + sst + "]"); - - let table = PDU_NL_SINGLE_SHIFT_TABLES[sst]; - - // Make sure table length is 128, or it will break table lookup algorithm. - equal(table.length, 128); - - // Make sure special values are preserved. - equal(table[PDU_NL_EXTENDED_ESCAPE], ESCAPE); - equal(table[PDU_NL_PAGE_BREAK], FF); - equal(table[PDU_NL_RESERVED_CONTROL], RESCTL); - } - - run_next_test(); -}); - -add_test(function test_gsm_sms_strict_7bit_charmap_validity() { - let defaultTable = PDU_NL_LOCKING_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - let defaultShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[PDU_NL_IDENTIFIER_DEFAULT]; - for (let from in GSM_SMS_STRICT_7BIT_CHARMAP) { - let to = GSM_SMS_STRICT_7BIT_CHARMAP[from]; - do_print("Verifying GSM_SMS_STRICT_7BIT_CHARMAP[\"\\u0x" - + from.charCodeAt(0).toString(16) + "\"] => \"\\u" - + to.charCodeAt(0).toString(16) + "\""); - - // Make sure "from" is not in default table - equal(defaultTable.indexOf(from), -1); - equal(defaultShiftTable.indexOf(from), -1); - // Make sure "to" is in default table - if ((defaultTable.indexOf(to) < 0) - && (defaultShiftTable.indexOf(to) < 0)) { - equal(false, true); - } - } - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js b/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js deleted file mode 100644 index 2b29ac60e..000000000 --- a/dom/system/gonk/tests/test_ril_worker_sms_segment_info.js +++ /dev/null @@ -1,115 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyGetter(this, "gSmsSegmentHelper", function() { - let ns = {}; - Cu.import("resource://gre/modules/SmsSegmentHelper.jsm", ns); - return ns.SmsSegmentHelper; -}); - -const ESCAPE = "\uffff"; -const RESCTL = "\ufffe"; - -function run_test() { - run_next_test(); -} - -/** - * Verify SmsSegmentHelper#countGsm7BitSeptets() and - * GsmPDUHelper#writeStringAsSeptets() algorithm match each other. - */ -add_test(function test_SmsSegmentHelper__countGsm7BitSeptets() { - let worker = newWorker({ - postRILMessage: function(data) { - // Do nothing - }, - postMessage: function(message) { - // Do nothing - } - }); - - let context = worker.ContextPool._contexts[0]; - let helper = context.GsmPDUHelper; - helper.resetOctetWritten = function() { - helper.octetsWritten = 0; - }; - helper.writeHexOctet = function() { - helper.octetsWritten++; - }; - - function do_check_calc(str, expectedCalcLen, lst, sst, strict7BitEncoding, strToWrite) { - equal(expectedCalcLen, - gSmsSegmentHelper - .countGsm7BitSeptets(str, - PDU_NL_LOCKING_SHIFT_TABLES[lst], - PDU_NL_SINGLE_SHIFT_TABLES[sst], - strict7BitEncoding)); - - helper.resetOctetWritten(); - strToWrite = strToWrite || str; - helper.writeStringAsSeptets(strToWrite, 0, lst, sst); - equal(Math.ceil(expectedCalcLen * 7 / 8), helper.octetsWritten); - } - - // Test calculation encoded message length using both locking/single shift tables. - for (let lst = 0; lst < PDU_NL_LOCKING_SHIFT_TABLES.length; lst++) { - let langTable = PDU_NL_LOCKING_SHIFT_TABLES[lst]; - - let str = langTable.substring(0, PDU_NL_EXTENDED_ESCAPE) - + langTable.substring(PDU_NL_EXTENDED_ESCAPE + 1); - - for (let sst = 0; sst < PDU_NL_SINGLE_SHIFT_TABLES.length; sst++) { - let langShiftTable = PDU_NL_SINGLE_SHIFT_TABLES[sst]; - - // , should be ignored. - do_check_calc(ESCAPE + RESCTL, 0, lst, sst); - - // Characters defined in locking shift table should be encoded directly. - do_check_calc(str, str.length, lst, sst); - - let [str1, str2] = ["", ""]; - for (let i = 0; i < langShiftTable.length; i++) { - if ((i == PDU_NL_EXTENDED_ESCAPE) || (i == PDU_NL_RESERVED_CONTROL)) { - continue; - } - - let c = langShiftTable[i]; - if (langTable.indexOf(c) >= 0) { - str1 += c; - } else { - str2 += c; - } - } - - // Characters found in both locking/single shift tables should be - // directly encoded. - do_check_calc(str1, str1.length, lst, sst); - - // Characters found only in single shift tables should be encoded as - // , therefore doubles its original length. - do_check_calc(str2, str2.length * 2, lst, sst); - } - } - - // Bug 790192: support strict GSM SMS 7-Bit encoding - let str = "", strToWrite = "", gsmLen = 0; - for (let c in GSM_SMS_STRICT_7BIT_CHARMAP) { - str += c; - strToWrite += GSM_SMS_STRICT_7BIT_CHARMAP[c]; - if (PDU_NL_LOCKING_SHIFT_TABLES.indexOf(GSM_SMS_STRICT_7BIT_CHARMAP[c])) { - gsmLen += 1; - } else { - gsmLen += 2; - } - } - do_check_calc(str, gsmLen, - PDU_NL_IDENTIFIER_DEFAULT, PDU_NL_IDENTIFIER_DEFAULT, - true, strToWrite); - - run_next_test(); -}); - diff --git a/dom/system/gonk/tests/test_ril_worker_smsc_address.js b/dom/system/gonk/tests/test_ril_worker_smsc_address.js deleted file mode 100644 index c8c283b7c..000000000 --- a/dom/system/gonk/tests/test_ril_worker_smsc_address.js +++ /dev/null @@ -1,112 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -const SMSC_ATT = '+13123149810'; -const SMSC_ATT_TYPO = '+++1312@@@314$$$9,8,1,0'; -const SMSC_ATT_TEXT = '"+13123149810",145'; -const SMSC_ATT_TEXT_INCORRECT_TOA = '"+13123149810",129'; -const SMSC_ATT_PDU = '07913121139418F0'; -const SMSC_O2 = '+447802000332'; -const SMSC_O2_TEXT = '"+447802000332",145'; -const SMSC_O2_PDU = '0791448720003023'; -const SMSC_EMPTY = ''; -const SMSC_TON_UNKNOWN = '0407485455' -const SMSC_TON_UNKNOWN_TEXT = '"0407485455",129'; -const SMSC_TON_UNKNOWN_TEXT_NO_TOA = '"0407485455"'; -const SMSC_TON_UNKNOWN_TEXT_INVALID_TOA = '"0407485455",abc'; -const SMSC_TON_UNKNOWN_PDU = '06814070844555'; -const SMSC_EMPTY_PDU = 'FFFFFFFFFFFFFFFFFFFFFFFF'; -const SMSC_EMPTY_TEXT = ''; - -function run_test() { - run_next_test(); -} - -function setSmsc(context, smsc, ton, npi, expected) { - context.Buf.postRILMessage = function() { - equal(this.readString(), expected); - }; - - context.RIL.setSmscAddress({ - smscAddress: smsc, - typeOfNumber: ton, - numberPlanIdentification: npi - }); -} - -function getSmsc(worker, context, raw, smsc, ton, npi) { - worker.postMessage = function(message) { - equal(message.smscAddress, smsc); - equal(message.typeOfNumber, ton); - equal(message.numberPlanIdentification, npi); - } - - context.Buf.writeString(raw); - context.RIL[REQUEST_GET_SMSC_ADDRESS](0, { rilMessageType: "getSmscAddress"}); -} - -add_test(function test_setSmscAddress() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let parcelTypes = []; - context.Buf.newParcel = (type, options) => parcelTypes.push(type); - - // Test text mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "text"; - - setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_TEXT); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - // Test pdu mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "pdu"; - - setSmsc(context, SMSC_ATT, 1, 1, SMSC_ATT_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_O2, 1, 1, SMSC_O2_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_ATT_TYPO, 1, 1, SMSC_ATT_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - setSmsc(context, SMSC_TON_UNKNOWN, 0, 1, SMSC_TON_UNKNOWN_PDU); - equal(parcelTypes.pop(), REQUEST_SET_SMSC_ADDRESS); - - run_next_test(); -}); - -add_test(function test_getSmscAddress() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - - // Test text mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "text"; - getSmsc(worker, context, SMSC_ATT_TEXT, SMSC_ATT, 1, 1); - getSmsc(worker, context, SMSC_ATT_TEXT_INCORRECT_TOA, SMSC_ATT, 1, 1); - getSmsc(worker, context, SMSC_O2_TEXT, SMSC_O2, 1, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_TEXT, SMSC_TON_UNKNOWN, 0, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_TEXT_NO_TOA, SMSC_TON_UNKNOWN, 0, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_TEXT_INVALID_TOA, SMSC_TON_UNKNOWN, - 0, 1); - getSmsc(worker, context, SMSC_EMPTY_TEXT, SMSC_EMPTY, 0, 1); - - // Test pdu mode. - worker.RILQUIRKS_SMSC_ADDRESS_FORMAT = "pdu"; - getSmsc(worker, context, SMSC_ATT_PDU, SMSC_ATT, 1, 1); - getSmsc(worker, context, SMSC_O2_PDU, SMSC_O2, 1, 1); - getSmsc(worker, context, SMSC_TON_UNKNOWN_PDU, SMSC_TON_UNKNOWN, 0, 1); - getSmsc(worker, context, SMSC_EMPTY_PDU, SMSC_EMPTY, 0, 1); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_ssn.js b/dom/system/gonk/tests/test_ril_worker_ssn.js deleted file mode 100644 index ea0a2a599..000000000 --- a/dom/system/gonk/tests/test_ril_worker_ssn.js +++ /dev/null @@ -1,104 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_notification() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - function Call(callIndex, number) { - this.callIndex = callIndex; - this.number = number; - } - - Call.prototype = { - // Should use CALL_STATE_ACTIVE. - // Any new outgoing call (state = dialing or alerting) will be drop if there - // is no pending outgoing call created before. - state: CALL_STATE_ACTIVE, - //callIndex: 0, - toa: 0, - isMpty: false, - isMT: false, - als: 0, - isVoice: true, - isVoicePrivacy: false, - //number: null, - numberPresentation: 0, - name: null, - namePresentation: 0, - uusInfo: null - }; - - let oneCall = { - 0: new Call(0, '00000') - }; - - let twoCalls = { - 0: new Call(0, '00000'), - 1: new Call(1, '11111') - }; - - function testNotification(calls, code, number, resultNotification) { - - let testInfo = {calls: calls, code: code, number: number, - resultNotification: resultNotification}; - do_print('Test case info: ' + JSON.stringify(testInfo)); - - // Set current calls. - context.RIL.sendChromeMessage({ - rilMessageType: "currentCalls", - calls: calls - }); - - let notificationInfo = { - notificationType: 1, // MT - code: code, - index: 0, - type: 0, - number: number - }; - - context.RIL._processSuppSvcNotification(notificationInfo); - - let postedMessage = workerHelper.postedMessage; - equal(postedMessage.rilMessageType, 'suppSvcNotification'); - equal(postedMessage.number, number); - equal(postedMessage.notification, resultNotification); - - // Clear all existed calls. - context.RIL.sendChromeMessage({ - rilMessageType: "currentCalls", - calls: {} - }); - } - - testNotification(oneCall, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(oneCall, SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_RETRIEVED, null, - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_RESUMED); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, '00000', - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, '11111', - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - testNotification(twoCalls, SUPP_SVC_NOTIFICATION_CODE2_PUT_ON_HOLD, '22222', - GECKO_SUPP_SVC_NOTIFICATION_REMOTE_HELD); - - run_next_test(); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_stk.js b/dom/system/gonk/tests/test_ril_worker_stk.js deleted file mode 100644 index 49b914e89..000000000 --- a/dom/system/gonk/tests/test_ril_worker_stk.js +++ /dev/null @@ -1,1698 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -/** - * Helper function. - */ -function newUint8SupportOutgoingIndexWorker() { - let worker = newWorker(); - let index = 4; // index for read - let buf = [0, 0, 0, 0]; // Preserved parcel size - let context = worker.ContextPool._contexts[0]; - - context.Buf.writeUint8 = function(value) { - if (context.Buf.outgoingIndex >= buf.length) { - buf.push(value); - } else { - buf[context.Buf.outgoingIndex] = value; - } - - context.Buf.outgoingIndex++; - }; - - context.Buf.readUint8 = function() { - return buf[index++]; - }; - - context.Buf.seekIncoming = function(offset) { - index += offset; - }; - - worker.debug = do_print; - - return worker; -} - -// Test RIL requests related to STK. -/** - * Verify if RIL.sendStkTerminalProfile be called. - */ -add_test(function test_if_send_stk_terminal_profile() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let profileSend = false; - context.RIL.sendStkTerminalProfile = function(data) { - profileSend = true; - }; - - let iccStatus = { - gsmUmtsSubscriptionAppIndex: 0, - apps: [{ - app_state: CARD_APPSTATE_READY, - app_type: CARD_APPTYPE_USIM - }], - }; - worker.RILQUIRKS_SEND_STK_PROFILE_DOWNLOAD = false; - - context.RIL._processICCStatus(iccStatus); - - equal(profileSend, false); - - run_next_test(); -}); - -/** - * Verify RIL.sendStkTerminalProfile - */ -add_test(function test_send_stk_terminal_profile() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let ril = context.RIL; - let buf = context.Buf; - - ril.sendStkTerminalProfile(STK_SUPPORTED_TERMINAL_PROFILE); - - buf.seekIncoming(8); - let profile = buf.readString(); - for (let i = 0; i < STK_SUPPORTED_TERMINAL_PROFILE.length; i++) { - equal(parseInt(profile.substring(2 * i, 2 * i + 2), 16), - STK_SUPPORTED_TERMINAL_PROFILE[i]); - } - - run_next_test(); -}); - -/** - * Verify STK terminal response - */ -add_test(function test_stk_terminal_response() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 44 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(10)) - equal(this.readInt32(), 44); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_PROVIDE_LOCAL_INFO); - equal(pduHelper.readHexOctet(), STK_LOCAL_INFO_NNA); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Text - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 8); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_7BIT_PACKED); - equal(pduHelper.readSeptetsToString(7, 0, PDU_NL_IDENTIFIER_DEFAULT, - PDU_NL_IDENTIFIER_DEFAULT), "Mozilla"); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_PROVIDE_LOCAL_INFO, - commandQualifier: STK_LOCAL_INFO_NNA, - options: { - isPacked: true - } - }, - input: "Mozilla", - resultCode: STK_RESULT_OK - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET INPUT with empty string. - * - * @See |TERMINAL RESPONSE: GET INPUT 1.9.1A| of 27.22.4.3.1 GET INPUT (normal) - * in TS 102 384. - */ -add_test(function test_stk_terminal_response_get_input_empty_string() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 30 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(3)) - equal(this.readInt32(), 30); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INPUT); - equal(pduHelper.readHexOctet(), 0x00); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Text - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INPUT, - commandQualifier: 0x00, - options: { - minLength: 0, - maxLength: 1, - defaultText: "" - } - }, - input: "", - resultCode: STK_RESULT_OK - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET INPUT with 160 unpacked characters. - * - * @See |TERMINAL RESPONSE: GET INPUT 1.8.1| of 27.22.4.3.1 GET INPUT (normal) - * in TS 102 384. - */ -add_test(function test_stk_terminal_response_get_input_160_unpacked_characters() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - let iccPduHelper = context.ICCPDUHelper; - let TEST_TEXT_STRING = "***1111111111###" + - "***2222222222###" + - "***3333333333###" + - "***4444444444###" + - "***5555555555###" + - "***6666666666###" + - "***7777777777###" + - "***8888888888###" + - "***9999999999###" + - "***0000000000###"; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 352 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(164)) - equal(this.readInt32(), 352); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INPUT); - equal(pduHelper.readHexOctet(), 0x00); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Text - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - // C-TLV Length Encoding: 161 = 0x81 0xA1 - equal(pduHelper.readHexOctet(), 0x81); - equal(pduHelper.readHexOctet(), 0xA1); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT); - equal(iccPduHelper.read8BitUnpackedToString(160), TEST_TEXT_STRING); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INPUT, - commandQualifier: 0x00, - options: { - minLength: 160, - maxLength: 160, - text: TEST_TEXT_STRING - } - }, - input: TEST_TEXT_STRING, - resultCode: STK_RESULT_OK - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET_INKEY - NO_RESPONSE_FROM_USER with - * duration provided. - * - * @See |27.22.4.2.8 GET INKEY (Variable Time out)| in TS 102 384. - */ -add_test(function test_stk_terminal_response_get_inkey_no_response_from_user() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 32 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // DURATION(4)) - equal(this.readInt32(), 32); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INKEY); - equal(pduHelper.readHexOctet(), 0x00); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_NO_RESPONSE_FROM_USER); - - // Duration, Type-Length-Value(Time unit, Time interval) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DURATION); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_TIME_UNIT_SECOND); - equal(pduHelper.readHexOctet(), 10); - - run_next_test(); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INKEY, - commandQualifier: 0x00, - options: { - duration: { - timeUnit: STK_TIME_UNIT_SECOND, - timeInterval: 10 - }, - text: 'Enter "+"' - } - }, - resultCode: STK_RESULT_NO_RESPONSE_FROM_USER - }; - context.RIL.sendStkTerminalResponse(response); -}); - -/** - * Verify STK terminal response : GET_INKEY - YES/NO request - */ -add_test(function test_stk_terminal_response_get_inkey() { - function do_test(isYesNo) { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Size, 32 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(3) + - // TEXT LENGTH(4)) - equal(this.readInt32(), 32); - - // Command Details, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_GET_INKEY); - equal(pduHelper.readHexOctet(), 0x04); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_RESULT_OK); - - // Yes/No response - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_TEXT_STRING | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_TEXT_CODING_GSM_8BIT); - equal(pduHelper.readHexOctet(), isYesNo ? 0x01 : 0x00); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_GET_INKEY, - commandQualifier: 0x04, - options: { - isYesNoRequested: true - } - }, - isYesNo: isYesNo, - resultCode: STK_RESULT_OK - }; - - context.RIL.sendStkTerminalResponse(response); - }; - - // Test "Yes" response - do_test(true); - // Test "No" response - do_test(false); - - run_next_test(); -}); - -/** - * Verify STK terminal response with additional information. - */ -add_test(function test_stk_terminal_response_with_additional_info() { - function do_test(aInfo) { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_TERMINAL_RESPONSE); - - // Token : we don't care - this.readInt32(); - - // Data Length 26 = 2 * (TLV_COMMAND_DETAILS_SIZE(5) + - // TLV_DEVICE_ID_SIZE(4) + - // TLV_RESULT_SIZE(4)) - equal(this.readInt32(), 26); - - // Command Details, Type-Length-Value(commandNumber, typeOfCommand, commandQualifier) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_COMMAND_DETAILS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 3); - equal(pduHelper.readHexOctet(), 0x01); - equal(pduHelper.readHexOctet(), STK_CMD_DISPLAY_TEXT); - equal(pduHelper.readHexOctet(), 0x01); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Result, Type-Length-Value(General result, Additional information on result) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_RESULT | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS); - equal(pduHelper.readHexOctet(), aInfo); - }; - - let response = { - command: { - commandNumber: 0x01, - typeOfCommand: STK_CMD_DISPLAY_TEXT, - commandQualifier: 0x01, - options: { - isHighPriority: true - } - }, - resultCode: STK_RESULT_TERMINAL_CRNTLY_UNABLE_TO_PROCESS, - additionalInformation: aInfo - }; - - context.RIL.sendStkTerminalResponse(response); - }; - - do_test(0x01); // 'Screen is busy' - - run_next_test(); -}); - -// Test ComprehensionTlvHelper - -/** - * Verify ComprehensionTlvHelper.writeLocationInfoTlv - */ -add_test(function test_write_location_info_tlv() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let tlvHelper = context.ComprehensionTlvHelper; - - // Test with 2-digit mnc, and gsmCellId obtained from UMTS network. - let loc = { - mcc: "466", - mnc: "92", - gsmLocationAreaCode : 10291, - gsmCellId: 19072823 - }; - tlvHelper.writeLocationInfoTlv(loc); - - let tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - - let length = pduHelper.readHexOctet(); - equal(length, 9); - - let mcc_mnc = pduHelper.readSwappedNibbleBcdString(3); - equal(mcc_mnc, "46692"); - - let lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet(); - equal(lac, 10291); - - let cellId = (pduHelper.readHexOctet() << 24) | - (pduHelper.readHexOctet() << 16) | - (pduHelper.readHexOctet() << 8) | - (pduHelper.readHexOctet()); - equal(cellId, 19072823); - - // Test with 1-digit mnc, and gsmCellId obtained from GSM network. - loc = { - mcc: "466", - mnc: "02", - gsmLocationAreaCode : 10291, - gsmCellId: 65534 - }; - tlvHelper.writeLocationInfoTlv(loc); - - tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - - length = pduHelper.readHexOctet(); - equal(length, 7); - - mcc_mnc = pduHelper.readSwappedNibbleBcdString(3); - equal(mcc_mnc, "46602"); - - lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet(); - equal(lac, 10291); - - cellId = (pduHelper.readHexOctet() << 8) | (pduHelper.readHexOctet()); - equal(cellId, 65534); - - // Test with 3-digit mnc, and gsmCellId obtained from GSM network. - loc = { - mcc: "466", - mnc: "222", - gsmLocationAreaCode : 10291, - gsmCellId: 65534 - }; - tlvHelper.writeLocationInfoTlv(loc); - - tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - - length = pduHelper.readHexOctet(); - equal(length, 7); - - mcc_mnc = pduHelper.readSwappedNibbleBcdString(3); - equal(mcc_mnc, "466222"); - - lac = (pduHelper.readHexOctet() << 8) | pduHelper.readHexOctet(); - equal(lac, 10291); - - cellId = (pduHelper.readHexOctet() << 8) | (pduHelper.readHexOctet()); - equal(cellId, 65534); - - run_next_test(); -}); - -/** - * Verify ComprehensionTlvHelper.writeErrorNumber - */ -add_test(function test_write_disconnecting_cause() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let tlvHelper = context.ComprehensionTlvHelper; - - tlvHelper.writeCauseTlv(RIL_CALL_FAILCAUSE_TO_GECKO_CALL_ERROR[CALL_FAIL_BUSY]); - let tag = pduHelper.readHexOctet(); - equal(tag, COMPREHENSIONTLV_TAG_CAUSE | COMPREHENSIONTLV_FLAG_CR); - let len = pduHelper.readHexOctet(); - equal(len, 2); // We have one cause. - let standard = pduHelper.readHexOctet(); - equal(standard, 0x60); - let cause = pduHelper.readHexOctet(); - equal(cause, 0x80 | CALL_FAIL_BUSY); - - run_next_test(); -}); - -/** - * Verify ComprehensionTlvHelper.getSizeOfLengthOctets - */ -add_test(function test_get_size_of_length_octets() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let tlvHelper = context.ComprehensionTlvHelper; - - let length = 0x70; - equal(tlvHelper.getSizeOfLengthOctets(length), 1); - - length = 0x80; - equal(tlvHelper.getSizeOfLengthOctets(length), 2); - - length = 0x180; - equal(tlvHelper.getSizeOfLengthOctets(length), 3); - - length = 0x18000; - equal(tlvHelper.getSizeOfLengthOctets(length), 4); - - run_next_test(); -}); - -/** - * Verify ComprehensionTlvHelper.writeLength - */ -add_test(function test_write_length() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let tlvHelper = context.ComprehensionTlvHelper; - - let length = 0x70; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), length); - - length = 0x80; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), 0x81); - equal(pduHelper.readHexOctet(), length); - - length = 0x180; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), 0x82); - equal(pduHelper.readHexOctet(), (length >> 8) & 0xff); - equal(pduHelper.readHexOctet(), length & 0xff); - - length = 0x18000; - tlvHelper.writeLength(length); - equal(pduHelper.readHexOctet(), 0x83); - equal(pduHelper.readHexOctet(), (length >> 16) & 0xff); - equal(pduHelper.readHexOctet(), (length >> 8) & 0xff); - equal(pduHelper.readHexOctet(), length & 0xff); - - run_next_test(); -}); - -// Test Proactive commands. - -function test_stk_proactive_command(aOptions) { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - let stkFactory = context.StkCommandParamsFactory; - - let testPdu = aOptions.pdu; - let testTypeOfCommand = aOptions.typeOfCommand; - let testIcons = aOptions.icons; - let testFunc = aOptions.testFunc; - - if (testIcons) { - let ril = context.RIL; - ril.iccInfoPrivate.sst = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x30]; //IMG: 39 - ril.appType = CARD_APPTYPE_SIM; - - // skip asynchornous process in IconLoader.loadIcons(). - let iconLoader = context.IconLoader; - iconLoader.loadIcons = (recordNumbers, onsuccess, onerror) => { - onsuccess(testIcons); - }; - } - - for(let i = 0 ; i < testPdu.length; i++) { - pduHelper.writeHexOctet(testPdu[i]); - } - - let berTlv = berHelper.decode(testPdu.length); - let ctlvs = berTlv.value; - let ctlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs); - let cmdDetails = ctlv.value; - equal(cmdDetails.typeOfCommand, testTypeOfCommand); - - stkFactory.createParam(cmdDetails, ctlvs, (aResult) => { - cmdDetails.options = aResult; - testFunc(context, cmdDetails, ctlvs); - }); -} - -/** - * Verify Proactive command helper : searchForSelectedTags - */ -add_test(function test_stk_proactive_command_search_for_selected_tags() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - - let tag_test = [ - 0xD0, - 0x3E, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x31, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x32, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x33, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x34, - 0x85, 0x0A, 0x61, 0x6C, 0x70, 0x68, 0x61, 0x20, 0x69, 0x64, 0x20, 0x35, - 0x85, 0x00]; - - for (let i = 0; i < tag_test.length; i++) { - pduHelper.writeHexOctet(tag_test[i]); - } - - let berTlv = berHelper.decode(tag_test.length); - let selectedCtlvs = - stkHelper.searchForSelectedTags(berTlv.value, [COMPREHENSIONTLV_TAG_ALPHA_ID]); - let tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 1"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 2"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 3"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 4"); - - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - equal(tlv.value.identifier, "alpha id 5"); - - // emulate that the alpha identifier is provided and is a null data object, - // which is converted to an empty string in ICCPDUHelper. - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - strictEqual(tlv.value.identifier, ""); - - // emulate that the alpha identifier is not provided - tlv = selectedCtlvs.retrieve(COMPREHENSIONTLV_TAG_ALPHA_ID); - strictEqual(tlv, undefined); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Refresh - */ -add_test(function test_stk_proactive_command_refresh() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x10, - 0x81, 0x03, 0x01, 0x01, 0x01, - 0x82, 0x02, 0x81, 0x82, - 0x92, 0x05, 0x01, 0x3F, 0x00, 0x2F, 0xE2 - ], - typeOfCommand: STK_CMD_REFRESH, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let stkHelper = context.StkProactiveCmdHelper; - let ctlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_FILE_LIST, ctlvs); - equal(ctlv.value.fileList, "3F002FE2"); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Play Tone - */ -add_test(function test_stk_proactive_command_play_tone() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x1F, - 0x81, 0x03, 0x01, 0x20, 0x00, - 0x82, 0x02, 0x81, 0x03, - 0x85, 0x09, 0x44, 0x69, 0x61, 0x6C, 0x20, 0x54, 0x6F, 0x6E, 0x65, - 0x8E, 0x01, 0x01, - 0x84, 0x02, 0x01, 0x05, - 0x9E, 0x02, 0x00, 0x01 - ], - typeOfCommand: STK_CMD_PLAY_TONE, - icons: [1], - testFunc: (context, cmdDetails, ctlvs) => { - let playTone = cmdDetails.options; - - equal(playTone.text, "Dial Tone"); - equal(playTone.tone, STK_TONE_TYPE_DIAL_TONE); - equal(playTone.duration.timeUnit, STK_TIME_UNIT_SECOND); - equal(playTone.duration.timeInterval, 5); - equal(playTone.iconSelfExplanatory, true); - equal(playTone.icons, 1); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Poll Interval - */ -add_test(function test_stk_proactive_command_poll_interval() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0D, - 0x81, 0x03, 0x01, 0x03, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x84, 0x02, 0x01, 0x14 - ], - typeOfCommand: STK_CMD_POLL_INTERVAL, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let interval = cmdDetails.options; - - equal(interval.timeUnit, STK_TIME_UNIT_SECOND); - equal(interval.timeInterval, 0x14); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command: Display Text - */ -add_test(function test_stk_proactive_command_display_text() { - test_stk_proactive_command({ - pdu: [ - 0xd0, - 0x2c, - 0x81, 0x03, 0x01, 0x21, 0x80, - 0x82, 0x02, 0x81, 0x02, - 0x0d, 0x1d, 0x00, 0xd3, 0x30, 0x9b, 0xfc, 0x06, 0xc9, 0x5c, 0x30, 0x1a, - 0xa8, 0xe8, 0x02, 0x59, 0xc3, 0xec, 0x34, 0xb9, 0xac, 0x07, 0xc9, 0x60, - 0x2f, 0x58, 0xed, 0x15, 0x9b, 0xb9, 0x40, - 0x9e, 0x02, 0x00, 0x01 - ], - typeOfCommand: STK_CMD_DISPLAY_TEXT, - icons: [1], - testFunc: (context, cmdDetails, ctlvs) => { - let textMsg = cmdDetails.options; - - equal(textMsg.text, "Saldo 2.04 E. Validez 20/05/13. "); - equal(textMsg.iconSelfExplanatory, true); - equal(textMsg.icons, 1); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command: Set Up Event List. - */ -add_test(function test_stk_proactive_command_event_list() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0F, - 0x81, 0x03, 0x01, 0x05, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x99, 0x04, 0x00, 0x01, 0x02, 0x03 - ], - typeOfCommand: STK_CMD_SET_UP_EVENT_LIST, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let event = cmdDetails.options; - - equal(Array.isArray(event.eventList), true); - - for (let i = 0; i < event.eventList.length; i++) { - equal(event.eventList[i], i); - } - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Get Input - */ -add_test(function test_stk_proactive_command_get_input() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x22, - 0x81, 0x03, 0x01, 0x23, 0x8F, - 0x82, 0x02, 0x81, 0x82, - 0x8D, 0x05, 0x04, 0x54, 0x65, 0x78, 0x74, - 0x91, 0x02, 0x01, 0x10, - 0x17, 0x08, 0x04, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74, - 0x9E, 0x02, 0x00, 0x01 - ], - typeOfCommand: STK_CMD_GET_INPUT, - icons: [1], - testFunc: (context, cmdDetails, ctlvs) => { - let input = cmdDetails.options; - - equal(input.text, "Text"); - equal(input.isAlphabet, true); - equal(input.isUCS2, true); - equal(input.hideInput, true); - equal(input.isPacked, true); - equal(input.isHelpAvailable, true); - equal(input.minLength, 0x01); - equal(input.maxLength, 0x10); - equal(input.defaultText, "Default"); - equal(input.iconSelfExplanatory, true); - equal(input.icons, 1); - } - }); - - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x11, - 0x81, 0x03, 0x01, 0x23, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x8D, 0x00, - 0x91, 0x02, 0x01, 0x10, - 0x17, 0x00 - ], - typeOfCommand: STK_CMD_GET_INPUT, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let input = cmdDetails.options; - - equal(input.text, null); - equal(input.minLength, 0x01); - equal(input.maxLength, 0x10); - equal(input.defaultText, null); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : More Time - */ -add_test(function test_stk_proactive_command_more_time() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - - let more_time_1 = [ - 0xD0, - 0x09, - 0x81, 0x03, 0x01, 0x02, 0x00, - 0x82, 0x02, 0x81, 0x82]; - - for(let i = 0 ; i < more_time_1.length; i++) { - pduHelper.writeHexOctet(more_time_1[i]); - } - - let berTlv = berHelper.decode(more_time_1.length); - let ctlvs = berTlv.value; - let tlv = stkHelper.searchForTag(COMPREHENSIONTLV_TAG_COMMAND_DETAILS, ctlvs); - equal(tlv.value.commandNumber, 0x01); - equal(tlv.value.typeOfCommand, STK_CMD_MORE_TIME); - equal(tlv.value.commandQualifier, 0x00); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Select Item - */ -add_test(function test_stk_proactive_command_select_item() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x3D, - 0x81, 0x03, 0x01, 0x24, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x10, 0x15, 0x20, - 0x90, 0x01, 0x01, - 0x9E, 0x02, 0x00, 0x01, - 0x9F, 0x04, 0x00, 0x01, 0x02, 0x03 - ], - typeOfCommand: STK_CMD_SELECT_ITEM, - icons: [1, 1, 2, 3], - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.iconSelfExplanatory, true); - equal(menu.icons, 1); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[0].iconSelfExplanatory, true); - equal(menu.items[0].icons, 1); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[1].iconSelfExplanatory, true); - equal(menu.items[1].icons, 2); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.items[2].iconSelfExplanatory, true); - equal(menu.items[2].icons, 3); - equal(menu.nextActionList[0], STK_CMD_SET_UP_CALL); - equal(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER); - equal(menu.nextActionList[2], STK_CMD_PLAY_TONE); - equal(menu.defaultItem, 0x00); - } - }); - - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x33, - 0x81, 0x03, 0x01, 0x24, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x00, 0x15, 0x81, - 0x90, 0x01, 0x03 - ], - typeOfCommand: STK_CMD_SELECT_ITEM, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.nextActionList[0], STK_NEXT_ACTION_NULL); - equal(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER); - equal(menu.nextActionList[2], STK_NEXT_ACTION_END_PROACTIVE_SESSION); - equal(menu.defaultItem, 0x02); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Set Up Menu - */ -add_test(function test_stk_proactive_command_set_up_menu() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x3A, - 0x81, 0x03, 0x01, 0x25, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x10, 0x15, 0x20, - 0x9E, 0x02, 0x00, 0x01, - 0x9F, 0x04, 0x00, 0x01, 0x02, 0x03 - ], - typeOfCommand: STK_CMD_SET_UP_MENU, - icons: [1, 1, 2, 3], - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.iconSelfExplanatory, true); - equal(menu.icons, 1); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[0].iconSelfExplanatory, true); - equal(menu.items[0].icons, 1); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[1].iconSelfExplanatory, true); - equal(menu.items[1].icons, 2); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.items[2].iconSelfExplanatory, true); - equal(menu.items[2].icons, 3); - equal(menu.nextActionList[0], STK_CMD_SET_UP_CALL); - equal(menu.nextActionList[1], STK_CMD_LAUNCH_BROWSER); - equal(menu.nextActionList[2], STK_CMD_PLAY_TONE); - } - }); - - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x30, - 0x81, 0x03, 0x01, 0x25, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x54, 0x69, 0x74, 0x6C, 0x65, - 0x8F, 0x07, 0x01, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x31, - 0x8F, 0x07, 0x02, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x32, - 0x8F, 0x07, 0x03, 0x69, 0x74, 0x65, 0x6D, 0x20, 0x33, - 0x18, 0x03, 0x81, 0x00, 0x00 - ], - typeOfCommand: STK_CMD_SET_UP_MENU, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let menu = cmdDetails.options; - - equal(menu.title, "Title"); - equal(menu.items[0].identifier, 1); - equal(menu.items[0].text, "item 1"); - equal(menu.items[1].identifier, 2); - equal(menu.items[1].text, "item 2"); - equal(menu.items[2].identifier, 3); - equal(menu.items[2].text, "item 3"); - equal(menu.nextActionList[0], STK_NEXT_ACTION_END_PROACTIVE_SESSION); - equal(menu.nextActionList[1], STK_NEXT_ACTION_NULL); - equal(menu.nextActionList[2], STK_NEXT_ACTION_NULL); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Set Up Call - */ -add_test(function test_stk_proactive_command_set_up_call() { - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x31, - 0x81, 0x03, 0x01, 0x10, 0x04, - 0x82, 0x02, 0x81, 0x82, - 0x05, 0x0A, 0x44, 0x69, 0x73, 0x63, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, - 0x86, 0x09, 0x81, 0x10, 0x32, 0x04, 0x21, 0x43, 0x65, 0x1C, 0x2C, - 0x05, 0x07, 0x4D, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x9E, 0x02, 0x00, 0x01, - 0x9E, 0x02, 0x01, 0x02 - ], - typeOfCommand: STK_CMD_SET_UP_CALL, - icons: [1, 2], - testFunc: (context, cmdDetails, ctlvs) => { - let setupCall = cmdDetails.options; - - equal(setupCall.address, "012340123456,1,2"); - equal(setupCall.confirmMessage.text, "Disconnect"); - equal(setupCall.confirmMessage.iconSelfExplanatory, true); - equal(setupCall.confirmMessage.icons, 1); - equal(setupCall.callMessage.text, "Message"); - equal(setupCall.callMessage.iconSelfExplanatory, false); - equal(setupCall.callMessage.icons, 2); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Timer Management - */ -add_test(function test_stk_proactive_command_timer_management() { - // Timer Management - Start - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x11, - 0x81, 0x03, 0x01, 0x27, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0xA4, 0x01, 0x01, - 0xA5, 0x03, 0x10, 0x20, 0x30 - ], - typeOfCommand: STK_CMD_TIMER_MANAGEMENT, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_TIMER_START); - - let timer = cmdDetails.options; - - equal(timer.timerId, 0x01); - equal(timer.timerValue, (0x01 * 60 * 60) + (0x02 * 60) + 0x03); - } - }); - - // Timer Management - Deactivate - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0C, - 0x81, 0x03, 0x01, 0x27, 0x01, - 0x82, 0x02, 0x81, 0x82, - 0xA4, 0x01, 0x01 - ], - typeOfCommand: STK_CMD_TIMER_MANAGEMENT, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_TIMER_DEACTIVATE); - - let timer = cmdDetails.options; - - equal(timer.timerId, 0x01); - ok(timer.timerValue === undefined); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive Command : Provide Local Information - */ -add_test(function test_stk_proactive_command_provide_local_information() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - let stkCmdHelper = context.StkCommandParamsFactory; - - // Verify IMEI - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x09, - 0x81, 0x03, 0x01, 0x26, 0x01, - 0x82, 0x02, 0x81, 0x82 - ], - typeOfCommand: STK_CMD_PROVIDE_LOCAL_INFO, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_LOCAL_INFO_IMEI); - - let provideLocalInfo = cmdDetails.options; - equal(provideLocalInfo.localInfoType, STK_LOCAL_INFO_IMEI); - } - }); - - // Verify Date and Time Zone - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x09, - 0x81, 0x03, 0x01, 0x26, 0x03, - 0x82, 0x02, 0x81, 0x82 - ], - typeOfCommand: STK_CMD_PROVIDE_LOCAL_INFO, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - equal(cmdDetails.commandQualifier, STK_LOCAL_INFO_DATE_TIME_ZONE); - - let provideLocalInfo = cmdDetails.options; - equal(provideLocalInfo.localInfoType, STK_LOCAL_INFO_DATE_TIME_ZONE); - } - }); - - run_next_test(); -}); - -/** - * Verify Proactive command : BIP Messages - */ -add_test(function test_stk_proactive_command_open_channel() { - let worker = newUint8Worker(); - let context = worker.ContextPool._contexts[0]; - let pduHelper = context.GsmPDUHelper; - let berHelper = context.BerTlvHelper; - let stkHelper = context.StkProactiveCmdHelper; - let stkCmdHelper = context.StkCommandParamsFactory; - - // Open Channel - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0F, - 0x81, 0x03, 0x01, 0x40, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x04, 0x4F, 0x70, 0x65, 0x6E //alpha id: "Open" - ], - typeOfCommand: STK_CMD_OPEN_CHANNEL, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Open"); - } - }); - - // Close Channel - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x10, - 0x81, 0x03, 0x01, 0x41, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x05, 0x43, 0x6C, 0x6F, 0x73, 0x65 //alpha id: "Close" - ], - typeOfCommand: STK_CMD_CLOSE_CHANNEL, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Close"); - } - }); - - // Receive Data - test_stk_proactive_command({ - pdu: [ - 0XD0, - 0X12, - 0x81, 0x03, 0x01, 0x42, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x07, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65 //alpha id: "Receive" - ], - typeOfCommand: STK_CMD_RECEIVE_DATA, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Receive"); - } - }); - - // Send Data - test_stk_proactive_command({ - pdu: [ - 0xD0, - 0x0F, - 0x81, 0x03, 0x01, 0x43, 0x00, - 0x82, 0x02, 0x81, 0x82, - 0x85, 0x04, 0x53, 0x65, 0x6E, 0x64 //alpha id: "Send" - ], - typeOfCommand: STK_CMD_SEND_DATA, - icons: null, - testFunc: (context, cmdDetails, ctlvs) => { - let bipMsg = cmdDetails.options; - - equal(bipMsg.text, "Send"); - } - }); - - run_next_test(); -}); - -/** - * Verify Event Download Command : Location Status - */ -add_test(function test_stk_event_download_location_status() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 42 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LOCATION_STATUS_SIZE(3) + - // TLV_LOCATION_INFO_GSM_SIZE(9)) - equal(this.readInt32(), 42); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 19 = TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LOCATION_STATUS_SIZE(3) + - // TLV_LOCATION_INFO_GSM_SIZE(9) - equal(pduHelper.readHexOctet(), 19); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_LOCATION_STATUS); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Location Status, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LOCATION_STATUS | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_SERVICE_STATE_NORMAL); - - // Location Info, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LOCATION_INFO | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 7); - - equal(pduHelper.readHexOctet(), 0x21); // MCC + MNC - equal(pduHelper.readHexOctet(), 0x63); - equal(pduHelper.readHexOctet(), 0x54); - equal(pduHelper.readHexOctet(), 0); // LAC - equal(pduHelper.readHexOctet(), 0); - equal(pduHelper.readHexOctet(), 0); // Cell ID - equal(pduHelper.readHexOctet(), 0); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_LOCATION_STATUS, - locationStatus: STK_SERVICE_STATE_NORMAL, - locationInfo: { - mcc: "123", - mnc: "456", - gsmLocationAreaCode: 0, - gsmCellId: 0 - } - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -// Test Event Download commands. - -/** - * Verify Event Download Command : Language Selection - */ -add_test(function test_stk_event_download_language_selection() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - let iccHelper = context.ICCPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 26 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LANGUAGE(4)) - equal(this.readInt32(), 26); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 19 = TLV_DEVICE_ID_SIZE(4) + - // TLV_EVENT_LIST_SIZE(3) + - // TLV_LANGUAGE(4) - equal(pduHelper.readHexOctet(), 11); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_LANGUAGE_SELECTION); - - // Device Identifies, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Language, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_LANGUAGE); - equal(pduHelper.readHexOctet(), 2); - equal(iccHelper.read8BitUnpackedToString(2), "zh"); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_LANGUAGE_SELECTION, - language: "zh" - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -/** - * Verify Event Download Command : User Activity - */ -add_test(function test_stk_event_download_user_activity() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 18 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3)) - equal(this.readInt32(), 18); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 7 = TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3) - equal(pduHelper.readHexOctet(), 7); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_USER_ACTIVITY); - - // Device Identities, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_USER_ACTIVITY - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -/** - * Verify Event Download Command : Idle Screen Available - */ -add_test(function test_stk_event_download_idle_screen_available() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 18 = 2 * (2 + TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3)) - equal(this.readInt32(), 18); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 7 = TLV_DEVICE_ID_SIZE(4) + TLV_EVENT_LIST_SIZE(3) - equal(pduHelper.readHexOctet(), 7); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE); - - // Device Identities, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_DISPLAY); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_IDLE_SCREEN_AVAILABLE - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); - -/** - * Verify Event Downloaded Command :Browser Termination - */ -add_test(function test_stk_event_download_browser_termination() { - let worker = newUint8SupportOutgoingIndexWorker(); - let context = worker.ContextPool._contexts[0]; - let buf = context.Buf; - let pduHelper = context.GsmPDUHelper; - - buf.sendParcel = function() { - // Type - equal(this.readInt32(), REQUEST_STK_SEND_ENVELOPE_COMMAND); - - // Token : we don't care - this.readInt32(); - - // Data Size, 24 = 2 * ( 2+TLV_DEVICE_ID(4)+TLV_EVENT_LIST_SIZE(3) - // +TLV_BROWSER_TERMINATION_CAUSE(3) ) - equal(this.readInt32(), 24); - - // BER tag - equal(pduHelper.readHexOctet(), BER_EVENT_DOWNLOAD_TAG); - - // BER length, 10 = TLV_DEVICE_ID(4)+TLV_EVENT_LIST_SIZE(3) - // ++TLV_BROWSER_TERMINATION_CAUSE(3) - equal(pduHelper.readHexOctet(), 10); - - // Event List, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_EVENT_LIST | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_EVENT_TYPE_BROWSER_TERMINATION); - - // Device Identities, Type-Length-Value(Source ID-Destination ID) - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_DEVICE_ID | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 2); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_ME); - equal(pduHelper.readHexOctet(), STK_DEVICE_ID_SIM); - - // Browser Termination Case, Type-Length-Value - equal(pduHelper.readHexOctet(), COMPREHENSIONTLV_TAG_BROWSER_TERMINATION_CAUSE | - COMPREHENSIONTLV_FLAG_CR); - equal(pduHelper.readHexOctet(), 1); - equal(pduHelper.readHexOctet(), STK_BROWSER_TERMINATION_CAUSE_USER); - - run_next_test(); - }; - - let event = { - eventType: STK_EVENT_TYPE_BROWSER_TERMINATION, - terminationCause: STK_BROWSER_TERMINATION_CAUSE_USER - }; - context.RIL.sendStkEventDownload({ - event: event - }); -}); diff --git a/dom/system/gonk/tests/test_ril_worker_voiceprivacy.js b/dom/system/gonk/tests/test_ril_worker_voiceprivacy.js deleted file mode 100644 index 21829da22..000000000 --- a/dom/system/gonk/tests/test_ril_worker_voiceprivacy.js +++ /dev/null @@ -1,94 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -subscriptLoader.loadSubScript("resource://gre/modules/ril_consts.js", this); - -function run_test() { - run_next_test(); -} - -add_test(function test_setVoicePrivacyMode_success() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setVoicePrivacyMode = function fakeSetVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE](0, {}); - }; - - context.RIL.setVoicePrivacyMode({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - - run_next_test(); -}); - -add_test(function test_setVoicePrivacyMode_generic_failure() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.RIL.setVoicePrivacyMode = function fakeSetVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_SET_PREFERRED_VOICE_PRIVACY_MODE](0, { - errorMsg: GECKO_ERROR_GENERIC_FAILURE - }); - }; - - context.RIL.setVoicePrivacyMode({ - enabled: true - }); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, GECKO_ERROR_GENERIC_FAILURE); - - run_next_test(); -}); - -add_test(function test_queryVoicePrivacyMode_success_enabled_true() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32List = function fakeReadUint32List() { - return [1]; - }; - - context.RIL.queryVoicePrivacyMode = function fakeQueryVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE](1, {}); - }; - - context.RIL.queryVoicePrivacyMode(); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - ok(postedMessage.enabled); - run_next_test(); -}); - -add_test(function test_queryVoicePrivacyMode_success_enabled_false() { - let workerHelper = newInterceptWorker(); - let worker = workerHelper.worker; - let context = worker.ContextPool._contexts[0]; - - context.Buf.readInt32List = function fakeReadUint32List() { - return [0]; - }; - - context.RIL.queryVoicePrivacyMode = function fakeQueryVoicePrivacyMode(options) { - context.RIL[REQUEST_CDMA_QUERY_PREFERRED_VOICE_PRIVACY_MODE](1, {}); - }; - - context.RIL.queryVoicePrivacyMode(); - - let postedMessage = workerHelper.postedMessage; - - equal(postedMessage.errorMsg, undefined); - ok(!postedMessage.enabled); - run_next_test(); -}); diff --git a/dom/system/gonk/tests/xpcshell.ini b/dom/system/gonk/tests/xpcshell.ini deleted file mode 100644 index 1e8b798a3..000000000 --- a/dom/system/gonk/tests/xpcshell.ini +++ /dev/null @@ -1,43 +0,0 @@ -[DEFAULT] -head = header_helpers.js -tail = - -[test_ril_worker_buf.js] -[test_ril_worker_icc_CardLock.js] -[test_ril_worker_icc_CardState.js] -[test_ril_worker_icc_BerTlvHelper.js] -[test_ril_worker_icc_GsmPDUHelper.js] -[test_ril_worker_icc_ICCContactHelper.js] -[test_ril_worker_icc_ICCIOHelper.js] -[test_ril_worker_icc_ICCPDUHelper.js] -[test_ril_worker_icc_ICCRecordHelper.js] -[test_ril_worker_icc_IconLoader.js] -[test_ril_worker_icc_ICCUtilsHelper.js] -[test_ril_worker_icc_SimRecordHelper.js] -[test_ril_worker_sms.js] -# Bug 916067 - B2G RIL: test_ril_worker_sms.js takes too long to finish -skip-if = true -[test_ril_worker_sms_cdma.js] -[test_ril_worker_sms_cdmapduhelper.js] -[test_ril_worker_sms_nl_tables.js] -[test_ril_worker_sms_gsmpduhelper.js] -[test_ril_worker_sms_segment_info.js] -[test_ril_worker_smsc_address.js] -[test_ril_worker_cf.js] -[test_ril_worker_cellbroadcast_config.js] -[test_ril_worker_cellbroadcast_gsm.js] -[test_ril_worker_cellbroadcast_umts.js] -[test_ril_worker_ruim.js] -[test_ril_worker_cw.js] -[test_ril_worker_clir.js] -[test_ril_worker_clip.js] -[test_ril_worker_ssn.js] -[test_ril_worker_voiceprivacy.js] -[test_ril_worker_ecm.js] -[test_ril_worker_stk.js] -requesttimeoutfactor = 4 -[test_ril_worker_barring_password.js] -[test_ril_worker_cdma_info_rec.js] -[test_ril_system_messenger.js] -# header_helpers.js is not needed for test_ril_system_messenger.js -head = diff --git a/dom/system/gonk/worker_buf.js b/dom/system/gonk/worker_buf.js deleted file mode 100644 index 7064eeac5..000000000 --- a/dom/system/gonk/worker_buf.js +++ /dev/null @@ -1,623 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - - -/** - * This object contains helpers buffering incoming data & deconstructing it - * into parcels as well as buffering outgoing data & constructing parcels. - * For that it maintains two buffers and corresponding uint8 views, indexes. - * - * The incoming buffer is a circular buffer where we store incoming data. - * As soon as a complete parcel is received, it is processed right away, so - * the buffer only needs to be large enough to hold one parcel. - * - * The outgoing buffer is to prepare outgoing parcels. The index is reset - * every time a parcel is sent. - */ - -var Buf = { - INT32_MAX: 2147483647, - UINT8_SIZE: 1, - UINT16_SIZE: 2, - UINT32_SIZE: 4, - PARCEL_SIZE_SIZE: 4, - PDU_HEX_OCTET_SIZE: 4, - - incomingBufferLength: 1024, - incomingBuffer: null, - incomingBytes: null, - incomingWriteIndex: 0, - incomingReadIndex: 0, - readIncoming: 0, - readAvailable: 0, - currentParcelSize: 0, - - outgoingBufferLength: 1024, - outgoingBuffer: null, - outgoingBytes: null, - outgoingIndex: 0, - outgoingBufferCalSizeQueue: null, - - _init: function() { - this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength); - this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength); - - this.incomingBytes = new Uint8Array(this.incomingBuffer); - this.outgoingBytes = new Uint8Array(this.outgoingBuffer); - - // Track where incoming data is read from and written to. - this.incomingWriteIndex = 0; - this.incomingReadIndex = 0; - - // Leave room for the parcel size for outgoing parcels. - this.outgoingIndex = this.PARCEL_SIZE_SIZE; - - // How many bytes we've read for this parcel so far. - this.readIncoming = 0; - - // How many bytes available as parcel data. - this.readAvailable = 0; - - // Size of the incoming parcel. If this is zero, we're expecting a new - // parcel. - this.currentParcelSize = 0; - - // Queue for storing outgoing override points - this.outgoingBufferCalSizeQueue = []; - }, - - /** - * Mark current outgoingIndex as start point for calculation length of data - * written to outgoingBuffer. - * Mark can be nested for here uses queue to remember marks. - * - * @param writeFunction - * Function to write data length into outgoingBuffer, this function is - * also used to allocate buffer for data length. - * Raw data size(in Uint8) is provided as parameter calling writeFunction. - * If raw data size is not in proper unit for writing, user can adjust - * the length value in writeFunction before writing. - **/ - startCalOutgoingSize: function(writeFunction) { - let sizeInfo = {index: this.outgoingIndex, - write: writeFunction}; - - // Allocate buffer for data lemgtj. - writeFunction.call(0); - - // Get size of data length buffer for it is not counted into data size. - sizeInfo.size = this.outgoingIndex - sizeInfo.index; - - // Enqueue size calculation information. - this.outgoingBufferCalSizeQueue.push(sizeInfo); - }, - - /** - * Calculate data length since last mark, and write it into mark position. - **/ - stopCalOutgoingSize: function() { - let sizeInfo = this.outgoingBufferCalSizeQueue.pop(); - - // Remember current outgoingIndex. - let currentOutgoingIndex = this.outgoingIndex; - // Calculate data length, in uint8. - let writeSize = this.outgoingIndex - sizeInfo.index - sizeInfo.size; - - // Write data length to mark, use same function for allocating buffer to make - // sure there is no buffer overloading. - this.outgoingIndex = sizeInfo.index; - sizeInfo.write(writeSize); - - // Restore outgoingIndex. - this.outgoingIndex = currentOutgoingIndex; - }, - - /** - * Grow the incoming buffer. - * - * @param min_size - * Minimum new size. The actual new size will be the the smallest - * power of 2 that's larger than this number. - */ - growIncomingBuffer: function(min_size) { - if (DEBUG) { - debug("Current buffer of " + this.incomingBufferLength + - " can't handle incoming " + min_size + " bytes."); - } - let oldBytes = this.incomingBytes; - this.incomingBufferLength = - 2 << Math.floor(Math.log(min_size)/Math.log(2)); - if (DEBUG) debug("New incoming buffer size: " + this.incomingBufferLength); - this.incomingBuffer = new ArrayBuffer(this.incomingBufferLength); - this.incomingBytes = new Uint8Array(this.incomingBuffer); - if (this.incomingReadIndex <= this.incomingWriteIndex) { - // Read and write index are in natural order, so we can just copy - // the old buffer over to the bigger one without having to worry - // about the indexes. - this.incomingBytes.set(oldBytes, 0); - } else { - // The write index has wrapped around but the read index hasn't yet. - // Write whatever the read index has left to read until it would - // circle around to the beginning of the new buffer, and the rest - // behind that. - let head = oldBytes.subarray(this.incomingReadIndex); - let tail = oldBytes.subarray(0, this.incomingReadIndex); - this.incomingBytes.set(head, 0); - this.incomingBytes.set(tail, head.length); - this.incomingReadIndex = 0; - this.incomingWriteIndex += head.length; - } - if (DEBUG) { - debug("New incoming buffer size is " + this.incomingBufferLength); - } - }, - - /** - * Grow the outgoing buffer. - * - * @param min_size - * Minimum new size. The actual new size will be the the smallest - * power of 2 that's larger than this number. - */ - growOutgoingBuffer: function(min_size) { - if (DEBUG) { - debug("Current buffer of " + this.outgoingBufferLength + - " is too small."); - } - let oldBytes = this.outgoingBytes; - this.outgoingBufferLength = - 2 << Math.floor(Math.log(min_size)/Math.log(2)); - this.outgoingBuffer = new ArrayBuffer(this.outgoingBufferLength); - this.outgoingBytes = new Uint8Array(this.outgoingBuffer); - this.outgoingBytes.set(oldBytes, 0); - if (DEBUG) { - debug("New outgoing buffer size is " + this.outgoingBufferLength); - } - }, - - /** - * Functions for reading data from the incoming buffer. - * - * These are all little endian, apart from readParcelSize(); - */ - - /** - * Ensure position specified is readable. - * - * @param index - * Data position in incoming parcel, valid from 0 to - * currentParcelSize. - */ - ensureIncomingAvailable: function(index) { - if (index >= this.currentParcelSize) { - throw new Error("Trying to read data beyond the parcel end!"); - } else if (index < 0) { - throw new Error("Trying to read data before the parcel begin!"); - } - }, - - /** - * Seek in current incoming parcel. - * - * @param offset - * Seek offset in relative to current position. - */ - seekIncoming: function(offset) { - // Translate to 0..currentParcelSize - let cur = this.currentParcelSize - this.readAvailable; - - let newIndex = cur + offset; - this.ensureIncomingAvailable(newIndex); - - // ... incomingReadIndex -->| - // 0 new cur currentParcelSize - // |================|=======|====================| - // |<-- cur -->|<- readAvailable ->| - // |<-- newIndex -->|<-- new readAvailable -->| - this.readAvailable = this.currentParcelSize - newIndex; - - // Translate back: - if (this.incomingReadIndex < cur) { - // The incomingReadIndex is wrapped. - newIndex += this.incomingBufferLength; - } - newIndex += (this.incomingReadIndex - cur); - newIndex %= this.incomingBufferLength; - this.incomingReadIndex = newIndex; - }, - - readUint8Unchecked: function() { - let value = this.incomingBytes[this.incomingReadIndex]; - this.incomingReadIndex = (this.incomingReadIndex + 1) % - this.incomingBufferLength; - return value; - }, - - readUint8: function() { - // Translate to 0..currentParcelSize - let cur = this.currentParcelSize - this.readAvailable; - this.ensureIncomingAvailable(cur); - - this.readAvailable--; - return this.readUint8Unchecked(); - }, - - readUint8Array: function(length) { - // Translate to 0..currentParcelSize - let last = this.currentParcelSize - this.readAvailable; - last += (length - 1); - this.ensureIncomingAvailable(last); - - let array = new Uint8Array(length); - for (let i = 0; i < length; i++) { - array[i] = this.readUint8Unchecked(); - } - - this.readAvailable -= length; - return array; - }, - - readUint16: function() { - return this.readUint8() | this.readUint8() << 8; - }, - - readInt32: function() { - return this.readUint8() | this.readUint8() << 8 | - this.readUint8() << 16 | this.readUint8() << 24; - }, - - readInt64: function() { - // Avoid using bitwise operators as the operands of all bitwise operators - // are converted to signed 32-bit integers. - return this.readUint8() + - this.readUint8() * Math.pow(2, 8) + - this.readUint8() * Math.pow(2, 16) + - this.readUint8() * Math.pow(2, 24) + - this.readUint8() * Math.pow(2, 32) + - this.readUint8() * Math.pow(2, 40) + - this.readUint8() * Math.pow(2, 48) + - this.readUint8() * Math.pow(2, 56); - }, - - readInt32List: function() { - let length = this.readInt32(); - let ints = []; - for (let i = 0; i < length; i++) { - ints.push(this.readInt32()); - } - return ints; - }, - - readString: function() { - let string_len = this.readInt32(); - if (string_len < 0 || string_len >= this.INT32_MAX) { - return null; - } - let s = ""; - for (let i = 0; i < string_len; i++) { - s += String.fromCharCode(this.readUint16()); - } - // Strings are \0\0 delimited, but that isn't part of the length. And - // if the string length is even, the delimiter is two characters wide. - // It's insane, I know. - this.readStringDelimiter(string_len); - return s; - }, - - readStringList: function() { - let num_strings = this.readInt32(); - let strings = []; - for (let i = 0; i < num_strings; i++) { - strings.push(this.readString()); - } - return strings; - }, - - readStringDelimiter: function(length) { - let delimiter = this.readUint16(); - if (!(length & 1)) { - delimiter |= this.readUint16(); - } - if (DEBUG) { - if (delimiter !== 0) { - debug("Something's wrong, found string delimiter: " + delimiter); - } - } - }, - - readParcelSize: function() { - return this.readUint8Unchecked() << 24 | - this.readUint8Unchecked() << 16 | - this.readUint8Unchecked() << 8 | - this.readUint8Unchecked(); - }, - - /** - * Functions for writing data to the outgoing buffer. - */ - - /** - * Ensure position specified is writable. - * - * @param index - * Data position in outgoing parcel, valid from 0 to - * outgoingBufferLength. - */ - ensureOutgoingAvailable: function(index) { - if (index >= this.outgoingBufferLength) { - this.growOutgoingBuffer(index + 1); - } - }, - - writeUint8: function(value) { - this.ensureOutgoingAvailable(this.outgoingIndex); - - this.outgoingBytes[this.outgoingIndex] = value; - this.outgoingIndex++; - }, - - writeUint16: function(value) { - this.writeUint8(value & 0xff); - this.writeUint8((value >> 8) & 0xff); - }, - - writeInt32: function(value) { - this.writeUint8(value & 0xff); - this.writeUint8((value >> 8) & 0xff); - this.writeUint8((value >> 16) & 0xff); - this.writeUint8((value >> 24) & 0xff); - }, - - writeString: function(value) { - if (value == null) { - this.writeInt32(-1); - return; - } - this.writeInt32(value.length); - for (let i = 0; i < value.length; i++) { - this.writeUint16(value.charCodeAt(i)); - } - // Strings are \0\0 delimited, but that isn't part of the length. And - // if the string length is even, the delimiter is two characters wide. - // It's insane, I know. - this.writeStringDelimiter(value.length); - }, - - writeStringList: function(strings) { - this.writeInt32(strings.length); - for (let i = 0; i < strings.length; i++) { - this.writeString(strings[i]); - } - }, - - writeStringDelimiter: function(length) { - this.writeUint16(0); - if (!(length & 1)) { - this.writeUint16(0); - } - }, - - writeParcelSize: function(value) { - /** - * Parcel size will always be the first thing in the parcel byte - * array, but the last thing written. Store the current index off - * to a temporary to be reset after we write the size. - */ - let currentIndex = this.outgoingIndex; - this.outgoingIndex = 0; - this.writeUint8((value >> 24) & 0xff); - this.writeUint8((value >> 16) & 0xff); - this.writeUint8((value >> 8) & 0xff); - this.writeUint8(value & 0xff); - this.outgoingIndex = currentIndex; - }, - - copyIncomingToOutgoing: function(length) { - if (!length || (length < 0)) { - return; - } - - let translatedReadIndexEnd = - this.currentParcelSize - this.readAvailable + length - 1; - this.ensureIncomingAvailable(translatedReadIndexEnd); - - let translatedWriteIndexEnd = this.outgoingIndex + length - 1; - this.ensureOutgoingAvailable(translatedWriteIndexEnd); - - let newIncomingReadIndex = this.incomingReadIndex + length; - if (newIncomingReadIndex < this.incomingBufferLength) { - // Reading won't cause wrapping, go ahead with builtin copy. - this.outgoingBytes - .set(this.incomingBytes.subarray(this.incomingReadIndex, - newIncomingReadIndex), - this.outgoingIndex); - } else { - // Not so lucky. - newIncomingReadIndex %= this.incomingBufferLength; - this.outgoingBytes - .set(this.incomingBytes.subarray(this.incomingReadIndex, - this.incomingBufferLength), - this.outgoingIndex); - if (newIncomingReadIndex) { - let firstPartLength = this.incomingBufferLength - this.incomingReadIndex; - this.outgoingBytes.set(this.incomingBytes.subarray(0, newIncomingReadIndex), - this.outgoingIndex + firstPartLength); - } - } - - this.incomingReadIndex = newIncomingReadIndex; - this.readAvailable -= length; - this.outgoingIndex += length; - }, - - /** - * Parcel management - */ - - /** - * Write incoming data to the circular buffer. - * - * @param incoming - * Uint8Array containing the incoming data. - */ - writeToIncoming: function(incoming) { - // We don't have to worry about the head catching the tail since - // we process any backlog in parcels immediately, before writing - // new data to the buffer. So the only edge case we need to handle - // is when the incoming data is larger than the buffer size. - let minMustAvailableSize = incoming.length + this.readIncoming; - if (minMustAvailableSize > this.incomingBufferLength) { - this.growIncomingBuffer(minMustAvailableSize); - } - - // We can let the typed arrays do the copying if the incoming data won't - // wrap around the edges of the circular buffer. - let remaining = this.incomingBufferLength - this.incomingWriteIndex; - if (remaining >= incoming.length) { - this.incomingBytes.set(incoming, this.incomingWriteIndex); - } else { - // The incoming data would wrap around it. - let head = incoming.subarray(0, remaining); - let tail = incoming.subarray(remaining); - this.incomingBytes.set(head, this.incomingWriteIndex); - this.incomingBytes.set(tail, 0); - } - this.incomingWriteIndex = (this.incomingWriteIndex + incoming.length) % - this.incomingBufferLength; - }, - - /** - * Process incoming data. - * - * @param incoming - * Uint8Array containing the incoming data. - */ - processIncoming: function(incoming) { - if (DEBUG) { - debug("Received " + incoming.length + " bytes."); - debug("Already read " + this.readIncoming); - } - - this.writeToIncoming(incoming); - this.readIncoming += incoming.length; - while (true) { - if (!this.currentParcelSize) { - // We're expecting a new parcel. - if (this.readIncoming < this.PARCEL_SIZE_SIZE) { - // We don't know how big the next parcel is going to be, need more - // data. - if (DEBUG) debug("Next parcel size unknown, going to sleep."); - return; - } - this.currentParcelSize = this.readParcelSize(); - if (DEBUG) { - debug("New incoming parcel of size " + this.currentParcelSize); - } - // The size itself is not included in the size. - this.readIncoming -= this.PARCEL_SIZE_SIZE; - } - - if (this.readIncoming < this.currentParcelSize) { - // We haven't read enough yet in order to be able to process a parcel. - if (DEBUG) debug("Read " + this.readIncoming + ", but parcel size is " - + this.currentParcelSize + ". Going to sleep."); - return; - } - - // Alright, we have enough data to process at least one whole parcel. - // Let's do that. - let expectedAfterIndex = (this.incomingReadIndex + this.currentParcelSize) - % this.incomingBufferLength; - - if (DEBUG) { - let parcel; - if (expectedAfterIndex < this.incomingReadIndex) { - let head = this.incomingBytes.subarray(this.incomingReadIndex); - let tail = this.incomingBytes.subarray(0, expectedAfterIndex); - parcel = Array.slice(head).concat(Array.slice(tail)); - } else { - parcel = Array.slice(this.incomingBytes.subarray( - this.incomingReadIndex, expectedAfterIndex)); - } - debug("Parcel (size " + this.currentParcelSize + "): " + parcel); - } - - if (DEBUG) debug("We have at least one complete parcel."); - try { - this.readAvailable = this.currentParcelSize; - this.processParcel(); - } catch (ex) { - if (DEBUG) debug("Parcel handling threw " + ex + "\n" + ex.stack); - } - - // Ensure that the whole parcel was consumed. - if (this.incomingReadIndex != expectedAfterIndex) { - if (DEBUG) { - debug("Parcel handler didn't consume whole parcel, " + - Math.abs(expectedAfterIndex - this.incomingReadIndex) + - " bytes left over"); - } - this.incomingReadIndex = expectedAfterIndex; - } - this.readIncoming -= this.currentParcelSize; - this.readAvailable = 0; - this.currentParcelSize = 0; - } - }, - - /** - * Communicate with the IPC thread. - */ - sendParcel: function() { - // Compute the size of the parcel and write it to the front of the parcel - // where we left room for it. Note that he parcel size does not include - // the size itself. - let parcelSize = this.outgoingIndex - this.PARCEL_SIZE_SIZE; - this.writeParcelSize(parcelSize); - - // This assumes that postRILMessage will make a copy of the ArrayBufferView - // right away! - let parcel = this.outgoingBytes.subarray(0, this.outgoingIndex); - if (DEBUG) debug("Outgoing parcel: " + Array.slice(parcel)); - this.onSendParcel(parcel); - this.outgoingIndex = this.PARCEL_SIZE_SIZE; - }, - - getCurrentParcelSize: function() { - return this.currentParcelSize; - }, - - getReadAvailable: function() { - return this.readAvailable; - } - - /** - * Process one parcel. - * - * |processParcel| is an implementation provided incoming parcel processing - * function invoked when we have received a complete parcel. Implementation - * may call multiple read functions to extract data from the incoming buffer. - */ - //processParcel: function() { - // let something = this.readInt32(); - // ... - //}, - - /** - * Write raw data out to underlying channel. - * - * |onSendParcel| is an implementation provided stream output function - * invoked when we're really going to write something out. We assume the - * data are completely copied to some output buffer in this call and may - * be destroyed when it's done. - * - * @param parcel - * An array of numeric octet data. - */ - //onSendParcel: function(parcel) { - // ... - //} -}; - -module.exports = { Buf: Buf }; diff --git a/dom/system/moz.build b/dom/system/moz.build index 3cff531b5..fc8cf533b 100644 --- a/dom/system/moz.build +++ b/dom/system/moz.build @@ -12,8 +12,6 @@ elif toolkit == 'cocoa': DIRS += ['mac'] elif toolkit == 'android': DIRS += ['android'] -elif toolkit == 'gonk': - DIRS += ['gonk'] elif toolkit in ('gtk2', 'gtk3'): DIRS += ['linux'] diff --git a/hal/gonk/GonkDiskSpaceWatcher.cpp b/hal/gonk/GonkDiskSpaceWatcher.cpp deleted file mode 100644 index cdc48ef89..000000000 --- a/hal/gonk/GonkDiskSpaceWatcher.cpp +++ /dev/null @@ -1,324 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Hal.h" -#include -#include -#include -#include -#include "base/message_loop.h" -#include "base/task.h" -#include "DiskSpaceWatcher.h" -#include "fanotify.h" -#include "nsIObserverService.h" -#include "nsIDiskSpaceWatcher.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" -#include "mozilla/ModuleUtils.h" -#include "mozilla/Preferences.h" -#include "mozilla/Services.h" - -using namespace mozilla; - -namespace mozilla { namespace hal_impl { class GonkDiskSpaceWatcher; } } - -using namespace mozilla::hal_impl; - -namespace mozilla { -namespace hal_impl { - -// NOTE: this should be unnecessary once we no longer support ICS. -#ifndef __NR_fanotify_init -#if defined(__ARM_EABI__) -#define __NR_fanotify_init 367 -#define __NR_fanotify_mark 368 -#elif defined(__i386__) -#define __NR_fanotify_init 338 -#define __NR_fanotify_mark 339 -#else -#error "Unhandled architecture" -#endif -#endif - -// fanotify_init and fanotify_mark functions are syscalls. -// The user space bits are not part of bionic so we add them here -// as well as fanotify.h -int fanotify_init (unsigned int flags, unsigned int event_f_flags) -{ - return syscall(__NR_fanotify_init, flags, event_f_flags); -} - -// Add, remove, or modify an fanotify mark on a filesystem object. -int fanotify_mark (int fanotify_fd, unsigned int flags, - uint64_t mask, int dfd, const char *pathname) -{ - - // On 32 bits platforms we have to convert the 64 bits mask into - // two 32 bits ints. - if (sizeof(void *) == 4) { - union { - uint64_t _64; - uint32_t _32[2]; - } _mask; - _mask._64 = mask; - return syscall(__NR_fanotify_mark, fanotify_fd, flags, - _mask._32[0], _mask._32[1], dfd, pathname); - } - - return syscall(__NR_fanotify_mark, fanotify_fd, flags, mask, dfd, pathname); -} - -class GonkDiskSpaceWatcher final : public MessageLoopForIO::Watcher -{ -public: - GonkDiskSpaceWatcher(); - ~GonkDiskSpaceWatcher() {}; - - virtual void OnFileCanReadWithoutBlocking(int aFd); - - // We should never write to the fanotify fd. - virtual void OnFileCanWriteWithoutBlocking(int aFd) - { - MOZ_CRASH("Must not write to fanotify fd"); - } - - void DoStart(); - void DoStop(); - -private: - void NotifyUpdate(); - - uint64_t mLowThreshold; - uint64_t mHighThreshold; - TimeDuration mTimeout; - TimeStamp mLastTimestamp; - uint64_t mLastFreeSpace; - uint32_t mSizeDelta; - - bool mIsDiskFull; - uint64_t mFreeSpace; - - int mFd; - MessageLoopForIO::FileDescriptorWatcher mReadWatcher; -}; - -static GonkDiskSpaceWatcher* gHalDiskSpaceWatcher = nullptr; - -#define WATCHER_PREF_LOW "disk_space_watcher.low_threshold" -#define WATCHER_PREF_HIGH "disk_space_watcher.high_threshold" -#define WATCHER_PREF_TIMEOUT "disk_space_watcher.timeout" -#define WATCHER_PREF_SIZE_DELTA "disk_space_watcher.size_delta" - -static const char kWatchedPath[] = "/data"; - -// Helper class to dispatch calls to xpcom on the main thread. -class DiskSpaceNotifier : public Runnable -{ -public: - DiskSpaceNotifier(const bool aIsDiskFull, const uint64_t aFreeSpace) : - mIsDiskFull(aIsDiskFull), - mFreeSpace(aFreeSpace) {} - - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - DiskSpaceWatcher::UpdateState(mIsDiskFull, mFreeSpace); - return NS_OK; - } - -private: - bool mIsDiskFull; - uint64_t mFreeSpace; -}; - -// Helper runnable to delete the watcher on the main thread. -class DiskSpaceCleaner : public Runnable -{ -public: - NS_IMETHOD Run() override - { - MOZ_ASSERT(NS_IsMainThread()); - if (gHalDiskSpaceWatcher) { - delete gHalDiskSpaceWatcher; - gHalDiskSpaceWatcher = nullptr; - } - return NS_OK; - } -}; - -GonkDiskSpaceWatcher::GonkDiskSpaceWatcher() : - mLastFreeSpace(UINT64_MAX), - mIsDiskFull(false), - mFreeSpace(UINT64_MAX), - mFd(-1) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(gHalDiskSpaceWatcher == nullptr); - - // Default values: 5MB for low threshold, 10MB for high threshold, and - // a timeout of 5 seconds. - mLowThreshold = Preferences::GetInt(WATCHER_PREF_LOW, 5) * 1024 * 1024; - mHighThreshold = Preferences::GetInt(WATCHER_PREF_HIGH, 10) * 1024 * 1024; - mTimeout = TimeDuration::FromSeconds(Preferences::GetInt(WATCHER_PREF_TIMEOUT, 5)); - mSizeDelta = Preferences::GetInt(WATCHER_PREF_SIZE_DELTA, 1) * 1024 * 1024; -} - -void -GonkDiskSpaceWatcher::DoStart() -{ - NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(), - "Not on the correct message loop"); - - mFd = fanotify_init(FAN_CLASS_NOTIF, FAN_CLOEXEC | O_LARGEFILE); - if (mFd == -1) { - if (errno == ENOSYS) { - // Don't change these printf_stderr since we need these logs even - // in opt builds. - printf_stderr("Warning: No fanotify support in this device's kernel.\n"); -#if ANDROID_VERSION >= 19 - MOZ_CRASH("Fanotify support must be enabled in the kernel."); -#endif - } else { - printf_stderr("Error calling fanotify_init()"); - } - return; - } - - if (fanotify_mark(mFd, FAN_MARK_ADD | FAN_MARK_MOUNT, FAN_CLOSE, - 0, kWatchedPath) < 0) { - NS_WARNING("Error calling fanotify_mark"); - close(mFd); - mFd = -1; - return; - } - - if (!MessageLoopForIO::current()->WatchFileDescriptor( - mFd, /* persistent = */ true, - MessageLoopForIO::WATCH_READ, - &mReadWatcher, gHalDiskSpaceWatcher)) { - NS_WARNING("Unable to watch fanotify fd."); - close(mFd); - mFd = -1; - } -} - -void -GonkDiskSpaceWatcher::DoStop() -{ - NS_ASSERTION(XRE_GetIOMessageLoop() == MessageLoopForIO::current(), - "Not on the correct message loop"); - - if (mFd != -1) { - mReadWatcher.StopWatchingFileDescriptor(); - fanotify_mark(mFd, FAN_MARK_FLUSH, 0, 0, kWatchedPath); - close(mFd); - mFd = -1; - } - - // Dispatch the cleanup to the main thread. - nsCOMPtr runnable = new DiskSpaceCleaner(); - NS_DispatchToMainThread(runnable); -} - -// We are called off the main thread, so we proxy first to the main thread -// before calling the xpcom object. -void -GonkDiskSpaceWatcher::NotifyUpdate() -{ - mLastTimestamp = TimeStamp::Now(); - mLastFreeSpace = mFreeSpace; - - nsCOMPtr runnable = - new DiskSpaceNotifier(mIsDiskFull, mFreeSpace); - NS_DispatchToMainThread(runnable); -} - -void -GonkDiskSpaceWatcher::OnFileCanReadWithoutBlocking(int aFd) -{ - struct fanotify_event_metadata* fem = nullptr; - char buf[4096]; - struct statfs sfs; - int32_t len, rc; - - do { - len = read(aFd, buf, sizeof(buf)); - } while(len == -1 && errno == EINTR); - - // Bail out if the file is busy. - if (len < 0 && errno == ETXTBSY) { - return; - } - - // We should get an exact multiple of fanotify_event_metadata - if (len <= 0 || (len % FAN_EVENT_METADATA_LEN != 0)) { - MOZ_CRASH("About to crash: fanotify_event_metadata read error."); - } - - fem = reinterpret_cast(buf); - - while (FAN_EVENT_OK(fem, len)) { - rc = fstatfs(fem->fd, &sfs); - if (rc < 0) { - NS_WARNING("Unable to stat fan_notify fd"); - } else { - bool firstRun = mFreeSpace == UINT64_MAX; - mFreeSpace = sfs.f_bavail * sfs.f_bsize; - // We change from full <-> free depending on the free space and the - // low and high thresholds. - // Once we are in 'full' mode we send updates for all size changes with - // a minimum of time between messages or when we cross a size change - // threshold. - if (firstRun) { - mIsDiskFull = mFreeSpace <= mLowThreshold; - // Always notify the current state at first run. - NotifyUpdate(); - } else if (!mIsDiskFull && (mFreeSpace <= mLowThreshold)) { - mIsDiskFull = true; - NotifyUpdate(); - } else if (mIsDiskFull && (mFreeSpace > mHighThreshold)) { - mIsDiskFull = false; - NotifyUpdate(); - } else if (mIsDiskFull) { - if (mTimeout < TimeStamp::Now() - mLastTimestamp || - mSizeDelta < llabs(mFreeSpace - mLastFreeSpace)) { - NotifyUpdate(); - } - } - } - close(fem->fd); - fem = FAN_EVENT_NEXT(fem, len); - } -} - -void -StartDiskSpaceWatcher() -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Bail out if called several times. - if (gHalDiskSpaceWatcher != nullptr) { - return; - } - - gHalDiskSpaceWatcher = new GonkDiskSpaceWatcher(); - - XRE_GetIOMessageLoop()->PostTask( - NewNonOwningRunnableMethod(gHalDiskSpaceWatcher, &GonkDiskSpaceWatcher::DoStart)); -} - -void -StopDiskSpaceWatcher() -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!gHalDiskSpaceWatcher) { - return; - } - - XRE_GetIOMessageLoop()->PostTask( - NewNonOwningRunnableMethod(gHalDiskSpaceWatcher, &GonkDiskSpaceWatcher::DoStop)); -} - -} // namespace hal_impl -} // namespace mozilla diff --git a/hal/gonk/GonkHal.cpp b/hal/gonk/GonkHal.cpp deleted file mode 100644 index 05d9295a2..000000000 --- a/hal/gonk/GonkHal.cpp +++ /dev/null @@ -1,2045 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mozilla/DebugOnly.h" - -#include "android/log.h" -#include "cutils/properties.h" -#include "hardware/hardware.h" -#include "hardware/lights.h" -#include "hardware_legacy/uevent.h" -#include "hardware_legacy/vibrator.h" -#include "hardware_legacy/power.h" -#include "libdisplay/GonkDisplay.h" -#include "utils/threads.h" - -#include "base/message_loop.h" -#include "base/task.h" - -#include "Hal.h" -#include "HalImpl.h" -#include "HalLog.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/dom/battery/Constants.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Monitor.h" -#include "mozilla/RefPtr.h" -#include "mozilla/Services.h" -#include "mozilla/StaticMutex.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/Preferences.h" -#include "mozilla/UniquePtrExtensions.h" -#include "nsAlgorithm.h" -#include "nsPrintfCString.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsIRecoveryService.h" -#include "nsIRunnable.h" -#include "nsScreenManagerGonk.h" -#include "nsThreadUtils.h" -#include "nsThreadUtils.h" -#include "nsIThread.h" -#include "nsXULAppAPI.h" -#include "OrientationObserver.h" -#include "UeventPoller.h" -#include "nsIWritablePropertyBag2.h" -#include - -#define NsecPerMsec 1000000LL -#define NsecPerSec 1000000000 - -// The header linux/oom.h is not available in bionic libc. We -// redefine some of its constants here. - -#ifndef OOM_DISABLE -#define OOM_DISABLE (-17) -#endif - -#ifndef OOM_ADJUST_MIN -#define OOM_ADJUST_MIN (-16) -#endif - -#ifndef OOM_ADJUST_MAX -#define OOM_ADJUST_MAX 15 -#endif - -#ifndef OOM_SCORE_ADJ_MIN -#define OOM_SCORE_ADJ_MIN (-1000) -#endif - -#ifndef OOM_SCORE_ADJ_MAX -#define OOM_SCORE_ADJ_MAX 1000 -#endif - -#ifndef BATTERY_CHARGING_ARGB -#define BATTERY_CHARGING_ARGB 0x00FF0000 -#endif -#ifndef BATTERY_FULL_ARGB -#define BATTERY_FULL_ARGB 0x0000FF00 -#endif - -using namespace mozilla; -using namespace mozilla::hal; -using namespace mozilla::dom; - -namespace mozilla { -namespace hal_impl { - -/** - * These are defined by libhardware, specifically, hardware/libhardware/include/hardware/lights.h - * in the gonk subsystem. - * If these change and are exposed to JS, make sure nsIHal.idl is updated as well. - */ -enum LightType { - eHalLightID_Backlight = 0, - eHalLightID_Keyboard = 1, - eHalLightID_Buttons = 2, - eHalLightID_Battery = 3, - eHalLightID_Notifications = 4, - eHalLightID_Attention = 5, - eHalLightID_Bluetooth = 6, - eHalLightID_Wifi = 7, - eHalLightID_Count // This should stay at the end -}; -enum LightMode { - eHalLightMode_User = 0, // brightness is managed by user setting - eHalLightMode_Sensor = 1, // brightness is managed by a light sensor - eHalLightMode_Count -}; -enum FlashMode { - eHalLightFlash_None = 0, - eHalLightFlash_Timed = 1, // timed flashing. Use flashOnMS and flashOffMS for timing - eHalLightFlash_Hardware = 2, // hardware assisted flashing - eHalLightFlash_Count -}; - -struct LightConfiguration { - LightType light; - LightMode mode; - FlashMode flash; - uint32_t flashOnMS; - uint32_t flashOffMS; - uint32_t color; -}; - -static light_device_t* sLights[eHalLightID_Count]; // will be initialized to nullptr - -static light_device_t* -GetDevice(hw_module_t* module, char const* name) -{ - int err; - hw_device_t* device; - err = module->methods->open(module, name, &device); - if (err == 0) { - return (light_device_t*)device; - } else { - return nullptr; - } -} - -static void -InitLights() -{ - // assume that if backlight is nullptr, nothing has been set yet - // if this is not true, the initialization will occur everytime a light is read or set! - if (!sLights[eHalLightID_Backlight]) { - int err; - hw_module_t* module; - - err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module); - if (err == 0) { - sLights[eHalLightID_Backlight] - = GetDevice(module, LIGHT_ID_BACKLIGHT); - sLights[eHalLightID_Keyboard] - = GetDevice(module, LIGHT_ID_KEYBOARD); - sLights[eHalLightID_Buttons] - = GetDevice(module, LIGHT_ID_BUTTONS); - sLights[eHalLightID_Battery] - = GetDevice(module, LIGHT_ID_BATTERY); - sLights[eHalLightID_Notifications] - = GetDevice(module, LIGHT_ID_NOTIFICATIONS); - sLights[eHalLightID_Attention] - = GetDevice(module, LIGHT_ID_ATTENTION); - sLights[eHalLightID_Bluetooth] - = GetDevice(module, LIGHT_ID_BLUETOOTH); - sLights[eHalLightID_Wifi] - = GetDevice(module, LIGHT_ID_WIFI); - } - } -} - -/** - * The state last set for the lights until liblights supports - * getting the light state. - */ -static light_state_t sStoredLightState[eHalLightID_Count]; - -/** -* Set the value of a light to a particular color, with a specific flash pattern. -* light specifices which light. See Hal.idl for the list of constants -* mode specifies user set or based on ambient light sensor -* flash specifies whether or how to flash the light -* flashOnMS and flashOffMS specify the pattern for XXX flash mode -* color specifies the color. If the light doesn't support color, the given color is -* transformed into a brightness, or just an on/off if that is all the light is capable of. -* returns true if successful and false if failed. -*/ -static bool -SetLight(LightType light, const LightConfiguration& aConfig) -{ - light_state_t state; - - InitLights(); - - if (light < 0 || light >= eHalLightID_Count || - sLights[light] == nullptr) { - return false; - } - - memset(&state, 0, sizeof(light_state_t)); - state.color = aConfig.color; - state.flashMode = aConfig.flash; - state.flashOnMS = aConfig.flashOnMS; - state.flashOffMS = aConfig.flashOffMS; - state.brightnessMode = aConfig.mode; - - sLights[light]->set_light(sLights[light], &state); - sStoredLightState[light] = state; - return true; -} - -/** -* GET the value of a light returning a particular color, with a specific flash pattern. -* returns true if successful and false if failed. -*/ -static bool -GetLight(LightType light, LightConfiguration* aConfig) -{ - light_state_t state; - - if (light < 0 || light >= eHalLightID_Count || - sLights[light] == nullptr) { - return false; - } - - memset(&state, 0, sizeof(light_state_t)); - state = sStoredLightState[light]; - - aConfig->light = light; - aConfig->color = state.color; - aConfig->flash = FlashMode(state.flashMode); - aConfig->flashOnMS = state.flashOnMS; - aConfig->flashOffMS = state.flashOffMS; - aConfig->mode = LightMode(state.brightnessMode); - - return true; -} - -namespace { - -/** - * This runnable runs for the lifetime of the program, once started. It's - * responsible for "playing" vibration patterns. - */ -class VibratorRunnable final - : public nsIRunnable - , public nsIObserver -{ -public: - VibratorRunnable() - : mMonitor("VibratorRunnable") - , mIndex(0) - { - nsCOMPtr os = services::GetObserverService(); - if (!os) { - NS_WARNING("Could not get observer service!"); - return; - } - - os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false); - } - - NS_DECL_THREADSAFE_ISUPPORTS - NS_DECL_NSIRUNNABLE - NS_DECL_NSIOBSERVER - - // Run on the main thread, not the vibrator thread. - void Vibrate(const nsTArray &pattern); - void CancelVibrate(); - - static bool ShuttingDown() { return sShuttingDown; } - -protected: - ~VibratorRunnable() {} - -private: - Monitor mMonitor; - - // The currently-playing pattern. - nsTArray mPattern; - - // The index we're at in the currently-playing pattern. If mIndex >= - // mPattern.Length(), then we're not currently playing anything. - uint32_t mIndex; - - // Set to true in our shutdown observer. When this is true, we kill the - // vibrator thread. - static bool sShuttingDown; -}; - -NS_IMPL_ISUPPORTS(VibratorRunnable, nsIRunnable, nsIObserver); - -bool VibratorRunnable::sShuttingDown = false; - -static StaticRefPtr sVibratorRunnable; - -NS_IMETHODIMP -VibratorRunnable::Run() -{ - MonitorAutoLock lock(mMonitor); - - // We currently assume that mMonitor.Wait(X) waits for X milliseconds. But in - // reality, the kernel might not switch to this thread for some time after the - // wait expires. So there's potential for some inaccuracy here. - // - // This doesn't worry me too much. Note that we don't even start vibrating - // immediately when VibratorRunnable::Vibrate is called -- we go through a - // condvar onto another thread. Better just to be chill about small errors in - // the timing here. - - while (!sShuttingDown) { - if (mIndex < mPattern.Length()) { - uint32_t duration = mPattern[mIndex]; - if (mIndex % 2 == 0) { - vibrator_on(duration); - } - mIndex++; - mMonitor.Wait(PR_MillisecondsToInterval(duration)); - } - else { - mMonitor.Wait(); - } - } - sVibratorRunnable = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -VibratorRunnable::Observe(nsISupports *subject, const char *topic, - const char16_t *data) -{ - MOZ_ASSERT(strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); - MonitorAutoLock lock(mMonitor); - sShuttingDown = true; - mMonitor.Notify(); - - return NS_OK; -} - -void -VibratorRunnable::Vibrate(const nsTArray &pattern) -{ - MonitorAutoLock lock(mMonitor); - mPattern = pattern; - mIndex = 0; - mMonitor.Notify(); -} - -void -VibratorRunnable::CancelVibrate() -{ - MonitorAutoLock lock(mMonitor); - mPattern.Clear(); - mPattern.AppendElement(0); - mIndex = 0; - mMonitor.Notify(); -} - -void -EnsureVibratorThreadInitialized() -{ - if (sVibratorRunnable) { - return; - } - - sVibratorRunnable = new VibratorRunnable(); - nsCOMPtr thread; - NS_NewThread(getter_AddRefs(thread), sVibratorRunnable); -} - -} // namespace - -void -Vibrate(const nsTArray &pattern, const hal::WindowIdentifier &) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (VibratorRunnable::ShuttingDown()) { - return; - } - EnsureVibratorThreadInitialized(); - sVibratorRunnable->Vibrate(pattern); -} - -void -CancelVibrate(const hal::WindowIdentifier &) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (VibratorRunnable::ShuttingDown()) { - return; - } - EnsureVibratorThreadInitialized(); - sVibratorRunnable->CancelVibrate(); -} - -namespace { - -class BatteryUpdater : public Runnable { -public: - NS_IMETHOD Run() override - { - hal::BatteryInformation info; - hal_impl::GetCurrentBatteryInformation(&info); - - // Control the battery indicator (led light) here using BatteryInformation - // we just retrieved. - uint32_t color = 0; // Format: 0x00rrggbb. - if (info.charging() && (info.level() == 1)) { - // Charging and battery full. - color = BATTERY_FULL_ARGB; - } else if (info.charging() && (info.level() < 1)) { - // Charging but not full. - color = BATTERY_CHARGING_ARGB; - } // else turn off battery indicator. - - LightConfiguration aConfig; - aConfig.light = eHalLightID_Battery; - aConfig.mode = eHalLightMode_User; - aConfig.flash = eHalLightFlash_None; - aConfig.flashOnMS = aConfig.flashOffMS = 0; - aConfig.color = color; - - SetLight(eHalLightID_Battery, aConfig); - - hal::NotifyBatteryChange(info); - - { - // bug 975667 - // Gecko gonk hal is required to emit battery charging/level notification via nsIObserverService. - // This is useful for XPCOM components that are not statically linked to Gecko and cannot call - // hal::EnableBatteryNotifications - nsCOMPtr obsService = mozilla::services::GetObserverService(); - nsCOMPtr propbag = - do_CreateInstance("@mozilla.org/hash-property-bag;1"); - if (obsService && propbag) { - propbag->SetPropertyAsBool(NS_LITERAL_STRING("charging"), - info.charging()); - propbag->SetPropertyAsDouble(NS_LITERAL_STRING("level"), - info.level()); - - obsService->NotifyObservers(propbag, "gonkhal-battery-notifier", nullptr); - } - } - - return NS_OK; - } -}; - -} // namespace - -class BatteryObserver final : public IUeventObserver -{ -public: - NS_INLINE_DECL_REFCOUNTING(BatteryObserver) - - BatteryObserver() - :mUpdater(new BatteryUpdater()) - { - } - - virtual void Notify(const NetlinkEvent &aEvent) - { - // this will run on IO thread - NetlinkEvent *event = const_cast(&aEvent); - const char *subsystem = event->getSubsystem(); - // e.g. DEVPATH=/devices/platform/sec-battery/power_supply/battery - const char *devpath = event->findParam("DEVPATH"); - if (strcmp(subsystem, "power_supply") == 0 && - strstr(devpath, "battery")) { - // aEvent will be valid only in this method. - NS_DispatchToMainThread(mUpdater); - } - } - -protected: - ~BatteryObserver() {} - -private: - RefPtr mUpdater; -}; - -// sBatteryObserver is owned by the IO thread. Only the IO thread may -// create or destroy it. -static StaticRefPtr sBatteryObserver; - -static void -RegisterBatteryObserverIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(!sBatteryObserver); - - sBatteryObserver = new BatteryObserver(); - RegisterUeventListener(sBatteryObserver); -} - -void -EnableBatteryNotifications() -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(RegisterBatteryObserverIOThread)); -} - -static void -UnregisterBatteryObserverIOThread() -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - MOZ_ASSERT(sBatteryObserver); - - UnregisterUeventListener(sBatteryObserver); - sBatteryObserver = nullptr; -} - -void -DisableBatteryNotifications() -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(UnregisterBatteryObserverIOThread)); -} - -static bool -GetCurrentBatteryCharge(int* aCharge) -{ - bool success = ReadSysFile("/sys/class/power_supply/battery/capacity", - aCharge); - if (!success) { - return false; - } - - #ifdef DEBUG - if ((*aCharge < 0) || (*aCharge > 100)) { - HAL_LOG("charge level contains unknown value: %d", *aCharge); - } - #endif - - return (*aCharge >= 0) && (*aCharge <= 100); -} - -static bool -GetCurrentBatteryCharging(int* aCharging) -{ - static const DebugOnly BATTERY_NOT_CHARGING = 0; - static const int BATTERY_CHARGING_USB = 1; - static const int BATTERY_CHARGING_AC = 2; - - // Generic device support - - int chargingSrc; - bool success = - ReadSysFile("/sys/class/power_supply/battery/charging_source", &chargingSrc); - - if (success) { - #ifdef DEBUG - if (chargingSrc != BATTERY_NOT_CHARGING && - chargingSrc != BATTERY_CHARGING_USB && - chargingSrc != BATTERY_CHARGING_AC) { - HAL_LOG("charging_source contained unknown value: %d", chargingSrc); - } - #endif - - *aCharging = (chargingSrc == BATTERY_CHARGING_USB || - chargingSrc == BATTERY_CHARGING_AC); - return true; - } - - // Otoro device support - - char chargingSrcString[16]; - - success = ReadSysFile("/sys/class/power_supply/battery/status", - chargingSrcString, sizeof(chargingSrcString)); - if (success) { - *aCharging = strcmp(chargingSrcString, "Charging") == 0 || - strcmp(chargingSrcString, "Full") == 0; - return true; - } - - return false; -} - -void -GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo) -{ - int charge; - static bool previousCharging = false; - static double previousLevel = 0.0, remainingTime = 0.0; - static struct timespec lastLevelChange; - struct timespec now; - double dtime, dlevel; - - if (GetCurrentBatteryCharge(&charge)) { - aBatteryInfo->level() = (double)charge / 100.0; - } else { - aBatteryInfo->level() = dom::battery::kDefaultLevel; - } - - int charging; - - if (GetCurrentBatteryCharging(&charging)) { - aBatteryInfo->charging() = charging; - } else { - aBatteryInfo->charging() = true; - } - - if (aBatteryInfo->charging() != previousCharging){ - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - memset(&lastLevelChange, 0, sizeof(struct timespec)); - remainingTime = 0.0; - } - - if (aBatteryInfo->charging()) { - if (aBatteryInfo->level() == 1.0) { - aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime; - } else if (aBatteryInfo->level() != previousLevel){ - if (lastLevelChange.tv_sec != 0) { - clock_gettime(CLOCK_MONOTONIC, &now); - dtime = now.tv_sec - lastLevelChange.tv_sec; - dlevel = aBatteryInfo->level() - previousLevel; - - if (dlevel <= 0.0) { - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } else { - remainingTime = (double) round(dtime / dlevel * (1.0 - aBatteryInfo->level())); - aBatteryInfo->remainingTime() = remainingTime; - } - - lastLevelChange = now; - } else { // lastLevelChange.tv_sec == 0 - clock_gettime(CLOCK_MONOTONIC, &lastLevelChange); - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } - - } else { - clock_gettime(CLOCK_MONOTONIC, &now); - dtime = now.tv_sec - lastLevelChange.tv_sec; - if (dtime < remainingTime) { - aBatteryInfo->remainingTime() = round(remainingTime - dtime); - } else { - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } - - } - - } else { - if (aBatteryInfo->level() == 0.0) { - aBatteryInfo->remainingTime() = dom::battery::kDefaultRemainingTime; - } else if (aBatteryInfo->level() != previousLevel){ - if (lastLevelChange.tv_sec != 0) { - clock_gettime(CLOCK_MONOTONIC, &now); - dtime = now.tv_sec - lastLevelChange.tv_sec; - dlevel = previousLevel - aBatteryInfo->level(); - - if (dlevel <= 0.0) { - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } else { - remainingTime = (double) round(dtime / dlevel * aBatteryInfo->level()); - aBatteryInfo->remainingTime() = remainingTime; - } - - lastLevelChange = now; - } else { // lastLevelChange.tv_sec == 0 - clock_gettime(CLOCK_MONOTONIC, &lastLevelChange); - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } - - } else { - clock_gettime(CLOCK_MONOTONIC, &now); - dtime = now.tv_sec - lastLevelChange.tv_sec; - if (dtime < remainingTime) { - aBatteryInfo->remainingTime() = round(remainingTime - dtime); - } else { - aBatteryInfo->remainingTime() = dom::battery::kUnknownRemainingTime; - } - - } - } - - previousCharging = aBatteryInfo->charging(); - previousLevel = aBatteryInfo->level(); -} - -namespace { - -// We can write to screenEnabledFilename to enable/disable the screen, but when -// we read, we always get "mem"! So we have to keep track ourselves whether -// the screen is on or not. -bool sScreenEnabled = true; - -// We can read wakeLockFilename to find out whether the cpu wake lock -// is already acquired, but reading and parsing it is a lot more work -// than tracking it ourselves, and it won't be accurate anyway (kernel -// internal wake locks aren't counted here.) -bool sCpuSleepAllowed = true; - -// Some CPU wake locks may be acquired internally in HAL. We use a counter to -// keep track of these needs. Note we have to hold |sInternalLockCpuMutex| -// when reading or writing this variable to ensure thread-safe. -int32_t sInternalLockCpuCount = 0; - -} // namespace - -bool -GetScreenEnabled() -{ - return sScreenEnabled; -} - -void -SetScreenEnabled(bool aEnabled) -{ - GetGonkDisplay()->SetEnabled(aEnabled); - sScreenEnabled = aEnabled; -} - -bool -GetKeyLightEnabled() -{ - LightConfiguration config; - bool ok = GetLight(eHalLightID_Buttons, &config); - if (ok) { - return (config.color != 0x00000000); - } - return false; -} - -void -SetKeyLightEnabled(bool aEnabled) -{ - LightConfiguration config; - config.mode = eHalLightMode_User; - config.flash = eHalLightFlash_None; - config.flashOnMS = config.flashOffMS = 0; - config.color = 0x00000000; - - if (aEnabled) { - // Convert the value in [0, 1] to an int between 0 and 255 and then convert - // it to a color. Note that the high byte is FF, corresponding to the alpha - // channel. - double brightness = GetScreenBrightness(); - uint32_t val = static_cast(round(brightness * 255.0)); - uint32_t color = (0xff<<24) + (val<<16) + (val<<8) + val; - - config.color = color; - } - - SetLight(eHalLightID_Buttons, config); - SetLight(eHalLightID_Keyboard, config); -} - -double -GetScreenBrightness() -{ - LightConfiguration config; - LightType light = eHalLightID_Backlight; - - bool ok = GetLight(light, &config); - if (ok) { - // backlight is brightness only, so using one of the RGB elements as value. - int brightness = config.color & 0xFF; - return brightness / 255.0; - } - // If GetLight fails, it's because the light doesn't exist. So return - // a value corresponding to "off". - return 0; -} - -void -SetScreenBrightness(double brightness) -{ - // Don't use De Morgan's law to push the ! into this expression; we want to - // catch NaN too. - if (!(0 <= brightness && brightness <= 1)) { - HAL_LOG("SetScreenBrightness: Dropping illegal brightness %f.", brightness); - return; - } - - // Convert the value in [0, 1] to an int between 0 and 255 and convert to a color - // note that the high byte is FF, corresponding to the alpha channel. - uint32_t val = static_cast(round(brightness * 255.0)); - uint32_t color = (0xff<<24) + (val<<16) + (val<<8) + val; - - LightConfiguration config; - config.mode = eHalLightMode_User; - config.flash = eHalLightFlash_None; - config.flashOnMS = config.flashOffMS = 0; - config.color = color; - SetLight(eHalLightID_Backlight, config); - if (GetKeyLightEnabled()) { - SetLight(eHalLightID_Buttons, config); - SetLight(eHalLightID_Keyboard, config); - } -} - -static StaticMutex sInternalLockCpuMutex; - -static void -UpdateCpuSleepState() -{ - const char *wakeLockFilename = "/sys/power/wake_lock"; - const char *wakeUnlockFilename = "/sys/power/wake_unlock"; - - sInternalLockCpuMutex.AssertCurrentThreadOwns(); - bool allowed = sCpuSleepAllowed && !sInternalLockCpuCount; - WriteSysFile(allowed ? wakeUnlockFilename : wakeLockFilename, "gecko"); -} - -static void -InternalLockCpu() { - StaticMutexAutoLock lock(sInternalLockCpuMutex); - ++sInternalLockCpuCount; - UpdateCpuSleepState(); -} - -static void -InternalUnlockCpu() { - StaticMutexAutoLock lock(sInternalLockCpuMutex); - --sInternalLockCpuCount; - UpdateCpuSleepState(); -} - -bool -GetCpuSleepAllowed() -{ - return sCpuSleepAllowed; -} - -void -SetCpuSleepAllowed(bool aAllowed) -{ - StaticMutexAutoLock lock(sInternalLockCpuMutex); - sCpuSleepAllowed = aAllowed; - UpdateCpuSleepState(); -} - -void -AdjustSystemClock(int64_t aDeltaMilliseconds) -{ - int fd; - struct timespec now; - - if (aDeltaMilliseconds == 0) { - return; - } - - // Preventing context switch before setting system clock - sched_yield(); - clock_gettime(CLOCK_REALTIME, &now); - now.tv_sec += (time_t)(aDeltaMilliseconds / 1000LL); - now.tv_nsec += (long)((aDeltaMilliseconds % 1000LL) * NsecPerMsec); - if (now.tv_nsec >= NsecPerSec) { - now.tv_sec += 1; - now.tv_nsec -= NsecPerSec; - } - - if (now.tv_nsec < 0) { - now.tv_nsec += NsecPerSec; - now.tv_sec -= 1; - } - - do { - fd = open("/dev/alarm", O_RDWR); - } while (fd == -1 && errno == EINTR); - ScopedClose autoClose(fd); - if (fd < 0) { - HAL_LOG("Failed to open /dev/alarm: %s", strerror(errno)); - return; - } - - if (ioctl(fd, ANDROID_ALARM_SET_RTC, &now) < 0) { - HAL_LOG("ANDROID_ALARM_SET_RTC failed: %s", strerror(errno)); - } - - hal::NotifySystemClockChange(aDeltaMilliseconds); -} - -int32_t -GetTimezoneOffset() -{ - PRExplodedTime prTime; - PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prTime); - - // Daylight saving time (DST) will be taken into account. - int32_t offset = prTime.tm_params.tp_gmt_offset; - offset += prTime.tm_params.tp_dst_offset; - - // Returns the timezone offset relative to UTC in minutes. - return -(offset / 60); -} - -static int32_t sKernelTimezoneOffset = 0; - -static void -UpdateKernelTimezone(int32_t timezoneOffset) -{ - if (sKernelTimezoneOffset == timezoneOffset) { - return; - } - - // Tell the kernel about the new time zone as well, so that FAT filesystems - // will get local timestamps rather than UTC timestamps. - // - // We assume that /init.rc has a sysclktz entry so that settimeofday has - // already been called once before we call it (there is a side-effect in - // the kernel the very first time settimeofday is called where it does some - // special processing if you only set the timezone). - struct timezone tz; - memset(&tz, 0, sizeof(tz)); - tz.tz_minuteswest = timezoneOffset; - settimeofday(nullptr, &tz); - sKernelTimezoneOffset = timezoneOffset; -} - -void -SetTimezone(const nsCString& aTimezoneSpec) -{ - if (aTimezoneSpec.Equals(GetTimezone())) { - // Even though the timezone hasn't changed, we still need to tell the - // kernel what the current timezone is. The timezone is persisted in - // a property and doesn't change across reboots, but the kernel still - // needs to be updated on every boot. - UpdateKernelTimezone(GetTimezoneOffset()); - return; - } - - int32_t oldTimezoneOffsetMinutes = GetTimezoneOffset(); - property_set("persist.sys.timezone", aTimezoneSpec.get()); - // This function is automatically called by the other time conversion - // functions that depend on the timezone. To be safe, we call it manually. - tzset(); - int32_t newTimezoneOffsetMinutes = GetTimezoneOffset(); - UpdateKernelTimezone(newTimezoneOffsetMinutes); - hal::NotifySystemTimezoneChange( - hal::SystemTimezoneChangeInformation( - oldTimezoneOffsetMinutes, newTimezoneOffsetMinutes)); -} - -nsCString -GetTimezone() -{ - char timezone[32]; - property_get("persist.sys.timezone", timezone, ""); - return nsCString(timezone); -} - -void -EnableSystemClockChangeNotifications() -{ -} - -void -DisableSystemClockChangeNotifications() -{ -} - -void -EnableSystemTimezoneChangeNotifications() -{ -} - -void -DisableSystemTimezoneChangeNotifications() -{ -} - -// Nothing to do here. Gonk widgetry always listens for screen -// orientation changes. -void -EnableScreenConfigurationNotifications() -{ -} - -void -DisableScreenConfigurationNotifications() -{ -} - -void -GetCurrentScreenConfiguration(hal::ScreenConfiguration* aScreenConfiguration) -{ - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - *aScreenConfiguration = screen->GetConfiguration(); -} - -bool -LockScreenOrientation(const dom::ScreenOrientationInternal& aOrientation) -{ - return OrientationObserver::GetInstance()->LockScreenOrientation(aOrientation); -} - -void -UnlockScreenOrientation() -{ - OrientationObserver::GetInstance()->UnlockScreenOrientation(); -} - -// This thread will wait for the alarm firing by a blocking IO. -static pthread_t sAlarmFireWatcherThread; - -// If |sAlarmData| is non-null, it's owned by the alarm-watcher thread. -struct AlarmData { -public: - AlarmData(int aFd) : mFd(aFd), - mGeneration(sNextGeneration++), - mShuttingDown(false) {} - ScopedClose mFd; - int mGeneration; - bool mShuttingDown; - - static int sNextGeneration; - -}; - -int AlarmData::sNextGeneration = 0; - -AlarmData* sAlarmData = nullptr; - -class AlarmFiredEvent : public Runnable { -public: - AlarmFiredEvent(int aGeneration) : mGeneration(aGeneration) {} - - NS_IMETHOD Run() override { - // Guard against spurious notifications caused by an alarm firing - // concurrently with it being disabled. - if (sAlarmData && !sAlarmData->mShuttingDown && - mGeneration == sAlarmData->mGeneration) { - hal::NotifyAlarmFired(); - } - // The fired alarm event has been delivered to the observer (if needed); - // we can now release a CPU wake lock. - InternalUnlockCpu(); - return NS_OK; - } - -private: - int mGeneration; -}; - -// Runs on alarm-watcher thread. -static void -DestroyAlarmData(void* aData) -{ - AlarmData* alarmData = static_cast(aData); - delete alarmData; -} - -// Runs on alarm-watcher thread. -void ShutDownAlarm(int aSigno) -{ - if (aSigno == SIGUSR1 && sAlarmData) { - sAlarmData->mShuttingDown = true; - } - return; -} - -static void* -WaitForAlarm(void* aData) -{ - pthread_cleanup_push(DestroyAlarmData, aData); - - AlarmData* alarmData = static_cast(aData); - - while (!alarmData->mShuttingDown) { - int alarmTypeFlags = 0; - - // ALARM_WAIT apparently will block even if an alarm hasn't been - // programmed, although this behavior doesn't seem to be - // documented. We rely on that here to avoid spinning the CPU - // while awaiting an alarm to be programmed. - do { - alarmTypeFlags = ioctl(alarmData->mFd, ANDROID_ALARM_WAIT); - } while (alarmTypeFlags < 0 && errno == EINTR && - !alarmData->mShuttingDown); - - if (!alarmData->mShuttingDown && alarmTypeFlags >= 0 && - (alarmTypeFlags & ANDROID_ALARM_RTC_WAKEUP_MASK)) { - // To make sure the observer can get the alarm firing notification - // *on time* (the system won't sleep during the process in any way), - // we need to acquire a CPU wake lock before firing the alarm event. - InternalLockCpu(); - RefPtr event = - new AlarmFiredEvent(alarmData->mGeneration); - NS_DispatchToMainThread(event); - } - } - - pthread_cleanup_pop(1); - return nullptr; -} - -bool -EnableAlarm() -{ - MOZ_ASSERT(!sAlarmData); - - int alarmFd = open("/dev/alarm", O_RDWR); - if (alarmFd < 0) { - HAL_LOG("Failed to open alarm device: %s.", strerror(errno)); - return false; - } - - UniquePtr alarmData = MakeUnique(alarmFd); - - struct sigaction actions; - memset(&actions, 0, sizeof(actions)); - sigemptyset(&actions.sa_mask); - actions.sa_flags = 0; - actions.sa_handler = ShutDownAlarm; - if (sigaction(SIGUSR1, &actions, nullptr)) { - HAL_LOG("Failed to set SIGUSR1 signal for alarm-watcher thread."); - return false; - } - - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); - - int status = pthread_create(&sAlarmFireWatcherThread, &attr, WaitForAlarm, - alarmData.get()); - if (status) { - alarmData.reset(); - HAL_LOG("Failed to create alarm-watcher thread. Status: %d.", status); - return false; - } - - pthread_attr_destroy(&attr); - - // The thread owns this now. We only hold a pointer. - sAlarmData = alarmData.release(); - return true; -} - -void -DisableAlarm() -{ - MOZ_ASSERT(sAlarmData); - - // NB: this must happen-before the thread cancellation. - sAlarmData = nullptr; - - // The cancel will interrupt the thread and destroy it, freeing the - // data pointed at by sAlarmData. - DebugOnly err = pthread_kill(sAlarmFireWatcherThread, SIGUSR1); - MOZ_ASSERT(!err); -} - -bool -SetAlarm(int32_t aSeconds, int32_t aNanoseconds) -{ - if (!sAlarmData) { - HAL_LOG("We should have enabled the alarm."); - return false; - } - - struct timespec ts; - ts.tv_sec = aSeconds; - ts.tv_nsec = aNanoseconds; - - // Currently we only support RTC wakeup alarm type. - const int result = ioctl(sAlarmData->mFd, - ANDROID_ALARM_SET(ANDROID_ALARM_RTC_WAKEUP), &ts); - - if (result < 0) { - HAL_LOG("Unable to set alarm: %s.", strerror(errno)); - return false; - } - - return true; -} - -static int -OomAdjOfOomScoreAdj(int aOomScoreAdj) -{ - // Convert OOM adjustment from the domain of /proc//oom_score_adj - // to the domain of /proc//oom_adj. - - int adj; - - if (aOomScoreAdj < 0) { - adj = (OOM_DISABLE * aOomScoreAdj) / OOM_SCORE_ADJ_MIN; - } else { - adj = (OOM_ADJUST_MAX * aOomScoreAdj) / OOM_SCORE_ADJ_MAX; - } - - return adj; -} - -static void -RoundOomScoreAdjUpWithLRU(int& aOomScoreAdj, uint32_t aLRU) -{ - // We want to add minimum value to round OomScoreAdj up according to - // the steps by aLRU. - aOomScoreAdj += - ceil(((float)OOM_SCORE_ADJ_MAX / OOM_ADJUST_MAX) * aLRU); -} - -#define OOM_LOG(level, args...) __android_log_print(level, "OomLogger", ##args) -class OomVictimLogger final - : public nsIObserver -{ -public: - OomVictimLogger() - : mLastLineChecked(-1.0), - mRegexes(nullptr) - { - // Enable timestamps in kernel's printk - WriteSysFile("/sys/module/printk/parameters/time", "Y"); - } - - NS_DECL_ISUPPORTS - NS_DECL_NSIOBSERVER - -protected: - ~OomVictimLogger() {} - -private: - double mLastLineChecked; - UniqueFreePtr mRegexes; -}; -NS_IMPL_ISUPPORTS(OomVictimLogger, nsIObserver); - -NS_IMETHODIMP -OomVictimLogger::Observe( - nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - nsDependentCString event_type(aTopic); - if (!event_type.EqualsLiteral("ipc:content-shutdown")) { - return NS_OK; - } - - // OOM message finding regexes - const char* const regexes_raw[] = { - ".*select.*to kill.*", - ".*send sigkill to.*", - ".*lowmem_shrink.*", - ".*[Oo]ut of [Mm]emory.*", - ".*[Kk]ill [Pp]rocess.*", - ".*[Kk]illed [Pp]rocess.*", - ".*oom-killer.*", - // The regexes below are for the output of dump_task from oom_kill.c - // 1st - title 2nd - body lines (8 ints and a string) - // oom_adj and oom_score_adj can be negative - "\\[ pid \\] uid tgid total_vm rss cpu oom_adj oom_score_adj name", - "\\[.*[0-9][0-9]*\\][ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*[0-9][0-9]*[ ]*.[0-9][0-9]*[ ]*.[0-9][0-9]*.*" - }; - const size_t regex_count = ArrayLength(regexes_raw); - - // Compile our regex just in time - if (!mRegexes) { - UniqueFreePtr regexes( - static_cast(malloc(sizeof(regex_t) * regex_count)) - ); - mRegexes.swap(regexes); - for (size_t i = 0; i < regex_count; i++) { - int compilation_err = - regcomp(&(mRegexes.get()[i]), regexes_raw[i], REG_NOSUB); - if (compilation_err) { - OOM_LOG(ANDROID_LOG_ERROR, "Cannot compile regex \"%s\"\n", regexes_raw[i]); - return NS_OK; - } - } - } - -#ifndef KLOG_SIZE_BUFFER - // Upstream bionic in commit - // e249b059637b49a285ed9f58a2a18bfd054e5d95 - // deprecated the old klog defs. - // Our current bionic does not hit this - // change yet so handle the future change. - // (ICS doesn't have KLOG_SIZE_BUFFER but - // JB and onwards does.) - #define KLOG_SIZE_BUFFER KLOG_WRITE -#endif - // Retreive kernel log - int msg_buf_size = klogctl(KLOG_SIZE_BUFFER, NULL, 0); - UniqueFreePtr msg_buf(static_cast(malloc(msg_buf_size + 1))); - int read_size = klogctl(KLOG_READ_ALL, msg_buf.get(), msg_buf_size); - - // Turn buffer into cstring - read_size = read_size > msg_buf_size ? msg_buf_size : read_size; - msg_buf.get()[read_size] = '\0'; - - // Foreach line - char* line_end; - char* line_begin = msg_buf.get(); - for (; (line_end = strchr(line_begin, '\n')); line_begin = line_end + 1) { - // make line into cstring - *line_end = '\0'; - - // Note: Kernel messages look like: - // <5>[63648.286409] sd 35:0:0:0: Attached scsi generic sg1 type 0 - // 5 is the loging level - // [*] is the time timestamp, seconds since boot - // last comes the logged message - - // Since the logging level can be a string we must - // skip it since scanf lacks wildcard matching - char* timestamp_begin = strchr(line_begin, '['); - char after_float; - double lineTimestamp = -1; - bool lineTimestampFound = false; - if (timestamp_begin && - // Note: scanf treats a ' ' as [ ]* - // Note: scanf treats [ %lf] as [ %lf thus we must check - // for the closing bracket outselves. - 2 == sscanf(timestamp_begin, "[ %lf%c", &lineTimestamp, &after_float) && - after_float == ']') { - if (lineTimestamp <= mLastLineChecked) { - continue; - } - - lineTimestampFound = true; - mLastLineChecked = lineTimestamp; - } - - // Log interesting lines - for (size_t i = 0; i < regex_count; i++) { - int matching = !regexec(&(mRegexes.get()[i]), line_begin, 0, NULL, 0); - if (matching) { - // Log content of kernel message. We try to skip the ], but if for - // some reason (most likely due to buffer overflow/wraparound), we - // can't find the ] then we just log the entire line. - char* endOfTimestamp = strchr(line_begin, ']'); - if (endOfTimestamp && endOfTimestamp[1] == ' ') { - // skip the ] and the space that follows it - line_begin = endOfTimestamp + 2; - } - if (!lineTimestampFound) { - OOM_LOG(ANDROID_LOG_WARN, "following kill message may be a duplicate"); - } - OOM_LOG(ANDROID_LOG_ERROR, "[Kill]: %s\n", line_begin); - break; - } - } - } - - return NS_OK; -} - -/** - * Wraps a particular ProcessPriority, giving us easy access to the prefs that - * are relevant to it. - * - * Creating a PriorityClass also ensures that the control group is created. - */ -class PriorityClass -{ -public: - /** - * Create a PriorityClass for the given ProcessPriority. This implicitly - * reads the relevant prefs and opens the cgroup.procs file of the relevant - * control group caching its file descriptor for later use. - */ - PriorityClass(ProcessPriority aPriority); - - /** - * Closes the file descriptor for the cgroup.procs file of the associated - * control group. - */ - ~PriorityClass(); - - PriorityClass(const PriorityClass& aOther); - PriorityClass& operator=(const PriorityClass& aOther); - - ProcessPriority Priority() - { - return mPriority; - } - - int32_t OomScoreAdj() - { - return clamped(mOomScoreAdj, OOM_SCORE_ADJ_MIN, OOM_SCORE_ADJ_MAX); - } - - int32_t KillUnderKB() - { - return mKillUnderKB; - } - - nsCString CGroup() - { - return mGroup; - } - - /** - * Adds a process to this priority class, this moves the process' PID into - * the associated control group. - * - * @param aPid The PID of the process to be added. - */ - void AddProcess(int aPid); - -private: - ProcessPriority mPriority; - int32_t mOomScoreAdj; - int32_t mKillUnderKB; - int mCpuCGroupProcsFd; - int mMemCGroupProcsFd; - nsCString mGroup; - - /** - * Return a string that identifies where we can find the value of aPref - * that's specific to mPriority. For example, we might return - * "hal.processPriorityManager.gonk.FOREGROUND_HIGH.oomScoreAdjust". - */ - nsCString PriorityPrefName(const char* aPref) - { - return nsPrintfCString("hal.processPriorityManager.gonk.%s.%s", - ProcessPriorityToString(mPriority), aPref); - } - - /** - * Get the full path of the cgroup.procs file associated with the group. - */ - nsCString CpuCGroupProcsFilename() - { - nsCString cgroupName = mGroup; - - /* If mGroup is empty, our cgroup.procs file is the root procs file, - * located at /dev/cpuctl/cgroup.procs. Otherwise our procs file is - * /dev/cpuctl/NAME/cgroup.procs. */ - - if (!mGroup.IsEmpty()) { - cgroupName.AppendLiteral("/"); - } - - return NS_LITERAL_CSTRING("/dev/cpuctl/") + cgroupName + - NS_LITERAL_CSTRING("cgroup.procs"); - } - - nsCString MemCGroupProcsFilename() - { - nsCString cgroupName = mGroup; - - /* If mGroup is empty, our cgroup.procs file is the root procs file, - * located at /sys/fs/cgroup/memory/cgroup.procs. Otherwise our procs - * file is /sys/fs/cgroup/memory/NAME/cgroup.procs. */ - - if (!mGroup.IsEmpty()) { - cgroupName.AppendLiteral("/"); - } - - return NS_LITERAL_CSTRING("/sys/fs/cgroup/memory/") + cgroupName + - NS_LITERAL_CSTRING("cgroup.procs"); - } - - int OpenCpuCGroupProcs() - { - return open(CpuCGroupProcsFilename().get(), O_WRONLY); - } - - int OpenMemCGroupProcs() - { - return open(MemCGroupProcsFilename().get(), O_WRONLY); - } -}; - -/** - * Try to create the cgroup for the given PriorityClass, if it doesn't already - * exist. This essentially implements mkdir -p; that is, we create parent - * cgroups as necessary. The group parameters are also set according to - * the corresponding preferences. - * - * @param aGroup The name of the group. - * @return true if we successfully created the cgroup, or if it already - * exists. Otherwise, return false. - */ -static bool -EnsureCpuCGroupExists(const nsACString &aGroup) -{ - NS_NAMED_LITERAL_CSTRING(kDevCpuCtl, "/dev/cpuctl/"); - NS_NAMED_LITERAL_CSTRING(kSlash, "/"); - - nsAutoCString groupName(aGroup); - HAL_LOG("EnsureCpuCGroupExists for group '%s'", groupName.get()); - - nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups."); - - /* If cgroup is not empty, append the cgroup name and a dot to obtain the - * group specific preferences. */ - if (!aGroup.IsEmpty()) { - prefPrefix += aGroup + NS_LITERAL_CSTRING("."); - } - - nsAutoCString cpuSharesPref(prefPrefix + NS_LITERAL_CSTRING("cpu_shares")); - int cpuShares = Preferences::GetInt(cpuSharesPref.get()); - - nsAutoCString cpuNotifyOnMigratePref(prefPrefix - + NS_LITERAL_CSTRING("cpu_notify_on_migrate")); - int cpuNotifyOnMigrate = Preferences::GetInt(cpuNotifyOnMigratePref.get()); - - // Create mCGroup and its parent directories, as necessary. - nsCString cgroupIter = aGroup + kSlash; - - int32_t offset = 0; - while ((offset = cgroupIter.FindChar('/', offset)) != -1) { - nsAutoCString path = kDevCpuCtl + Substring(cgroupIter, 0, offset); - int rv = mkdir(path.get(), 0744); - - if (rv == -1 && errno != EEXIST) { - HAL_LOG("Could not create the %s control group.", path.get()); - return false; - } - - offset++; - } - HAL_LOG("EnsureCpuCGroupExists created group '%s'", groupName.get()); - - nsAutoCString pathPrefix(kDevCpuCtl + aGroup + kSlash); - nsAutoCString cpuSharesPath(pathPrefix + NS_LITERAL_CSTRING("cpu.shares")); - if (cpuShares && !WriteSysFile(cpuSharesPath.get(), - nsPrintfCString("%d", cpuShares).get())) { - HAL_LOG("Could not set the cpu share for group %s", cpuSharesPath.get()); - return false; - } - - nsAutoCString notifyOnMigratePath(pathPrefix - + NS_LITERAL_CSTRING("cpu.notify_on_migrate")); - if (!WriteSysFile(notifyOnMigratePath.get(), - nsPrintfCString("%d", cpuNotifyOnMigrate).get())) { - HAL_LOG("Could not set the cpu migration notification flag for group %s", - notifyOnMigratePath.get()); - return false; - } - - return true; -} - -static bool -EnsureMemCGroupExists(const nsACString &aGroup) -{ - NS_NAMED_LITERAL_CSTRING(kMemCtl, "/sys/fs/cgroup/memory/"); - NS_NAMED_LITERAL_CSTRING(kSlash, "/"); - - nsAutoCString groupName(aGroup); - HAL_LOG("EnsureMemCGroupExists for group '%s'", groupName.get()); - - nsAutoCString prefPrefix("hal.processPriorityManager.gonk.cgroups."); - - /* If cgroup is not empty, append the cgroup name and a dot to obtain the - * group specific preferences. */ - if (!aGroup.IsEmpty()) { - prefPrefix += aGroup + NS_LITERAL_CSTRING("."); - } - - nsAutoCString memSwappinessPref(prefPrefix + NS_LITERAL_CSTRING("memory_swappiness")); - int memSwappiness = Preferences::GetInt(memSwappinessPref.get()); - - // Create mCGroup and its parent directories, as necessary. - nsCString cgroupIter = aGroup + kSlash; - - int32_t offset = 0; - while ((offset = cgroupIter.FindChar('/', offset)) != -1) { - nsAutoCString path = kMemCtl + Substring(cgroupIter, 0, offset); - int rv = mkdir(path.get(), 0744); - - if (rv == -1 && errno != EEXIST) { - HAL_LOG("Could not create the %s control group.", path.get()); - return false; - } - - offset++; - } - HAL_LOG("EnsureMemCGroupExists created group '%s'", groupName.get()); - - nsAutoCString pathPrefix(kMemCtl + aGroup + kSlash); - nsAutoCString memSwappinessPath(pathPrefix + NS_LITERAL_CSTRING("memory.swappiness")); - if (!WriteSysFile(memSwappinessPath.get(), - nsPrintfCString("%d", memSwappiness).get())) { - HAL_LOG("Could not set the memory.swappiness for group %s", memSwappinessPath.get()); - return false; - } - HAL_LOG("Set memory.swappiness for group %s to %d", memSwappinessPath.get(), memSwappiness); - - return true; -} - -PriorityClass::PriorityClass(ProcessPriority aPriority) - : mPriority(aPriority) - , mOomScoreAdj(0) - , mKillUnderKB(0) - , mCpuCGroupProcsFd(-1) - , mMemCGroupProcsFd(-1) -{ - DebugOnly rv; - - rv = Preferences::GetInt(PriorityPrefName("OomScoreAdjust").get(), - &mOomScoreAdj); - MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing oom_score_adj preference"); - - rv = Preferences::GetInt(PriorityPrefName("KillUnderKB").get(), - &mKillUnderKB); - - rv = Preferences::GetCString(PriorityPrefName("cgroup").get(), &mGroup); - MOZ_ASSERT(NS_SUCCEEDED(rv), "Missing control group preference"); - - if (EnsureCpuCGroupExists(mGroup)) { - mCpuCGroupProcsFd = OpenCpuCGroupProcs(); - } - if (EnsureMemCGroupExists(mGroup)) { - mMemCGroupProcsFd = OpenMemCGroupProcs(); - } -} - -PriorityClass::~PriorityClass() -{ - if (mCpuCGroupProcsFd != -1) { - close(mCpuCGroupProcsFd); - } - if (mMemCGroupProcsFd != -1) { - close(mMemCGroupProcsFd); - } -} - -PriorityClass::PriorityClass(const PriorityClass& aOther) - : mPriority(aOther.mPriority) - , mOomScoreAdj(aOther.mOomScoreAdj) - , mKillUnderKB(aOther.mKillUnderKB) - , mGroup(aOther.mGroup) -{ - mCpuCGroupProcsFd = OpenCpuCGroupProcs(); - mMemCGroupProcsFd = OpenMemCGroupProcs(); -} - -PriorityClass& PriorityClass::operator=(const PriorityClass& aOther) -{ - mPriority = aOther.mPriority; - mOomScoreAdj = aOther.mOomScoreAdj; - mKillUnderKB = aOther.mKillUnderKB; - mGroup = aOther.mGroup; - mCpuCGroupProcsFd = OpenCpuCGroupProcs(); - mMemCGroupProcsFd = OpenMemCGroupProcs(); - return *this; -} - -void PriorityClass::AddProcess(int aPid) -{ - if (mCpuCGroupProcsFd >= 0) { - nsPrintfCString str("%d", aPid); - - if (write(mCpuCGroupProcsFd, str.get(), strlen(str.get())) < 0) { - HAL_ERR("Couldn't add PID %d to the %s cpu control group", aPid, mGroup.get()); - } - } - if (mMemCGroupProcsFd >= 0) { - nsPrintfCString str("%d", aPid); - - if (write(mMemCGroupProcsFd, str.get(), strlen(str.get())) < 0) { - HAL_ERR("Couldn't add PID %d to the %s memory control group", aPid, mGroup.get()); - } - } -} - -/** - * Get the PriorityClass associated with the given ProcessPriority. - * - * If you pass an invalid ProcessPriority value, we return null. - * - * The pointers returned here are owned by GetPriorityClass (don't free them - * yourself). They are guaranteed to stick around until shutdown. - */ -PriorityClass* -GetPriorityClass(ProcessPriority aPriority) -{ - static StaticAutoPtr> priorityClasses; - - // Initialize priorityClasses if this is the first time we're running this - // method. - if (!priorityClasses) { - priorityClasses = new nsTArray(); - ClearOnShutdown(&priorityClasses); - - for (int32_t i = 0; i < NUM_PROCESS_PRIORITY; i++) { - priorityClasses->AppendElement(PriorityClass(ProcessPriority(i))); - } - } - - if (aPriority < 0 || - static_cast(aPriority) >= priorityClasses->Length()) { - return nullptr; - } - - return &(*priorityClasses)[aPriority]; -} - -static void -EnsureKernelLowMemKillerParamsSet() -{ - static bool kernelLowMemKillerParamsSet; - if (kernelLowMemKillerParamsSet) { - return; - } - kernelLowMemKillerParamsSet = true; - - HAL_LOG("Setting kernel's low-mem killer parameters."); - - // Set /sys/module/lowmemorykiller/parameters/{adj,minfree,notify_trigger} - // according to our prefs. These files let us tune when the kernel kills - // processes when we're low on memory, and when it notifies us that we're - // running low on available memory. - // - // adj and minfree are both comma-separated lists of integers. If adj="A,B" - // and minfree="X,Y", then the kernel will kill processes with oom_adj - // A or higher once we have fewer than X pages of memory free, and will kill - // processes with oom_adj B or higher once we have fewer than Y pages of - // memory free. - // - // notify_trigger is a single integer. If we set notify_trigger=Z, then - // we'll get notified when there are fewer than Z pages of memory free. (See - // GonkMemoryPressureMonitoring.cpp.) - - // Build the adj and minfree strings. - nsAutoCString adjParams; - nsAutoCString minfreeParams; - - DebugOnly lowerBoundOfNextOomScoreAdj = OOM_SCORE_ADJ_MIN - 1; - DebugOnly lowerBoundOfNextKillUnderKB = 0; - int32_t countOfLowmemorykillerParametersSets = 0; - - long page_size = sysconf(_SC_PAGESIZE); - - for (int i = NUM_PROCESS_PRIORITY - 1; i >= 0; i--) { - // The system doesn't function correctly if we're missing these prefs, so - // crash loudly. - - PriorityClass* pc = GetPriorityClass(static_cast(i)); - - int32_t oomScoreAdj = pc->OomScoreAdj(); - int32_t killUnderKB = pc->KillUnderKB(); - - if (killUnderKB == 0) { - // ProcessPriority values like PROCESS_PRIORITY_FOREGROUND_KEYBOARD, - // which has only OomScoreAdjust but lacks KillUnderMB value, will not - // create new LMK parameters. - continue; - } - - // The LMK in kernel silently malfunctions if we assign the parameters - // in non-increasing order, so we add this assertion here. See bug 887192. - MOZ_ASSERT(oomScoreAdj > lowerBoundOfNextOomScoreAdj); - MOZ_ASSERT(killUnderKB > lowerBoundOfNextKillUnderKB); - - // The LMK in kernel only accept 6 sets of LMK parameters. See bug 914728. - MOZ_ASSERT(countOfLowmemorykillerParametersSets < 6); - - // adj is in oom_adj units. - adjParams.AppendPrintf("%d,", OomAdjOfOomScoreAdj(oomScoreAdj)); - - // minfree is in pages. - minfreeParams.AppendPrintf("%ld,", killUnderKB * 1024 / page_size); - - lowerBoundOfNextOomScoreAdj = oomScoreAdj; - lowerBoundOfNextKillUnderKB = killUnderKB; - countOfLowmemorykillerParametersSets++; - } - - // Strip off trailing commas. - adjParams.Cut(adjParams.Length() - 1, 1); - minfreeParams.Cut(minfreeParams.Length() - 1, 1); - if (!adjParams.IsEmpty() && !minfreeParams.IsEmpty()) { - WriteSysFile("/sys/module/lowmemorykiller/parameters/adj", adjParams.get()); - WriteSysFile("/sys/module/lowmemorykiller/parameters/minfree", - minfreeParams.get()); - } - - // Set the low-memory-notification threshold. - int32_t lowMemNotifyThresholdKB; - if (NS_SUCCEEDED(Preferences::GetInt( - "hal.processPriorityManager.gonk.notifyLowMemUnderKB", - &lowMemNotifyThresholdKB))) { - - // notify_trigger is in pages. - WriteSysFile("/sys/module/lowmemorykiller/parameters/notify_trigger", - nsPrintfCString("%ld", lowMemNotifyThresholdKB * 1024 / page_size).get()); - } - - // Ensure OOM events appear in logcat - RefPtr oomLogger = new OomVictimLogger(); - nsCOMPtr os = services::GetObserverService(); - if (os) { - os->AddObserver(oomLogger, "ipc:content-shutdown", false); - } -} - -void -SetProcessPriority(int aPid, ProcessPriority aPriority, uint32_t aLRU) -{ - HAL_LOG("SetProcessPriority(pid=%d, priority=%d, LRU=%u)", - aPid, aPriority, aLRU); - - // If this is the first time SetProcessPriority was called, set the kernel's - // OOM parameters according to our prefs. - // - // We could/should do this on startup instead of waiting for the first - // SetProcessPriorityCall. But in practice, the master process needs to set - // its priority early in the game, so we can reasonably rely on - // SetProcessPriority being called early in startup. - EnsureKernelLowMemKillerParamsSet(); - - PriorityClass* pc = GetPriorityClass(aPriority); - - int oomScoreAdj = pc->OomScoreAdj(); - - RoundOomScoreAdjUpWithLRU(oomScoreAdj, aLRU); - - // We try the newer interface first, and fall back to the older interface - // on failure. - if (!WriteSysFile(nsPrintfCString("/proc/%d/oom_score_adj", aPid).get(), - nsPrintfCString("%d", oomScoreAdj).get())) - { - WriteSysFile(nsPrintfCString("/proc/%d/oom_adj", aPid).get(), - nsPrintfCString("%d", OomAdjOfOomScoreAdj(oomScoreAdj)).get()); - } - - HAL_LOG("Assigning pid %d to cgroup %s", aPid, pc->CGroup().get()); - pc->AddProcess(aPid); -} - -static bool -IsValidRealTimePriority(int aValue, int aSchedulePolicy) -{ - return (aValue >= sched_get_priority_min(aSchedulePolicy)) && - (aValue <= sched_get_priority_max(aSchedulePolicy)); -} - -static void -SetThreadNiceValue(pid_t aTid, ThreadPriority aThreadPriority, int aValue) -{ - MOZ_ASSERT(aThreadPriority < NUM_THREAD_PRIORITY); - MOZ_ASSERT(aThreadPriority >= 0); - - HAL_LOG("Setting thread %d to priority level %s; nice level %d", - aTid, ThreadPriorityToString(aThreadPriority), aValue); - int rv = setpriority(PRIO_PROCESS, aTid, aValue); - - if (rv) { - HAL_LOG("Failed to set thread %d to priority level %s; error %s", aTid, - ThreadPriorityToString(aThreadPriority), strerror(errno)); - } -} - -static void -SetRealTimeThreadPriority(pid_t aTid, - ThreadPriority aThreadPriority, - int aValue) -{ - int policy = SCHED_FIFO; - - MOZ_ASSERT(aThreadPriority < NUM_THREAD_PRIORITY); - MOZ_ASSERT(aThreadPriority >= 0); - MOZ_ASSERT(IsValidRealTimePriority(aValue, policy), "Invalid real time priority"); - - // Setting real time priorities requires using sched_setscheduler - HAL_LOG("Setting thread %d to priority level %s; Real Time priority %d, " - "Schedule FIFO", aTid, ThreadPriorityToString(aThreadPriority), - aValue); - sched_param schedParam; - schedParam.sched_priority = aValue; - int rv = sched_setscheduler(aTid, policy, &schedParam); - - if (rv) { - HAL_LOG("Failed to set thread %d to real time priority level %s; error %s", - aTid, ThreadPriorityToString(aThreadPriority), strerror(errno)); - } -} - -/* - * Used to store the nice value adjustments and real time priorities for the - * various thread priority levels. - */ -struct ThreadPriorityPrefs { - bool initialized; - struct { - int nice; - int realTime; - } priorities[NUM_THREAD_PRIORITY]; -}; - -/* - * Reads the preferences for the various process priority levels and sets up - * watchers so that if they're dynamically changed the change is reflected on - * the appropriate variables. - */ -void -EnsureThreadPriorityPrefs(ThreadPriorityPrefs* prefs) -{ - if (prefs->initialized) { - return; - } - - for (int i = THREAD_PRIORITY_COMPOSITOR; i < NUM_THREAD_PRIORITY; i++) { - ThreadPriority priority = static_cast(i); - - // Read the nice values - const char* threadPriorityStr = ThreadPriorityToString(priority); - nsPrintfCString niceStr("hal.gonk.%s.nice", threadPriorityStr); - Preferences::AddIntVarCache(&prefs->priorities[i].nice, niceStr.get()); - - // Read the real-time priorities - nsPrintfCString realTimeStr("hal.gonk.%s.rt_priority", threadPriorityStr); - Preferences::AddIntVarCache(&prefs->priorities[i].realTime, - realTimeStr.get()); - } - - prefs->initialized = true; -} - -static void -DoSetThreadPriority(pid_t aTid, hal::ThreadPriority aThreadPriority) -{ - // See bug 999115, we can only read preferences on the main thread otherwise - // we create a race condition in HAL - MOZ_ASSERT(NS_IsMainThread(), "Can only set thread priorities on main thread"); - MOZ_ASSERT(aThreadPriority >= 0); - - static ThreadPriorityPrefs prefs = { 0 }; - EnsureThreadPriorityPrefs(&prefs); - - switch (aThreadPriority) { - case THREAD_PRIORITY_COMPOSITOR: - break; - default: - HAL_ERR("Unrecognized thread priority %d; Doing nothing", - aThreadPriority); - return; - } - - int realTimePriority = prefs.priorities[aThreadPriority].realTime; - - if (IsValidRealTimePriority(realTimePriority, SCHED_FIFO)) { - SetRealTimeThreadPriority(aTid, aThreadPriority, realTimePriority); - return; - } - - SetThreadNiceValue(aTid, aThreadPriority, - prefs.priorities[aThreadPriority].nice); -} - -namespace { - -/** - * This class sets the priority of threads given the kernel thread's id and a - * value taken from hal::ThreadPriority. - * - * This runnable must always be dispatched to the main thread otherwise it will fail. - * We have to run this from the main thread since preferences can only be read on - * main thread. - */ -class SetThreadPriorityRunnable : public Runnable -{ -public: - SetThreadPriorityRunnable(pid_t aThreadId, hal::ThreadPriority aThreadPriority) - : mThreadId(aThreadId) - , mThreadPriority(aThreadPriority) - { } - - NS_IMETHOD Run() override - { - NS_ASSERTION(NS_IsMainThread(), "Can only set thread priorities on main thread"); - hal_impl::DoSetThreadPriority(mThreadId, mThreadPriority); - return NS_OK; - } - -private: - pid_t mThreadId; - hal::ThreadPriority mThreadPriority; -}; - -} // namespace - -void -SetCurrentThreadPriority(ThreadPriority aThreadPriority) -{ - pid_t threadId = gettid(); - hal_impl::SetThreadPriority(threadId, aThreadPriority); -} - -void -SetThreadPriority(PlatformThreadId aThreadId, - ThreadPriority aThreadPriority) -{ - switch (aThreadPriority) { - case THREAD_PRIORITY_COMPOSITOR: { - nsCOMPtr runnable = - new SetThreadPriorityRunnable(aThreadId, aThreadPriority); - NS_DispatchToMainThread(runnable); - break; - } - default: - HAL_LOG("Unrecognized thread priority %d; Doing nothing", - aThreadPriority); - return; - } -} - -void -FactoryReset(FactoryResetReason& aReason) -{ - nsCOMPtr recoveryService = - do_GetService("@mozilla.org/recovery-service;1"); - if (!recoveryService) { - NS_WARNING("Could not get recovery service!"); - return; - } - - if (aReason == FactoryResetReason::Wipe) { - recoveryService->FactoryReset("wipe"); - } else if (aReason == FactoryResetReason::Root) { - recoveryService->FactoryReset("root"); - } else { - recoveryService->FactoryReset("normal"); - } -} - -} // hal_impl -} // mozilla diff --git a/hal/gonk/GonkSensor.cpp b/hal/gonk/GonkSensor.cpp deleted file mode 100644 index 7bd2d3c9b..000000000 --- a/hal/gonk/GonkSensor.cpp +++ /dev/null @@ -1,861 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include -#include - -#include "mozilla/DebugOnly.h" -#include "mozilla/Saturate.h" - -#include "base/basictypes.h" -#include "base/thread.h" -#include "base/task.h" - -#include "GonkSensorsInterface.h" -#include "GonkSensorsPollInterface.h" -#include "GonkSensorsRegistryInterface.h" -#include "Hal.h" -#include "HalLog.h" -#include "HalSensor.h" -#include "hardware/sensors.h" -#include "nsThreadUtils.h" - -using namespace mozilla::hal; - -namespace mozilla { - -// -// Internal implementation -// - -// The value from SensorDevice.h (Android) -#define DEFAULT_DEVICE_POLL_RATE 200000000 /*200ms*/ -// ProcessOrientation.cpp needs smaller poll rate to detect delay between -// different orientation angles -#define ACCELEROMETER_POLL_RATE 66667000 /*66.667ms*/ - -// This is present in Android from API level 18 onwards, which is 4.3. We might -// be building on something before 4.3, so use a local define for its value -#define MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR 15 - -double radToDeg(double a) { - return a * (180.0 / M_PI); -} - -static SensorType -HardwareSensorToHalSensor(int type) -{ - switch(type) { - case SENSOR_TYPE_ORIENTATION: - return SENSOR_ORIENTATION; - case SENSOR_TYPE_ACCELEROMETER: - return SENSOR_ACCELERATION; - case SENSOR_TYPE_PROXIMITY: - return SENSOR_PROXIMITY; - case SENSOR_TYPE_LIGHT: - return SENSOR_LIGHT; - case SENSOR_TYPE_GYROSCOPE: - return SENSOR_GYROSCOPE; - case SENSOR_TYPE_LINEAR_ACCELERATION: - return SENSOR_LINEAR_ACCELERATION; - case SENSOR_TYPE_ROTATION_VECTOR: - return SENSOR_ROTATION_VECTOR; - case MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR: - return SENSOR_GAME_ROTATION_VECTOR; - default: - return SENSOR_UNKNOWN; - } -} - -static SensorAccuracyType -HardwareStatusToHalAccuracy(int status) { - return static_cast(status); -} - -static int -HalSensorToHardwareSensor(SensorType type) -{ - switch(type) { - case SENSOR_ORIENTATION: - return SENSOR_TYPE_ORIENTATION; - case SENSOR_ACCELERATION: - return SENSOR_TYPE_ACCELEROMETER; - case SENSOR_PROXIMITY: - return SENSOR_TYPE_PROXIMITY; - case SENSOR_LIGHT: - return SENSOR_TYPE_LIGHT; - case SENSOR_GYROSCOPE: - return SENSOR_TYPE_GYROSCOPE; - case SENSOR_LINEAR_ACCELERATION: - return SENSOR_TYPE_LINEAR_ACCELERATION; - case SENSOR_ROTATION_VECTOR: - return SENSOR_TYPE_ROTATION_VECTOR; - case SENSOR_GAME_ROTATION_VECTOR: - return MOZ_SENSOR_TYPE_GAME_ROTATION_VECTOR; - default: - return -1; - } -} - -static int -SensorseventStatus(const sensors_event_t& data) -{ - int type = data.type; - switch(type) { - case SENSOR_ORIENTATION: - return data.orientation.status; - case SENSOR_LINEAR_ACCELERATION: - case SENSOR_ACCELERATION: - return data.acceleration.status; - case SENSOR_GYROSCOPE: - return data.gyro.status; - } - - return SENSOR_STATUS_UNRELIABLE; -} - -class SensorRunnable : public Runnable -{ -public: - SensorRunnable(const sensors_event_t& data, const sensor_t* sensors, ssize_t size) - { - mSensorData.sensor() = HardwareSensorToHalSensor(data.type); - mSensorData.accuracy() = HardwareStatusToHalAccuracy(SensorseventStatus(data)); - mSensorData.timestamp() = data.timestamp; - if (mSensorData.sensor() == SENSOR_GYROSCOPE) { - // libhardware returns gyro as rad. convert. - mSensorValues.AppendElement(radToDeg(data.data[0])); - mSensorValues.AppendElement(radToDeg(data.data[1])); - mSensorValues.AppendElement(radToDeg(data.data[2])); - } else if (mSensorData.sensor() == SENSOR_PROXIMITY) { - mSensorValues.AppendElement(data.data[0]); - mSensorValues.AppendElement(0); - - // Determine the maxRange for this sensor. - for (ssize_t i = 0; i < size; i++) { - if (sensors[i].type == SENSOR_TYPE_PROXIMITY) { - mSensorValues.AppendElement(sensors[i].maxRange); - } - } - } else if (mSensorData.sensor() == SENSOR_LIGHT) { - mSensorValues.AppendElement(data.data[0]); - } else if (mSensorData.sensor() == SENSOR_ROTATION_VECTOR) { - mSensorValues.AppendElement(data.data[0]); - mSensorValues.AppendElement(data.data[1]); - mSensorValues.AppendElement(data.data[2]); - if (data.data[3] == 0.0) { - // data.data[3] was optional in Android <= API level 18. It can be computed from 012, - // but it's better to take the actual value if one is provided. The computation is - // v = 1 - d[0]*d[0] - d[1]*d[1] - d[2]*d[2] - // d[3] = v > 0 ? sqrt(v) : 0; - // I'm assuming that it will be 0 if it's not passed in. (The values form a unit - // quaternion, so the angle can be computed from the direction vector.) - float sx = data.data[0], sy = data.data[1], sz = data.data[2]; - float v = 1.0f - sx*sx - sy*sy - sz*sz; - mSensorValues.AppendElement(v > 0.0f ? sqrt(v) : 0.0f); - } else { - mSensorValues.AppendElement(data.data[3]); - } - } else if (mSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) { - mSensorValues.AppendElement(data.data[0]); - mSensorValues.AppendElement(data.data[1]); - mSensorValues.AppendElement(data.data[2]); - mSensorValues.AppendElement(data.data[3]); - } else { - mSensorValues.AppendElement(data.data[0]); - mSensorValues.AppendElement(data.data[1]); - mSensorValues.AppendElement(data.data[2]); - } - mSensorData.values() = mSensorValues; - } - - ~SensorRunnable() {} - - NS_IMETHOD Run() override - { - NotifySensorChange(mSensorData); - return NS_OK; - } - -private: - SensorData mSensorData; - AutoTArray mSensorValues; -}; - -namespace hal_impl { - -static DebugOnly sSensorRefCount[NUM_SENSOR_TYPE]; -static base::Thread* sPollingThread; -static sensors_poll_device_t* sSensorDevice; -static sensors_module_t* sSensorModule; - -static void -PollSensors() -{ - const size_t numEventMax = 16; - sensors_event_t buffer[numEventMax]; - const sensor_t* sensors; - int size = sSensorModule->get_sensors_list(sSensorModule, &sensors); - - do { - // didn't check sSensorDevice because already be done on creating pollingThread. - int n = sSensorDevice->poll(sSensorDevice, buffer, numEventMax); - if (n < 0) { - HAL_ERR("Error polling for sensor data (err=%d)", n); - break; - } - - for (int i = 0; i < n; ++i) { - // FIXME: bug 802004, add proper support for the magnetic field sensor. - if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD) - continue; - - // Bug 938035, transfer HAL data for orientation sensor to meet w3c spec - // ex: HAL report alpha=90 means East but alpha=90 means West in w3c spec - if (buffer[i].type == SENSOR_TYPE_ORIENTATION) { - buffer[i].orientation.azimuth = 360 - buffer[i].orientation.azimuth; - buffer[i].orientation.pitch = -buffer[i].orientation.pitch; - buffer[i].orientation.roll = -buffer[i].orientation.roll; - } - - if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) { - // Emulator is broken and gives us events without types set - int index; - for (index = 0; index < size; index++) { - if (sensors[index].handle == buffer[i].sensor) { - break; - } - } - if (index < size && - HardwareSensorToHalSensor(sensors[index].type) != SENSOR_UNKNOWN) { - buffer[i].type = sensors[index].type; - } else { - HAL_LOG("Could not determine sensor type of event"); - continue; - } - } - - NS_DispatchToMainThread(new SensorRunnable(buffer[i], sensors, size)); - } - } while (true); -} - -static void -SwitchSensor(bool aActivate, sensor_t aSensor, pthread_t aThreadId) -{ - int index = HardwareSensorToHalSensor(aSensor.type); - - MOZ_ASSERT(sSensorRefCount[index] || aActivate); - - sSensorDevice->activate(sSensorDevice, aSensor.handle, aActivate); - - if (aActivate) { - if (aSensor.type == SENSOR_TYPE_ACCELEROMETER) { - sSensorDevice->setDelay(sSensorDevice, aSensor.handle, - ACCELEROMETER_POLL_RATE); - } else { - sSensorDevice->setDelay(sSensorDevice, aSensor.handle, - DEFAULT_DEVICE_POLL_RATE); - } - } - - if (aActivate) { - sSensorRefCount[index]++; - } else { - sSensorRefCount[index]--; - } -} - -static void -SetSensorState(SensorType aSensor, bool activate) -{ - int type = HalSensorToHardwareSensor(aSensor); - const sensor_t* sensors = nullptr; - - int size = sSensorModule->get_sensors_list(sSensorModule, &sensors); - for (ssize_t i = 0; i < size; i++) { - if (sensors[i].type == type) { - SwitchSensor(activate, sensors[i], pthread_self()); - break; - } - } -} - -static void -EnableSensorNotificationsInternal(SensorType aSensor) -{ - if (!sSensorModule) { - hw_get_module(SENSORS_HARDWARE_MODULE_ID, - (hw_module_t const**)&sSensorModule); - if (!sSensorModule) { - HAL_ERR("Can't get sensor HAL module\n"); - return; - } - - sensors_open(&sSensorModule->common, &sSensorDevice); - if (!sSensorDevice) { - sSensorModule = nullptr; - HAL_ERR("Can't get sensor poll device from module \n"); - return; - } - - sensor_t const* sensors; - int count = sSensorModule->get_sensors_list(sSensorModule, &sensors); - for (size_t i=0 ; iactivate(sSensorDevice, sensors[i].handle, 0); - } - } - - if (!sPollingThread) { - sPollingThread = new base::Thread("GonkSensors"); - MOZ_ASSERT(sPollingThread); - // sPollingThread never terminates because poll may never return - sPollingThread->Start(); - sPollingThread->message_loop()->PostTask( - NewRunnableFunction(PollSensors)); - } - - SetSensorState(aSensor, true); -} - -static void -DisableSensorNotificationsInternal(SensorType aSensor) -{ - if (!sSensorModule) { - return; - } - SetSensorState(aSensor, false); -} - -// -// Daemon -// - -typedef detail::SaturateOp SaturateOpUint32; - -/** - * The poll notification handler receives all events about sensors and - * sensor events. - */ -class SensorsPollNotificationHandler final - : public GonkSensorsPollNotificationHandler -{ -public: - SensorsPollNotificationHandler(GonkSensorsPollInterface* aPollInterface) - : mPollInterface(aPollInterface) - { - MOZ_ASSERT(mPollInterface); - - mPollInterface->SetNotificationHandler(this); - } - - void EnableSensorsByType(SensorsType aType) - { - if (SaturateOpUint32(mClasses[aType].mActivated)++) { - return; - } - - SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType); - - // Old ref-count for the sensor type was 0, so we - // activate all sensors of the type. - for (size_t i = 0; i < mSensors.Length(); ++i) { - if (mSensors[i].mType == aType && - mSensors[i].mDeliveryMode == deliveryMode) { - mPollInterface->EnableSensor(mSensors[i].mId, nullptr); - mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType), - nullptr); - } - } - } - - void DisableSensorsByType(SensorsType aType) - { - if (SaturateOpUint32(mClasses[aType].mActivated)-- != 1) { - return; - } - - SensorsDeliveryMode deliveryMode = DefaultSensorsDeliveryMode(aType); - - // Old ref-count for the sensor type was 1, so we - // deactivate all sensors of the type. - for (size_t i = 0; i < mSensors.Length(); ++i) { - if (mSensors[i].mType == aType && - mSensors[i].mDeliveryMode == deliveryMode) { - mPollInterface->DisableSensor(mSensors[i].mId, nullptr); - } - } - } - - void ClearSensorClasses() - { - for (size_t i = 0; i < MOZ_ARRAY_LENGTH(mClasses); ++i) { - mClasses[i] = SensorsSensorClass(); - } - } - - void ClearSensors() - { - mSensors.Clear(); - } - - // Methods for SensorsPollNotificationHandler - // - - void ErrorNotification(SensorsError aError) override - { - // XXX: Bug 1206056: Try to repair some of the errors or restart cleanly. - } - - void SensorDetectedNotification(int32_t aId, SensorsType aType, - float aRange, float aResolution, - float aPower, int32_t aMinPeriod, - int32_t aMaxPeriod, - SensorsTriggerMode aTriggerMode, - SensorsDeliveryMode aDeliveryMode) override - { - auto i = FindSensorIndexById(aId); - if (i == -1) { - // Add a new sensor... - i = mSensors.Length(); - mSensors.AppendElement(SensorsSensor(aId, aType, aRange, aResolution, - aPower, aMinPeriod, aMaxPeriod, - aTriggerMode, aDeliveryMode)); - } else { - // ...or update an existing one. - mSensors[i] = SensorsSensor(aId, aType, aRange, aResolution, aPower, - aMinPeriod, aMaxPeriod, aTriggerMode, - aDeliveryMode); - } - - mClasses[aType].UpdateFromSensor(mSensors[i]); - - if (mClasses[aType].mActivated && - mSensors[i].mDeliveryMode == DefaultSensorsDeliveryMode(aType)) { - // The new sensor's type is enabled, so enable sensor. - mPollInterface->EnableSensor(aId, nullptr); - mPollInterface->SetPeriod(mSensors[i].mId, DefaultSensorPeriod(aType), - nullptr); - } - } - - void SensorLostNotification(int32_t aId) override - { - auto i = FindSensorIndexById(aId); - if (i != -1) { - mSensors.RemoveElementAt(i); - } - } - - void EventNotification(int32_t aId, const SensorsEvent& aEvent) override - { - auto i = FindSensorIndexById(aId); - if (i == -1) { - HAL_ERR("Sensor %d not registered", aId); - return; - } - - SensorData sensorData; - auto rv = CreateSensorData(aEvent, mClasses[mSensors[i].mType], - sensorData); - if (NS_FAILED(rv)) { - return; - } - - NotifySensorChange(sensorData); - } - -private: - ssize_t FindSensorIndexById(int32_t aId) const - { - for (size_t i = 0; i < mSensors.Length(); ++i) { - if (mSensors[i].mId == aId) { - return i; - } - } - return -1; - } - - uint64_t DefaultSensorPeriod(SensorsType aType) const - { - return aType == SENSORS_TYPE_ACCELEROMETER ? ACCELEROMETER_POLL_RATE - : DEFAULT_DEVICE_POLL_RATE; - } - - SensorsDeliveryMode DefaultSensorsDeliveryMode(SensorsType aType) const - { - if (aType == SENSORS_TYPE_PROXIMITY || - aType == SENSORS_TYPE_SIGNIFICANT_MOTION) { - return SENSORS_DELIVERY_MODE_IMMEDIATE; - } - return SENSORS_DELIVERY_MODE_BEST_EFFORT; - } - - SensorType HardwareSensorToHalSensor(SensorsType aType) const - { - // FIXME: bug 802004, add proper support for the magnetic-field sensor. - switch (aType) { - case SENSORS_TYPE_ORIENTATION: - return SENSOR_ORIENTATION; - case SENSORS_TYPE_ACCELEROMETER: - return SENSOR_ACCELERATION; - case SENSORS_TYPE_PROXIMITY: - return SENSOR_PROXIMITY; - case SENSORS_TYPE_LIGHT: - return SENSOR_LIGHT; - case SENSORS_TYPE_GYROSCOPE: - return SENSOR_GYROSCOPE; - case SENSORS_TYPE_LINEAR_ACCELERATION: - return SENSOR_LINEAR_ACCELERATION; - case SENSORS_TYPE_ROTATION_VECTOR: - return SENSOR_ROTATION_VECTOR; - case SENSORS_TYPE_GAME_ROTATION_VECTOR: - return SENSOR_GAME_ROTATION_VECTOR; - default: - NS_NOTREACHED("Invalid sensors type"); - } - return SENSOR_UNKNOWN; - } - - SensorAccuracyType HardwareStatusToHalAccuracy(SensorsStatus aStatus) const - { - return static_cast(aStatus - 1); - } - - nsresult CreateSensorData(const SensorsEvent& aEvent, - const SensorsSensorClass& aSensorClass, - SensorData& aSensorData) const - { - AutoTArray sensorValues; - - auto sensor = HardwareSensorToHalSensor(aEvent.mType); - - if (sensor == SENSOR_UNKNOWN) { - return NS_ERROR_ILLEGAL_VALUE; - } - - aSensorData.sensor() = sensor; - aSensorData.accuracy() = HardwareStatusToHalAccuracy(aEvent.mStatus); - aSensorData.timestamp() = aEvent.mTimestamp; - - if (aSensorData.sensor() == SENSOR_ORIENTATION) { - // Bug 938035: transfer HAL data for orientation sensor to meet W3C spec - // ex: HAL report alpha=90 means East but alpha=90 means West in W3C spec - sensorValues.AppendElement(360.0 - radToDeg(aEvent.mData.mFloat[0])); - sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[1])); - sensorValues.AppendElement(-radToDeg(aEvent.mData.mFloat[2])); - } else if (aSensorData.sensor() == SENSOR_ACCELERATION) { - sensorValues.AppendElement(aEvent.mData.mFloat[0]); - sensorValues.AppendElement(aEvent.mData.mFloat[1]); - sensorValues.AppendElement(aEvent.mData.mFloat[2]); - } else if (aSensorData.sensor() == SENSOR_PROXIMITY) { - sensorValues.AppendElement(aEvent.mData.mFloat[0]); - sensorValues.AppendElement(aSensorClass.mMinValue); - sensorValues.AppendElement(aSensorClass.mMaxValue); - } else if (aSensorData.sensor() == SENSOR_LINEAR_ACCELERATION) { - sensorValues.AppendElement(aEvent.mData.mFloat[0]); - sensorValues.AppendElement(aEvent.mData.mFloat[1]); - sensorValues.AppendElement(aEvent.mData.mFloat[2]); - } else if (aSensorData.sensor() == SENSOR_GYROSCOPE) { - sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[0])); - sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[1])); - sensorValues.AppendElement(radToDeg(aEvent.mData.mFloat[2])); - } else if (aSensorData.sensor() == SENSOR_LIGHT) { - sensorValues.AppendElement(aEvent.mData.mFloat[0]); - } else if (aSensorData.sensor() == SENSOR_ROTATION_VECTOR) { - sensorValues.AppendElement(aEvent.mData.mFloat[0]); - sensorValues.AppendElement(aEvent.mData.mFloat[1]); - sensorValues.AppendElement(aEvent.mData.mFloat[2]); - sensorValues.AppendElement(aEvent.mData.mFloat[3]); - } else if (aSensorData.sensor() == SENSOR_GAME_ROTATION_VECTOR) { - sensorValues.AppendElement(aEvent.mData.mFloat[0]); - sensorValues.AppendElement(aEvent.mData.mFloat[1]); - sensorValues.AppendElement(aEvent.mData.mFloat[2]); - sensorValues.AppendElement(aEvent.mData.mFloat[3]); - } - - aSensorData.values() = sensorValues; - - return NS_OK; - } - - GonkSensorsPollInterface* mPollInterface; - nsTArray mSensors; - SensorsSensorClass mClasses[SENSORS_NUM_TYPES]; -}; - -static StaticAutoPtr sPollNotificationHandler; - -/** - * This is the notifiaction handler for the Sensors interface. If the backend - * crashes, we can restart it from here. - */ -class SensorsNotificationHandler final : public GonkSensorsNotificationHandler -{ -public: - SensorsNotificationHandler(GonkSensorsInterface* aInterface) - : mInterface(aInterface) - { - MOZ_ASSERT(mInterface); - - mInterface->SetNotificationHandler(this); - } - - void BackendErrorNotification(bool aCrashed) override - { - // XXX: Bug 1206056: restart sensorsd - } - -private: - GonkSensorsInterface* mInterface; -}; - -static StaticAutoPtr sNotificationHandler; - -/** - * |SensorsRegisterModuleResultHandler| implements the result-handler - * callback for registering the Poll service and activating the first - * sensors. If an error occures during the process, the result handler - * disconnects and closes the backend. - */ -class SensorsRegisterModuleResultHandler final - : public GonkSensorsRegistryResultHandler -{ -public: - SensorsRegisterModuleResultHandler( - uint32_t* aSensorsTypeActivated, - GonkSensorsInterface* aInterface) - : mSensorsTypeActivated(aSensorsTypeActivated) - , mInterface(aInterface) - { - MOZ_ASSERT(mSensorsTypeActivated); - MOZ_ASSERT(mInterface); - } - void OnError(SensorsError aError) override - { - GonkSensorsRegistryResultHandler::OnError(aError); // print error message - Disconnect(); // Registering failed, so close the connection completely - } - void RegisterModule(uint32_t aProtocolVersion) override - { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!sPollNotificationHandler); - - // Init, step 3: set notification handler for poll service and vice versa - auto pollInterface = mInterface->GetSensorsPollInterface(); - if (!pollInterface) { - Disconnect(); - return; - } - if (NS_FAILED(pollInterface->SetProtocolVersion(aProtocolVersion))) { - Disconnect(); - return; - } - - sPollNotificationHandler = - new SensorsPollNotificationHandler(pollInterface); - - // Init, step 4: activate sensors - for (int i = 0; i < SENSORS_NUM_TYPES; ++i) { - while (mSensorsTypeActivated[i]) { - sPollNotificationHandler->EnableSensorsByType( - static_cast(i)); - --mSensorsTypeActivated[i]; - } - } - } -public: - void Disconnect() - { - class DisconnectResultHandler final : public GonkSensorsResultHandler - { - public: - void OnError(SensorsError aError) - { - GonkSensorsResultHandler::OnError(aError); // print error message - sNotificationHandler = nullptr; - } - void Disconnect() override - { - sNotificationHandler = nullptr; - } - }; - mInterface->Disconnect(new DisconnectResultHandler()); - } -private: - uint32_t* mSensorsTypeActivated; - GonkSensorsInterface* mInterface; -}; - -/** - * |SensorsConnectResultHandler| implements the result-handler - * callback for starting the Sensors backend. - */ -class SensorsConnectResultHandler final : public GonkSensorsResultHandler -{ -public: - SensorsConnectResultHandler( - uint32_t* aSensorsTypeActivated, - GonkSensorsInterface* aInterface) - : mSensorsTypeActivated(aSensorsTypeActivated) - , mInterface(aInterface) - { - MOZ_ASSERT(mSensorsTypeActivated); - MOZ_ASSERT(mInterface); - } - void OnError(SensorsError aError) override - { - GonkSensorsResultHandler::OnError(aError); // print error message - sNotificationHandler = nullptr; - } - void Connect() override - { - MOZ_ASSERT(NS_IsMainThread()); - - // Init, step 2: register poll service - auto registryInterface = mInterface->GetSensorsRegistryInterface(); - if (!registryInterface) { - return; - } - registryInterface->RegisterModule( - GonkSensorsPollModule::SERVICE_ID, - new SensorsRegisterModuleResultHandler(mSensorsTypeActivated, - mInterface)); - } -private: - uint32_t* mSensorsTypeActivated; - GonkSensorsInterface* mInterface; -}; - -static uint32_t sSensorsTypeActivated[SENSORS_NUM_TYPES]; - -static const SensorsType sSensorsType[] = { - [SENSOR_ORIENTATION] = SENSORS_TYPE_ORIENTATION, - [SENSOR_ACCELERATION] = SENSORS_TYPE_ACCELEROMETER, - [SENSOR_PROXIMITY] = SENSORS_TYPE_PROXIMITY, - [SENSOR_LINEAR_ACCELERATION] = SENSORS_TYPE_LINEAR_ACCELERATION, - [SENSOR_GYROSCOPE] = SENSORS_TYPE_GYROSCOPE, - [SENSOR_LIGHT] = SENSORS_TYPE_LIGHT, - [SENSOR_ROTATION_VECTOR] = SENSORS_TYPE_ROTATION_VECTOR, - [SENSOR_GAME_ROTATION_VECTOR] = SENSORS_TYPE_GAME_ROTATION_VECTOR -}; - -void -EnableSensorNotificationsDaemon(SensorType aSensor) -{ - if ((aSensor < 0) || - (aSensor > static_cast(MOZ_ARRAY_LENGTH(sSensorsType)))) { - HAL_ERR("Sensor type %d not known", aSensor); - return; // Unsupported sensor type - } - - auto interface = GonkSensorsInterface::GetInstance(); - if (!interface) { - return; - } - - if (sPollNotificationHandler) { - // Everythings already up and running; enable sensor type. - sPollNotificationHandler->EnableSensorsByType(sSensorsType[aSensor]); - return; - } - - ++SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]); - - if (sNotificationHandler) { - // We are in the middle of a pending start up; nothing else to do. - return; - } - - // Start up - - MOZ_ASSERT(!sPollNotificationHandler); - MOZ_ASSERT(!sNotificationHandler); - - sNotificationHandler = new SensorsNotificationHandler(interface); - - // Init, step 1: connect to Sensors backend - interface->Connect( - sNotificationHandler, - new SensorsConnectResultHandler(sSensorsTypeActivated, interface)); -} - -void -DisableSensorNotificationsDaemon(SensorType aSensor) -{ - if ((aSensor < 0) || - (aSensor > static_cast(MOZ_ARRAY_LENGTH(sSensorsType)))) { - HAL_ERR("Sensor type %d not known", aSensor); - return; // Unsupported sensor type - } - - if (sPollNotificationHandler) { - // Everthings up and running; disable sensors type - sPollNotificationHandler->DisableSensorsByType(sSensorsType[aSensor]); - return; - } - - // We might be in the middle of a startup; decrement type's ref-counter. - --SaturateOpUint32(sSensorsTypeActivated[sSensorsType[aSensor]]); - - // TODO: stop sensorsd if all sensors are disabled -} - -// -// Public interface -// - -// TODO: Remove in-Gecko sensors code. Until all devices' base -// images come with sensorsd installed, we have to support the -// in-Gecko implementation as well. So we test for the existance -// of the binary. If it's there, we use it. Otherwise we run the -// old code. -static bool -HasDaemon() -{ - static bool tested; - static bool hasDaemon; - - if (MOZ_UNLIKELY(!tested)) { - hasDaemon = !access("/system/bin/sensorsd", X_OK); - tested = true; - } - - return hasDaemon; -} - -void -EnableSensorNotifications(SensorType aSensor) -{ - if (HasDaemon()) { - EnableSensorNotificationsDaemon(aSensor); - } else { - EnableSensorNotificationsInternal(aSensor); - } -} - -void -DisableSensorNotifications(SensorType aSensor) -{ - if (HasDaemon()) { - DisableSensorNotificationsDaemon(aSensor); - } else { - DisableSensorNotificationsInternal(aSensor); - } -} - -} // hal_impl -} // mozilla diff --git a/hal/gonk/GonkSensorsHelpers.cpp b/hal/gonk/GonkSensorsHelpers.cpp deleted file mode 100644 index ccc940c7c..000000000 --- a/hal/gonk/GonkSensorsHelpers.cpp +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GonkSensorsHelpers.h" - -namespace mozilla { -namespace hal { - -// -// Unpacking -// - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsEvent& aOut) -{ - nsresult rv = UnpackPDU(aPDU, aOut.mType); - if (NS_FAILED(rv)) { - return rv; - } - rv = UnpackPDU(aPDU, aOut.mTimestamp); - if (NS_FAILED(rv)) { - return rv; - } - rv = UnpackPDU(aPDU, aOut.mStatus); - if (NS_FAILED(rv)) { - return rv; - } - - size_t i = 0; - - switch (aOut.mType) { - case SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED: - case SENSORS_TYPE_GYROSCOPE_UNCALIBRATED: - /* 6 data values */ - rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); - if (NS_FAILED(rv)) { - return rv; - } - /* fall through */ - case SENSORS_TYPE_ROTATION_VECTOR: - case SENSORS_TYPE_GAME_ROTATION_VECTOR: - case SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR: - /* 5 data values */ - rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); - if (NS_FAILED(rv)) { - return rv; - } - rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); - if (NS_FAILED(rv)) { - return rv; - } - /* fall through */ - case SENSORS_TYPE_ACCELEROMETER: - case SENSORS_TYPE_GEOMAGNETIC_FIELD: - case SENSORS_TYPE_ORIENTATION: - case SENSORS_TYPE_GYROSCOPE: - case SENSORS_TYPE_GRAVITY: - case SENSORS_TYPE_LINEAR_ACCELERATION: - /* 3 data values */ - rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); - if (NS_FAILED(rv)) { - return rv; - } - rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); - if (NS_FAILED(rv)) { - return rv; - } - /* fall through */ - case SENSORS_TYPE_LIGHT: - case SENSORS_TYPE_PRESSURE: - case SENSORS_TYPE_TEMPERATURE: - case SENSORS_TYPE_PROXIMITY: - case SENSORS_TYPE_RELATIVE_HUMIDITY: - case SENSORS_TYPE_AMBIENT_TEMPERATURE: - case SENSORS_TYPE_HEART_RATE: - case SENSORS_TYPE_TILT_DETECTOR: - case SENSORS_TYPE_WAKE_GESTURE: - case SENSORS_TYPE_GLANCE_GESTURE: - case SENSORS_TYPE_PICK_UP_GESTURE: - case SENSORS_TYPE_WRIST_TILT_GESTURE: - case SENSORS_TYPE_SIGNIFICANT_MOTION: - case SENSORS_TYPE_STEP_DETECTED: - /* 1 data value */ - rv = UnpackPDU(aPDU, aOut.mData.mFloat[i++]); - if (NS_FAILED(rv)) { - return rv; - } - break; - case SENSORS_TYPE_STEP_COUNTER: - /* 1 data value */ - rv = UnpackPDU(aPDU, aOut.mData.mUint[0]); - if (NS_FAILED(rv)) { - return rv; - } - break; - default: - if (MOZ_HAL_IPC_UNPACK_WARN_IF(true, SensorsEvent)) { - return NS_ERROR_ILLEGAL_VALUE; - } - } - rv = UnpackPDU(aPDU, aOut.mDeliveryMode); - if (NS_FAILED(rv)) { - return rv; - } - return NS_OK; -} - -} // namespace hal -} // namespace mozilla diff --git a/hal/gonk/GonkSensorsHelpers.h b/hal/gonk/GonkSensorsHelpers.h deleted file mode 100644 index 5218af53a..000000000 --- a/hal/gonk/GonkSensorsHelpers.h +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef hal_gonk_GonkSensorsHelpers_h -#define hal_gonk_GonkSensorsHelpers_h - -#include -#include -#include "SensorsTypes.h" - -namespace mozilla { -namespace hal { - -using mozilla::ipc::DaemonSocketPDU; -using mozilla::ipc::DaemonSocketPDUHeader; -using mozilla::ipc::DaemonSocketPDUHelpers::Convert; -using mozilla::ipc::DaemonSocketPDUHelpers::PackPDU; -using mozilla::ipc::DaemonSocketPDUHelpers::UnpackPDU; - -using namespace mozilla::ipc::DaemonSocketPDUHelpers; - -// -// Conversion -// -// The functions below convert the input value to the output value's -// type and perform extension tests on the validity of the result. On -// success the output value will be returned in |aOut|. The functions -// return NS_OK on success, or an XPCOM error code otherwise. -// -// See the documentation of the HAL IPC framework for more information -// on conversion functions. -// - -nsresult -Convert(int32_t aIn, SensorsStatus& aOut) -{ - static const uint8_t sStatus[] = { - [0] = SENSORS_STATUS_NO_CONTACT, // '-1' - [1] = SENSORS_STATUS_UNRELIABLE, // '0' - [2] = SENSORS_STATUS_ACCURACY_LOW, // '1' - [3] = SENSORS_STATUS_ACCURACY_MEDIUM, // '2' - [4] = SENSORS_STATUS_ACCURACY_HIGH // '3' - }; - static const int8_t sOffset = -1; // '-1' is the lower bound of the status - - if (MOZ_HAL_IPC_CONVERT_WARN_IF(aIn < sOffset, int32_t, SensorsStatus) || - MOZ_HAL_IPC_CONVERT_WARN_IF( - aIn >= (static_cast(MOZ_ARRAY_LENGTH(sStatus)) + sOffset), - int32_t, SensorsStatus)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = static_cast(sStatus[aIn - sOffset]); - return NS_OK; -} - -nsresult -Convert(uint8_t aIn, SensorsDeliveryMode& aOut) -{ - static const uint8_t sMode[] = { - [0x00] = SENSORS_DELIVERY_MODE_BEST_EFFORT, - [0x01] = SENSORS_DELIVERY_MODE_IMMEDIATE - }; - if (MOZ_HAL_IPC_CONVERT_WARN_IF( - aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, SensorsDeliveryMode)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = static_cast(sMode[aIn]); - return NS_OK; -} - -nsresult -Convert(uint8_t aIn, SensorsError& aOut) -{ - static const uint8_t sError[] = { - [0x00] = SENSORS_ERROR_NONE, - [0x01] = SENSORS_ERROR_FAIL, - [0x02] = SENSORS_ERROR_NOT_READY, - [0x03] = SENSORS_ERROR_NOMEM, - [0x04] = SENSORS_ERROR_BUSY, - [0x05] = SENSORS_ERROR_DONE, - [0x06] = SENSORS_ERROR_UNSUPPORTED, - [0x07] = SENSORS_ERROR_PARM_INVALID - }; - if (MOZ_HAL_IPC_CONVERT_WARN_IF( - aIn >= MOZ_ARRAY_LENGTH(sError), uint8_t, SensorsError)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = static_cast(sError[aIn]); - return NS_OK; -} - -nsresult -Convert(uint8_t aIn, SensorsTriggerMode& aOut) -{ - static const uint8_t sMode[] = { - [0x00] = SENSORS_TRIGGER_MODE_CONTINUOUS, - [0x01] = SENSORS_TRIGGER_MODE_ON_CHANGE, - [0x02] = SENSORS_TRIGGER_MODE_ONE_SHOT, - [0x03] = SENSORS_TRIGGER_MODE_SPECIAL - }; - if (MOZ_HAL_IPC_CONVERT_WARN_IF( - aIn >= MOZ_ARRAY_LENGTH(sMode), uint8_t, SensorsTriggerMode)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = static_cast(sMode[aIn]); - return NS_OK; -} - -nsresult -Convert(uint32_t aIn, SensorsType& aOut) -{ - static const uint8_t sType[] = { - [0x00] = 0, // invalid, required by gcc - [0x01] = SENSORS_TYPE_ACCELEROMETER, - [0x02] = SENSORS_TYPE_GEOMAGNETIC_FIELD, - [0x03] = SENSORS_TYPE_ORIENTATION, - [0x04] = SENSORS_TYPE_GYROSCOPE, - [0x05] = SENSORS_TYPE_LIGHT, - [0x06] = SENSORS_TYPE_PRESSURE, - [0x07] = SENSORS_TYPE_TEMPERATURE, - [0x08] = SENSORS_TYPE_PROXIMITY, - [0x09] = SENSORS_TYPE_GRAVITY, - [0x0a] = SENSORS_TYPE_LINEAR_ACCELERATION, - [0x0b] = SENSORS_TYPE_ROTATION_VECTOR, - [0x0c] = SENSORS_TYPE_RELATIVE_HUMIDITY, - [0x0d] = SENSORS_TYPE_AMBIENT_TEMPERATURE, - [0x0e] = SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED, - [0x0f] = SENSORS_TYPE_GAME_ROTATION_VECTOR, - [0x10] = SENSORS_TYPE_GYROSCOPE_UNCALIBRATED, - [0x11] = SENSORS_TYPE_SIGNIFICANT_MOTION, - [0x12] = SENSORS_TYPE_STEP_DETECTED, - [0x13] = SENSORS_TYPE_STEP_COUNTER, - [0x14] = SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR, - [0x15] = SENSORS_TYPE_HEART_RATE, - [0x16] = SENSORS_TYPE_TILT_DETECTOR, - [0x17] = SENSORS_TYPE_WAKE_GESTURE, - [0x18] = SENSORS_TYPE_GLANCE_GESTURE, - [0x19] = SENSORS_TYPE_PICK_UP_GESTURE, - [0x1a] = SENSORS_TYPE_WRIST_TILT_GESTURE - }; - if (MOZ_HAL_IPC_CONVERT_WARN_IF( - !aIn, uint32_t, SensorsType) || - MOZ_HAL_IPC_CONVERT_WARN_IF( - aIn >= MOZ_ARRAY_LENGTH(sType), uint32_t, SensorsType)) { - return NS_ERROR_ILLEGAL_VALUE; - } - aOut = static_cast(sType[aIn]); - return NS_OK; -} - -nsresult -Convert(nsresult aIn, SensorsError& aOut) -{ - if (NS_SUCCEEDED(aIn)) { - aOut = SENSORS_ERROR_NONE; - } else if (aIn == NS_ERROR_OUT_OF_MEMORY) { - aOut = SENSORS_ERROR_NOMEM; - } else if (aIn == NS_ERROR_ILLEGAL_VALUE) { - aOut = SENSORS_ERROR_PARM_INVALID; - } else { - aOut = SENSORS_ERROR_FAIL; - } - return NS_OK; -} - -// -// Packing -// -// Pack functions store a value in PDU. See the documentation of the -// HAL IPC framework for more information. -// -// There are currently no sensor-specific pack functions necessary. If -// you add one, put it below. -// - -// -// Unpacking -// -// Unpack function retrieve a value from a PDU. The functions return -// NS_OK on success, or an XPCOM error code otherwise. On sucess, the -// returned value is stored in the second argument |aOut|. -// -// See the documentation of the HAL IPC framework for more information -// on unpack functions. -// - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsDeliveryMode& aOut) -{ - return UnpackPDU(aPDU, UnpackConversion(aOut)); -} - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsError& aOut) -{ - return UnpackPDU(aPDU, UnpackConversion(aOut)); -} - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsEvent& aOut); - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsStatus& aOut) -{ - return UnpackPDU(aPDU, UnpackConversion(aOut)); -} - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsTriggerMode& aOut) -{ - return UnpackPDU(aPDU, UnpackConversion(aOut)); -} - -nsresult -UnpackPDU(DaemonSocketPDU& aPDU, SensorsType& aOut) -{ - return UnpackPDU(aPDU, UnpackConversion(aOut)); -} - -} // namespace hal -} // namespace mozilla - -#endif // hal_gonk_GonkSensorsHelpers_h diff --git a/hal/gonk/GonkSensorsInterface.cpp b/hal/gonk/GonkSensorsInterface.cpp deleted file mode 100644 index 51e1ff50c..000000000 --- a/hal/gonk/GonkSensorsInterface.cpp +++ /dev/null @@ -1,494 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GonkSensorsInterface.h" -#include "GonkSensorsPollInterface.h" -#include "GonkSensorsRegistryInterface.h" -#include "HalLog.h" -#include -#include -#include - -namespace mozilla { -namespace hal { - -using namespace mozilla::ipc; - -// -// GonkSensorsResultHandler -// - -void -GonkSensorsResultHandler::OnError(SensorsError aError) -{ - HAL_ERR("Received error code %d", static_cast(aError)); -} - -void -GonkSensorsResultHandler::Connect() -{ } - -void -GonkSensorsResultHandler::Disconnect() -{ } - -GonkSensorsResultHandler::~GonkSensorsResultHandler() -{ } - -// -// GonkSensorsNotificationHandler -// - -void -GonkSensorsNotificationHandler::BackendErrorNotification(bool aCrashed) -{ - if (aCrashed) { - HAL_ERR("Sensors backend crashed"); - } else { - HAL_ERR("Error in sensors backend"); - } -} - -GonkSensorsNotificationHandler::~GonkSensorsNotificationHandler() -{ } - -// -// GonkSensorsProtocol -// - -class GonkSensorsProtocol final - : public DaemonSocketIOConsumer - , public GonkSensorsRegistryModule - , public GonkSensorsPollModule -{ -public: - GonkSensorsProtocol(); - - void SetConnection(DaemonSocket* aConnection); - - already_AddRefed FetchResultHandler( - const DaemonSocketPDUHeader& aHeader); - - // Methods for |SensorsRegistryModule| and |SensorsPollModule| - // - - nsresult Send(DaemonSocketPDU* aPDU, - DaemonSocketResultHandler* aRes) override; - - // Methods for |DaemonSocketIOConsumer| - // - - void Handle(DaemonSocketPDU& aPDU) override; - void StoreResultHandler(const DaemonSocketPDU& aPDU) override; - -private: - void HandleRegistrySvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - void HandlePollSvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - - DaemonSocket* mConnection; - nsTArray> mResultHandlerQ; -}; - -GonkSensorsProtocol::GonkSensorsProtocol() -{ } - -void -GonkSensorsProtocol::SetConnection(DaemonSocket* aConnection) -{ - mConnection = aConnection; -} - -already_AddRefed -GonkSensorsProtocol::FetchResultHandler(const DaemonSocketPDUHeader& aHeader) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - if (aHeader.mOpcode & 0x80) { - return nullptr; // Ignore notifications - } - - RefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - - return res.forget(); -} - -void -GonkSensorsProtocol::HandleRegistrySvc( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - GonkSensorsRegistryModule::HandleSvc(aHeader, aPDU, aRes); -} - -void -GonkSensorsProtocol::HandlePollSvc( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - GonkSensorsPollModule::HandleSvc(aHeader, aPDU, aRes); -} - -// |SensorsRegistryModule|, |SensorsPollModule| - -nsresult -GonkSensorsProtocol::Send(DaemonSocketPDU* aPDU, - DaemonSocketResultHandler* aRes) -{ - MOZ_ASSERT(mConnection); - MOZ_ASSERT(aPDU); - - aPDU->SetConsumer(this); - aPDU->SetResultHandler(aRes); - aPDU->UpdateHeader(); - - if (mConnection->GetConnectionStatus() == SOCKET_DISCONNECTED) { - HAL_ERR("Sensors socket is disconnected"); - return NS_ERROR_FAILURE; - } - - mConnection->SendSocketData(aPDU); // Forward PDU to data channel - - return NS_OK; -} - -// |DaemonSocketIOConsumer| - -void -GonkSensorsProtocol::Handle(DaemonSocketPDU& aPDU) -{ - static void (GonkSensorsProtocol::* const HandleSvc[])( - const DaemonSocketPDUHeader&, DaemonSocketPDU&, - DaemonSocketResultHandler*) = { - [GonkSensorsRegistryModule::SERVICE_ID] = - &GonkSensorsProtocol::HandleRegistrySvc, - [GonkSensorsPollModule::SERVICE_ID] = - &GonkSensorsProtocol::HandlePollSvc - }; - - DaemonSocketPDUHeader header; - - if (NS_FAILED(UnpackPDU(aPDU, header))) { - return; - } - if (!(header.mService < MOZ_ARRAY_LENGTH(HandleSvc)) || - !HandleSvc[header.mService]) { - HAL_ERR("Sensors service %d unknown", header.mService); - return; - } - - RefPtr res = FetchResultHandler(header); - - (this->*(HandleSvc[header.mService]))(header, aPDU, res); -} - -void -GonkSensorsProtocol::StoreResultHandler(const DaemonSocketPDU& aPDU) -{ - MOZ_ASSERT(!NS_IsMainThread()); - - mResultHandlerQ.AppendElement(aPDU.GetResultHandler()); -} - -// -// GonkSensorsInterface -// - -GonkSensorsInterface* -GonkSensorsInterface::GetInstance() -{ - static GonkSensorsInterface* sGonkSensorsInterface; - - if (sGonkSensorsInterface) { - return sGonkSensorsInterface; - } - - sGonkSensorsInterface = new GonkSensorsInterface(); - - return sGonkSensorsInterface; -} - -void -GonkSensorsInterface::SetNotificationHandler( - GonkSensorsNotificationHandler* aNotificationHandler) -{ - MOZ_ASSERT(NS_IsMainThread()); - - mNotificationHandler = aNotificationHandler; -} - -/* - * The connect procedure consists of several steps. - * - * (1) Start listening for the command channel's socket connection: We - * do this before anything else, so that we don't miss connection - * requests from the Sensors daemon. This step will create a listen - * socket. - * - * (2) Start the Sensors daemon: When the daemon starts up it will open - * a socket connection to Gecko and thus create the data channel. - * Gecko already opened the listen socket in step (1). Step (2) ends - * with the creation of the data channel. - * - * (3) Signal success to the caller. - * - * If any step fails, we roll-back the procedure and signal an error to the - * caller. - */ -void -GonkSensorsInterface::Connect(GonkSensorsNotificationHandler* aNotificationHandler, - GonkSensorsResultHandler* aRes) -{ -#define BASE_SOCKET_NAME "sensorsd" - static unsigned long POSTFIX_LENGTH = 16; - - // If we could not cleanup properly before and an old - // instance of the daemon is still running, we kill it - // here. - mozilla::hal::StopSystemService("sensorsd"); - - mNotificationHandler = aNotificationHandler; - - mResultHandlerQ.AppendElement(aRes); - - if (!mProtocol) { - mProtocol = MakeUnique(); - } - - if (!mListenSocket) { - mListenSocket = new ListenSocket(this, LISTEN_SOCKET); - } - - // Init, step 1: Listen for data channel... */ - - if (!mDataSocket) { - mDataSocket = new DaemonSocket(mProtocol.get(), this, DATA_SOCKET); - } else if (mDataSocket->GetConnectionStatus() == SOCKET_CONNECTED) { - // Command channel should not be open; let's close it. - mDataSocket->Close(); - } - - // The listen socket's name is generated with a random postfix. This - // avoids naming collisions if we still have a listen socket from a - // previously failed cleanup. It also makes it hard for malicious - // external programs to capture the socket name or connect before - // the daemon can do so. If no random postfix can be generated, we - // simply use the base name as-is. - nsresult rv = DaemonSocketConnector::CreateRandomAddressString( - NS_LITERAL_CSTRING(BASE_SOCKET_NAME), POSTFIX_LENGTH, mListenSocketName); - if (NS_FAILED(rv)) { - mListenSocketName.AssignLiteral(BASE_SOCKET_NAME); - } - - rv = mListenSocket->Listen(new DaemonSocketConnector(mListenSocketName), - mDataSocket); - if (NS_FAILED(rv)) { - OnConnectError(DATA_SOCKET); - return; - } - - // The protocol implementation needs a data channel for - // sending commands to the daemon. We set it here, because - // this is the earliest time when it's available. - mProtocol->SetConnection(mDataSocket); -} - -/* - * Disconnecting is inverse to connecting. - * - * (1) Close data socket: We close the data channel and the daemon will - * will notice. Once we see the socket's disconnect, we continue with - * the cleanup. - * - * (2) Close listen socket: The listen socket is not active any longer - * and we simply close it. - * - * (3) Signal success to the caller. - * - * We don't have to stop the daemon explicitly. It will cleanup and quit - * after it noticed the closing of the data channel - * - * Rolling back half-completed cleanups is not possible. In the case of - * an error, we simply push forward and try to recover during the next - * initialization. - */ -void -GonkSensorsInterface::Disconnect(GonkSensorsResultHandler* aRes) -{ - mNotificationHandler = nullptr; - - // Cleanup, step 1: Close data channel - mDataSocket->Close(); - - mResultHandlerQ.AppendElement(aRes); -} - -GonkSensorsRegistryInterface* -GonkSensorsInterface::GetSensorsRegistryInterface() -{ - if (mRegistryInterface) { - return mRegistryInterface.get(); - } - - mRegistryInterface = MakeUnique(mProtocol.get()); - - return mRegistryInterface.get(); -} - -GonkSensorsPollInterface* -GonkSensorsInterface::GetSensorsPollInterface() -{ - if (mPollInterface) { - return mPollInterface.get(); - } - - mPollInterface = MakeUnique(mProtocol.get()); - - return mPollInterface.get(); -} - -GonkSensorsInterface::GonkSensorsInterface() - : mNotificationHandler(nullptr) -{ } - -GonkSensorsInterface::~GonkSensorsInterface() -{ } - -void -GonkSensorsInterface::DispatchError(GonkSensorsResultHandler* aRes, - SensorsError aError) -{ - DaemonResultRunnable1::Dispatch( - aRes, &GonkSensorsResultHandler::OnError, - ConstantInitOp1(aError)); -} - -void -GonkSensorsInterface::DispatchError( - GonkSensorsResultHandler* aRes, nsresult aRv) -{ - SensorsError error; - - if (NS_FAILED(Convert(aRv, error))) { - error = SENSORS_ERROR_FAIL; - } - DispatchError(aRes, error); -} - -// |DaemonSocketConsumer|, |ListenSocketConsumer| - -void -GonkSensorsInterface::OnConnectSuccess(int aIndex) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); - - switch (aIndex) { - case LISTEN_SOCKET: { - // Init, step 2: Start Sensors daemon - nsCString args("-a "); - args.Append(mListenSocketName); - mozilla::hal::StartSystemService("sensorsd", args.get()); - } - break; - case DATA_SOCKET: - if (!mResultHandlerQ.IsEmpty()) { - // Init, step 3: Signal success - RefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - if (res) { - res->Connect(); - } - } - break; - } -} - -void -GonkSensorsInterface::OnConnectError(int aIndex) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!mResultHandlerQ.IsEmpty()); - - switch (aIndex) { - case DATA_SOCKET: - // Stop daemon and close listen socket - mozilla::hal::StopSystemService("sensorsd"); - mListenSocket->Close(); - // fall through - case LISTEN_SOCKET: - if (!mResultHandlerQ.IsEmpty()) { - // Signal error to caller - RefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - if (res) { - DispatchError(res, SENSORS_ERROR_FAIL); - } - } - break; - } -} - -/* - * Disconnects can happend - * - * (a) during startup, - * (b) during regular service, or - * (c) during shutdown. - * - * For cases (a) and (c), |mResultHandlerQ| contains an element. For - * case (b) |mResultHandlerQ| will be empty. This distinguishes a crash in - * the daemon. The following procedure to recover from crashes consists of - * several steps for case (b). - * - * (1) Close listen socket. - * (2) Wait for all sockets to be disconnected and inform caller about - * the crash. - * (3) After all resources have been cleaned up, let the caller restart - * the daemon. - */ -void -GonkSensorsInterface::OnDisconnect(int aIndex) -{ - MOZ_ASSERT(NS_IsMainThread()); - - switch (aIndex) { - case DATA_SOCKET: - // Cleanup, step 2 (Recovery, step 1): Close listen socket - mListenSocket->Close(); - break; - case LISTEN_SOCKET: - // Cleanup, step 3: Signal success to caller - if (!mResultHandlerQ.IsEmpty()) { - RefPtr res = mResultHandlerQ.ElementAt(0); - mResultHandlerQ.RemoveElementAt(0); - if (res) { - res->Disconnect(); - } - } - break; - } - - /* For recovery make sure all sockets disconnected, in order to avoid - * the remaining disconnects interfere with the restart procedure. - */ - if (mNotificationHandler && mResultHandlerQ.IsEmpty()) { - if (mListenSocket->GetConnectionStatus() == SOCKET_DISCONNECTED && - mDataSocket->GetConnectionStatus() == SOCKET_DISCONNECTED) { - // Recovery, step 2: Notify the caller to prepare the restart procedure. - mNotificationHandler->BackendErrorNotification(true); - mNotificationHandler = nullptr; - } - } -} - -} // namespace hal -} // namespace mozilla diff --git a/hal/gonk/GonkSensorsInterface.h b/hal/gonk/GonkSensorsInterface.h deleted file mode 100644 index 6e356dc36..000000000 --- a/hal/gonk/GonkSensorsInterface.h +++ /dev/null @@ -1,191 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=8 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * The sensors interface gives you access to the low-level sensors code - * in a platform-independent manner. The interfaces in this file allow - * for starting an stopping the sensors driver. Specific functionality - * is implemented in sub-interfaces. - */ - -#ifndef hal_gonk_GonkSensorsInterface_h -#define hal_gonk_GonkSensorsInterface_h - -#include -#include -#include -#include -#include "SensorsTypes.h" - -namespace mozilla { -namespace ipc { - -class DaemonSocket; -class ListenSocket; - -} -} - -namespace mozilla { -namespace hal { - -class GonkSensorsPollInterface; -class GonkSensorsProtocol; -class GonkSensorsRegistryInterface; - -/** - * This class is the result-handler interface for the Sensors - * interface. Methods always run on the main thread. - */ -class GonkSensorsResultHandler - : public mozilla::ipc::DaemonSocketResultHandler -{ -public: - - /** - * Called if a command failed. - * - * @param aError The error code. - */ - virtual void OnError(SensorsError aError); - - /** - * The callback method for |GonkSensorsInterface::Connect|. - */ - virtual void Connect(); - - /** - * The callback method for |GonkSensorsInterface::Connect|. - */ - virtual void Disconnect(); - -protected: - virtual ~GonkSensorsResultHandler(); -}; - -/** - * This is the notification-handler interface. Implement this classes - * methods to handle event and notifications from the sensors daemon. - * All methods run on the main thread. - */ -class GonkSensorsNotificationHandler -{ -public: - - /** - * This notification is called when the backend code fails - * unexpectedly. Save state in the high-level code and restart - * the driver. - * - * @param aCrash True is the sensors driver crashed. - */ - virtual void BackendErrorNotification(bool aCrashed); - -protected: - virtual ~GonkSensorsNotificationHandler(); -}; - -/** - * This class implements the public interface to the Sensors functionality - * and driver. Use |GonkSensorsInterface::GetInstance| to retrieve an instance. - * All methods run on the main thread. - */ -class GonkSensorsInterface final - : public mozilla::ipc::DaemonSocketConsumer - , public mozilla::ipc::ListenSocketConsumer -{ -public: - /** - * Returns an instance of the Sensors backend. This code can return - * |nullptr| if no Sensors backend is available. - * - * @return An instance of |GonkSensorsInterface|. - */ - static GonkSensorsInterface* GetInstance(); - - /** - * This method sets the notification handler for sensor notifications. Call - * this method immediately after retreiving an instance of the class, or you - * won't be able able to receive notifications. You may not free the handler - * class while the Sensors backend is connected. - * - * @param aNotificationHandler An instance of a notification handler. - */ - void SetNotificationHandler( - GonkSensorsNotificationHandler* aNotificationHandler); - - /** - * This method starts the Sensors backend and establishes ad connection - * with Gecko. This is a multi-step process and errors are signalled by - * |GonkSensorsNotificationHandler::BackendErrorNotification|. If you see - * this notification before the connection has been established, it's - * certainly best to assume the Sensors backend to be not evailable. - * - * @param aRes The result handler. - */ - void Connect(GonkSensorsNotificationHandler* aNotificationHandler, - GonkSensorsResultHandler* aRes); - - /** - * This method disconnects Gecko from the Sensors backend and frees - * the backend's resources. This will invalidate all interfaces and - * state. Don't use any sensors functionality without reconnecting - * first. - * - * @param aRes The result handler. - */ - void Disconnect(GonkSensorsResultHandler* aRes); - - /** - * Returns the Registry interface for the connected Sensors backend. - * - * @return An instance of the Sensors Registry interface. - */ - GonkSensorsRegistryInterface* GetSensorsRegistryInterface(); - - /** - * Returns the Poll interface for the connected Sensors backend. - * - * @return An instance of the Sensors Poll interface. - */ - GonkSensorsPollInterface* GetSensorsPollInterface(); - -private: - enum Channel { - LISTEN_SOCKET, - DATA_SOCKET - }; - - GonkSensorsInterface(); - ~GonkSensorsInterface(); - - void DispatchError(GonkSensorsResultHandler* aRes, SensorsError aError); - void DispatchError(GonkSensorsResultHandler* aRes, nsresult aRv); - - // Methods for |DaemonSocketConsumer| and |ListenSocketConsumer| - // - - void OnConnectSuccess(int aIndex) override; - void OnConnectError(int aIndex) override; - void OnDisconnect(int aIndex) override; - - nsCString mListenSocketName; - RefPtr mListenSocket; - RefPtr mDataSocket; - UniquePtr mProtocol; - - nsTArray > mResultHandlerQ; - - GonkSensorsNotificationHandler* mNotificationHandler; - - UniquePtr mRegistryInterface; - UniquePtr mPollInterface; -}; - -} // namespace hal -} // namespace mozilla - -#endif // hal_gonk_GonkSensorsInterface_h diff --git a/hal/gonk/GonkSensorsPollInterface.cpp b/hal/gonk/GonkSensorsPollInterface.cpp deleted file mode 100644 index d4edc2e7a..000000000 --- a/hal/gonk/GonkSensorsPollInterface.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GonkSensorsPollInterface.h" -#include "HalLog.h" -#include - -namespace mozilla { -namespace hal { - -using namespace mozilla::ipc; - -// -// GonkSensorsPollResultHandler -// - -void -GonkSensorsPollResultHandler::OnError(SensorsError aError) -{ - HAL_ERR("Received error code %d", static_cast(aError)); -} - -void -GonkSensorsPollResultHandler::EnableSensor() -{ } - -void -GonkSensorsPollResultHandler::DisableSensor() -{ } - -void -GonkSensorsPollResultHandler::SetPeriod() -{ } - -GonkSensorsPollResultHandler::~GonkSensorsPollResultHandler() -{ } - -// -// GonkSensorsPollNotificationHandler -// - -void -GonkSensorsPollNotificationHandler::ErrorNotification(SensorsError aError) -{ - HAL_ERR("Received error code %d", static_cast(aError)); -} - -void -GonkSensorsPollNotificationHandler::SensorDetectedNotification( - int32_t aId, - SensorsType aType, - float aRange, - float aResolution, - float aPower, - int32_t aMinPeriod, - int32_t aMaxPeriod, - SensorsTriggerMode aTriggerMode, - SensorsDeliveryMode aDeliveryMode) -{ } - -void -GonkSensorsPollNotificationHandler::SensorLostNotification(int32_t aId) -{ } - -void -GonkSensorsPollNotificationHandler::EventNotification(int32_t aId, - const SensorsEvent& aEvent) -{ } - -GonkSensorsPollNotificationHandler::~GonkSensorsPollNotificationHandler() -{ } - -// -// GonkSensorsPollModule -// - -GonkSensorsPollModule::GonkSensorsPollModule() - : mProtocolVersion(0) -{ } - -GonkSensorsPollModule::~GonkSensorsPollModule() -{ } - -nsresult -GonkSensorsPollModule::SetProtocolVersion(unsigned long aProtocolVersion) -{ - if ((aProtocolVersion < MIN_PROTOCOL_VERSION) || - (aProtocolVersion > MAX_PROTOCOL_VERSION)) { - HAL_ERR("Sensors Poll protocol version %lu not supported", - aProtocolVersion); - return NS_ERROR_ILLEGAL_VALUE; - } - mProtocolVersion = aProtocolVersion; - return NS_OK; -} - -void -GonkSensorsPollModule::HandleSvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - static void (GonkSensorsPollModule::* const HandleOp[])( - const DaemonSocketPDUHeader&, DaemonSocketPDU&, - DaemonSocketResultHandler*) = { - [0] = &GonkSensorsPollModule::HandleRsp, - [1] = &GonkSensorsPollModule::HandleNtf - }; - - MOZ_ASSERT(!NS_IsMainThread()); // I/O thread - - // Negate twice to map bit to 0/1 - unsigned long isNtf = !!(aHeader.mOpcode & 0x80); - - (this->*(HandleOp[isNtf]))(aHeader, aPDU, aRes); -} - -// Commands -// - -nsresult -GonkSensorsPollModule::EnableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes) -{ - MOZ_ASSERT(NS_IsMainThread()); - - UniquePtr pdu = - MakeUnique(SERVICE_ID, OPCODE_ENABLE_SENSOR, 0); - - nsresult rv = PackPDU(aId, *pdu); - if (NS_FAILED(rv)) { - return rv; - } - rv = Send(pdu.get(), aRes); - if (NS_FAILED(rv)) { - return rv; - } - Unused << pdu.release(); - return NS_OK; -} - -nsresult -GonkSensorsPollModule::DisableSensorCmd(int32_t aId, GonkSensorsPollResultHandler* aRes) -{ - MOZ_ASSERT(NS_IsMainThread()); - - UniquePtr pdu = - MakeUnique(SERVICE_ID, OPCODE_DISABLE_SENSOR, 0); - - nsresult rv = PackPDU(aId, *pdu); - if (NS_FAILED(rv)) { - return rv; - } - rv = Send(pdu.get(), aRes); - if (NS_FAILED(rv)) { - return rv; - } - Unused << pdu.release(); - return NS_OK; -} - -nsresult -GonkSensorsPollModule::SetPeriodCmd(int32_t aId, uint64_t aPeriod, - GonkSensorsPollResultHandler* aRes) -{ - MOZ_ASSERT(NS_IsMainThread()); - - UniquePtr pdu = - MakeUnique(SERVICE_ID, OPCODE_SET_PERIOD, 0); - - nsresult rv = PackPDU(aId, *pdu); - if (NS_FAILED(rv)) { - return rv; - } - rv = PackPDU(aPeriod, *pdu); - if (NS_FAILED(rv)) { - return rv; - } - rv = Send(pdu.get(), aRes); - if (NS_FAILED(rv)) { - return rv; - } - Unused << pdu.release(); - return NS_OK; -} - -// Responses -// - -void -GonkSensorsPollModule::ErrorRsp( - const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, GonkSensorsPollResultHandler* aRes) -{ - ErrorRunnable::Dispatch( - aRes, &GonkSensorsPollResultHandler::OnError, UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::EnableSensorRsp( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes) -{ - ResultRunnable::Dispatch( - aRes, &GonkSensorsPollResultHandler::EnableSensor, UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::DisableSensorRsp( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes) -{ - ResultRunnable::Dispatch( - aRes, &GonkSensorsPollResultHandler::DisableSensor, UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::SetPeriodRsp( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes) -{ - ResultRunnable::Dispatch( - aRes, &GonkSensorsPollResultHandler::SetPeriod, UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::HandleRsp( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - static void (GonkSensorsPollModule::* const sHandleRsp[])( - const DaemonSocketPDUHeader&, DaemonSocketPDU&, - GonkSensorsPollResultHandler*) = { - [OPCODE_ERROR] = &GonkSensorsPollModule::ErrorRsp, - [OPCODE_ENABLE_SENSOR] = &GonkSensorsPollModule::EnableSensorRsp, - [OPCODE_DISABLE_SENSOR] = &GonkSensorsPollModule::DisableSensorRsp, - [OPCODE_SET_PERIOD] = &GonkSensorsPollModule::SetPeriodRsp, - }; - - MOZ_ASSERT(!NS_IsMainThread()); // I/O thread - - if (!(aHeader.mOpcode < MOZ_ARRAY_LENGTH(sHandleRsp)) || - !sHandleRsp[aHeader.mOpcode]) { - HAL_ERR("Sensors poll response opcode %d unknown", aHeader.mOpcode); - return; - } - - RefPtr res = - static_cast(aRes); - - if (!res) { - return; // Return early if no result handler has been set for response - } - - (this->*(sHandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res); -} - -// Notifications -// - -// Returns the current notification handler to a notification runnable -class GonkSensorsPollModule::NotificationHandlerWrapper final -{ -public: - typedef GonkSensorsPollNotificationHandler ObjectType; - - static ObjectType* GetInstance() - { - MOZ_ASSERT(NS_IsMainThread()); - - return sNotificationHandler; - } - - static GonkSensorsPollNotificationHandler* sNotificationHandler; -}; - -GonkSensorsPollNotificationHandler* - GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler; - -void -GonkSensorsPollModule::ErrorNtf( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) -{ - ErrorNotification::Dispatch( - &GonkSensorsPollNotificationHandler::ErrorNotification, - UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::SensorDetectedNtf( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) -{ - SensorDetectedNotification::Dispatch( - &GonkSensorsPollNotificationHandler::SensorDetectedNotification, - UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::SensorLostNtf( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) -{ - SensorLostNotification::Dispatch( - &GonkSensorsPollNotificationHandler::SensorLostNotification, - UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::EventNtf( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU) -{ - EventNotification::Dispatch( - &GonkSensorsPollNotificationHandler::EventNotification, - UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsPollModule::HandleNtf( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - static void (GonkSensorsPollModule::* const sHandleNtf[])( - const DaemonSocketPDUHeader&, DaemonSocketPDU&) = { - [0] = &GonkSensorsPollModule::ErrorNtf, - [1] = &GonkSensorsPollModule::SensorDetectedNtf, - [2] = &GonkSensorsPollModule::SensorLostNtf, - [3] = &GonkSensorsPollModule::EventNtf - }; - - MOZ_ASSERT(!NS_IsMainThread()); - - uint8_t index = aHeader.mOpcode - 0x80; - - if (!(index < MOZ_ARRAY_LENGTH(sHandleNtf)) || !sHandleNtf[index]) { - HAL_ERR("Sensors poll notification opcode %d unknown", aHeader.mOpcode); - return; - } - - (this->*(sHandleNtf[index]))(aHeader, aPDU); -} - -// -// GonkSensorsPollInterface -// - -GonkSensorsPollInterface::GonkSensorsPollInterface( - GonkSensorsPollModule* aModule) - : mModule(aModule) -{ } - -GonkSensorsPollInterface::~GonkSensorsPollInterface() -{ } - -void -GonkSensorsPollInterface::SetNotificationHandler( - GonkSensorsPollNotificationHandler* aNotificationHandler) -{ - MOZ_ASSERT(NS_IsMainThread()); - - GonkSensorsPollModule::NotificationHandlerWrapper::sNotificationHandler = - aNotificationHandler; -} - -nsresult -GonkSensorsPollInterface::SetProtocolVersion(unsigned long aProtocolVersion) -{ - MOZ_ASSERT(mModule); - - return mModule->SetProtocolVersion(aProtocolVersion); -} - -void -GonkSensorsPollInterface::EnableSensor(int32_t aId, - GonkSensorsPollResultHandler* aRes) -{ - MOZ_ASSERT(mModule); - - nsresult rv = mModule->EnableSensorCmd(aId, aRes); - if (NS_FAILED(rv)) { - DispatchError(aRes, rv); - } -} - -void -GonkSensorsPollInterface::DisableSensor(int32_t aId, - GonkSensorsPollResultHandler* aRes) -{ - MOZ_ASSERT(mModule); - - nsresult rv = mModule->DisableSensorCmd(aId, aRes); - if (NS_FAILED(rv)) { - DispatchError(aRes, rv); - } -} - -void -GonkSensorsPollInterface::SetPeriod(int32_t aId, uint64_t aPeriod, - GonkSensorsPollResultHandler* aRes) -{ - MOZ_ASSERT(mModule); - - nsresult rv = mModule->SetPeriodCmd(aId, aPeriod, aRes); - if (NS_FAILED(rv)) { - DispatchError(aRes, rv); - } -} - -void -GonkSensorsPollInterface::DispatchError( - GonkSensorsPollResultHandler* aRes, SensorsError aError) -{ - DaemonResultRunnable1::Dispatch( - aRes, &GonkSensorsPollResultHandler::OnError, - ConstantInitOp1(aError)); -} - -void -GonkSensorsPollInterface::DispatchError( - GonkSensorsPollResultHandler* aRes, nsresult aRv) -{ - SensorsError error; - - if (NS_FAILED(Convert(aRv, error))) { - error = SENSORS_ERROR_FAIL; - } - DispatchError(aRes, error); -} - -} // namespace hal -} // namespace mozilla diff --git a/hal/gonk/GonkSensorsPollInterface.h b/hal/gonk/GonkSensorsPollInterface.h deleted file mode 100644 index 89381a9bd..000000000 --- a/hal/gonk/GonkSensorsPollInterface.h +++ /dev/null @@ -1,340 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * The poll interface gives yo access to the Sensors daemon's Poll service, - * which handles sensors. The poll service will inform you when sensors are - * detected or removed from the system. You can activate (or deactivate) - * existing sensors and poll will deliver the sensors' events. - * - * All public methods and callback methods run on the main thread. - */ - -#ifndef hal_gonk_GonkSensorsPollInterface_h -#define hal_gonk_GonkSensorsPollInterface_h - -#include -#include -#include "SensorsTypes.h" - -namespace mozilla { -namespace ipc { - -class DaemonSocketPDU; -class DaemonSocketPDUHeader; - -} -} - -namespace mozilla { -namespace hal { - -class SensorsInterface; - -using mozilla::ipc::DaemonSocketPDU; -using mozilla::ipc::DaemonSocketPDUHeader; -using mozilla::ipc::DaemonSocketResultHandler; - -/** - * This class is the result-handler interface for the Sensors - * Poll interface. Methods always run on the main thread. - */ -class GonkSensorsPollResultHandler : public DaemonSocketResultHandler -{ -public: - - /** - * Called if a poll command failed. - * - * @param aError The error code. - */ - virtual void OnError(SensorsError aError); - - /** - * The callback method for |GonkSensorsPollInterface::EnableSensor|. - */ - virtual void EnableSensor(); - - /** - * The callback method for |GonkSensorsPollInterface::DisableSensor|. - */ - virtual void DisableSensor(); - - /** - * The callback method for |GonkSensorsPollInterface::SetPeriod|. - */ - virtual void SetPeriod(); - -protected: - virtual ~GonkSensorsPollResultHandler(); -}; - -/** - * This is the notification-handler interface. Implement this classes - * methods to handle event and notifications from the sensors daemon. - */ -class GonkSensorsPollNotificationHandler -{ -public: - - /** - * The notification handler for errors. You'll receive this call if - * there's been a critical error in the daemon. Either try to handle - * the error, or restart the daemon. - * - * @param aError The error code. - */ - virtual void ErrorNotification(SensorsError aError); - - /** - * This methods gets call when a new sensor has been detected. - * - * @param aId The sensor's id. - * @param aType The sensor's type. - * @param aRange The sensor's maximum value. - * @param aResolution The minimum difference between two consecutive values. - * @param aPower The sensor's power consumption (in mA). - * @param aMinPeriod The minimum time between two events (in ns). - * @param aMaxPeriod The maximum time between two events (in ns). - * @param aTriggerMode The sensor's mode for triggering events. - * @param aDeliveryMode The sensor's urgency for event delivery. - */ - virtual void SensorDetectedNotification(int32_t aId, SensorsType aType, - float aRange, float aResolution, - float aPower, int32_t aMinPeriod, - int32_t aMaxPeriod, - SensorsTriggerMode aTriggerMode, - SensorsDeliveryMode aDeliveryMode); - - /** - * This methods gets call when an existing sensor has been removed. - * - * @param aId The sensor's id. - */ - virtual void SensorLostNotification(int32_t aId); - - /** - * This is the callback methods for sensor events. Only activated sensors - * generate events. All sensors are disabled by default. The actual data - * of the event depends on the sensor type. - * - * @param aId The sensor's id. - * @param aEvent The event's data. - */ - virtual void EventNotification(int32_t aId, const SensorsEvent& aEvent); - -protected: - virtual ~GonkSensorsPollNotificationHandler(); -}; - -/** - * This is the module class for the Sensors poll component. It handles PDU - * packing and unpacking. Methods are either executed on the main thread or - * the I/O thread. - * - * This is an internal class, use |GonkSensorsPollInterface| instead. - */ -class GonkSensorsPollModule -{ -public: - class NotificationHandlerWrapper; - - enum { - SERVICE_ID = 0x01 - }; - - enum { - OPCODE_ERROR = 0x00, - OPCODE_ENABLE_SENSOR = 0x01, - OPCODE_DISABLE_SENSOR = 0x02, - OPCODE_SET_PERIOD = 0x03 - }; - - enum { - MIN_PROTOCOL_VERSION = 1, - MAX_PROTOCOL_VERSION = 1 - }; - - virtual nsresult Send(DaemonSocketPDU* aPDU, - DaemonSocketResultHandler* aRes) = 0; - - nsresult SetProtocolVersion(unsigned long aProtocolVersion); - - // - // Commands - // - - nsresult EnableSensorCmd(int32_t aId, - GonkSensorsPollResultHandler* aRes); - - nsresult DisableSensorCmd(int32_t aId, - GonkSensorsPollResultHandler* aRes); - - nsresult SetPeriodCmd(int32_t aId, uint64_t aPeriod, - GonkSensorsPollResultHandler* aRes); - -protected: - GonkSensorsPollModule(); - virtual ~GonkSensorsPollModule(); - - void HandleSvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - -private: - - // - // Responses - // - - typedef mozilla::ipc::DaemonResultRunnable0< - GonkSensorsPollResultHandler, void> - ResultRunnable; - - typedef mozilla::ipc::DaemonResultRunnable1< - GonkSensorsPollResultHandler, void, SensorsError, SensorsError> - ErrorRunnable; - - void ErrorRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes); - - void EnableSensorRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes); - - void DisableSensorRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes); - - void SetPeriodRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsPollResultHandler* aRes); - - void HandleRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - - // - // Notifications - // - - typedef mozilla::ipc::DaemonNotificationRunnable1< - NotificationHandlerWrapper, void, SensorsError> - ErrorNotification; - - typedef mozilla::ipc::DaemonNotificationRunnable9< - NotificationHandlerWrapper, void, int32_t, SensorsType, - float, float, float, int32_t, int32_t, SensorsTriggerMode, - SensorsDeliveryMode> - SensorDetectedNotification; - - typedef mozilla::ipc::DaemonNotificationRunnable1< - NotificationHandlerWrapper, void, int32_t> - SensorLostNotification; - - typedef mozilla::ipc::DaemonNotificationRunnable2< - NotificationHandlerWrapper, void, int32_t, SensorsEvent, int32_t, - const SensorsEvent&> - EventNotification; - - class SensorDetectedInitOp; - class SensorLostInitOp; - class EventInitOp; - - void ErrorNtf(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU); - - void SensorDetectedNtf(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU); - - void SensorLostNtf(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU); - - void EventNtf(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU); - - void HandleNtf(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes); - -private: - unsigned long mProtocolVersion; -}; - -/** - * This class implements the public interface to the Sensors poll - * component. Use |SensorsInterface::GetPollInterface| to retrieve - * an instance. All methods run on the main thread. - */ -class GonkSensorsPollInterface final -{ -public: - GonkSensorsPollInterface(GonkSensorsPollModule* aModule); - ~GonkSensorsPollInterface(); - - /** - * This method sets the notification handler for poll notifications. Call - * this method immediately after registering the module. Otherwise you won't - * be able able to receive poll notifications. You may not free the handler - * class while the poll component is regsitered. - * - * @param aNotificationHandler An instance of a poll notification handler. - */ - void SetNotificationHandler( - GonkSensorsPollNotificationHandler* aNotificationHandler); - - /** - * This method sets the protocol version. You should set it to the - * value that has been returned from the backend when registering the - * Poll service. You cannot send or receive messages before setting - * the protocol version. - * - * @param aProtocolVersion - * @return NS_OK for supported versions, or an XPCOM error code otherwise. - */ - nsresult SetProtocolVersion(unsigned long aProtocolVersion); - - /** - * Enables an existing sensor. The sensor id will have been delivered in - * a SensorDetectedNotification. - * - * @param aId The sensor's id. - * @param aRes The result handler. - */ - void EnableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes); - - /** - * Disables an existing sensor. The sensor id will have been delivered in - * a SensorDetectedNotification. - * - * @param aId The sensor's id. - * @param aRes The result handler. - */ - void DisableSensor(int32_t aId, GonkSensorsPollResultHandler* aRes); - - /** - * Sets the period for a sensor. The sensor id will have been delivered in - * a SensorDetectedNotification. The value for the period should be between - * the sensor's minimum and maximum period. - * - * @param aId The sensor's id. - * @param aPeriod The sensor's new period. - * @param aRes The result handler. - */ - void SetPeriod(int32_t aId, uint64_t aPeriod, GonkSensorsPollResultHandler* aRes); - -private: - void DispatchError(GonkSensorsPollResultHandler* aRes, SensorsError aError); - void DispatchError(GonkSensorsPollResultHandler* aRes, nsresult aRv); - - GonkSensorsPollModule* mModule; -}; - -} // hal -} // namespace mozilla - -#endif // hal_gonk_GonkSensorsPollInterface_h diff --git a/hal/gonk/GonkSensorsRegistryInterface.cpp b/hal/gonk/GonkSensorsRegistryInterface.cpp deleted file mode 100644 index 601dc7a2a..000000000 --- a/hal/gonk/GonkSensorsRegistryInterface.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GonkSensorsRegistryInterface.h" -#include "GonkSensorsHelpers.h" -#include "HalLog.h" -#include - -namespace mozilla { -namespace hal { - -using namespace mozilla::ipc; - -// -// GonkSensorsRegistryResultHandler -// - -void -GonkSensorsRegistryResultHandler::OnError(SensorsError aError) -{ - HAL_ERR("Received error code %d", static_cast(aError)); -} - -void -GonkSensorsRegistryResultHandler::RegisterModule(uint32_t aProtocolVersion) -{ } - -void -GonkSensorsRegistryResultHandler::UnregisterModule() -{ } - -GonkSensorsRegistryResultHandler::~GonkSensorsRegistryResultHandler() -{ } - -// -// GonkSensorsRegistryModule -// - -GonkSensorsRegistryModule::~GonkSensorsRegistryModule() -{ } - -void -GonkSensorsRegistryModule::HandleSvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - DaemonSocketResultHandler* aRes) -{ - static void (GonkSensorsRegistryModule::* const HandleRsp[])( - const DaemonSocketPDUHeader&, - DaemonSocketPDU&, - GonkSensorsRegistryResultHandler*) = { - [OPCODE_ERROR] = &GonkSensorsRegistryModule::ErrorRsp, - [OPCODE_REGISTER_MODULE] = &GonkSensorsRegistryModule::RegisterModuleRsp, - [OPCODE_UNREGISTER_MODULE] = &GonkSensorsRegistryModule::UnregisterModuleRsp - }; - - if ((aHeader.mOpcode >= MOZ_ARRAY_LENGTH(HandleRsp)) || - !HandleRsp[aHeader.mOpcode]) { - HAL_ERR("Sensors registry response opcode %d unknown", aHeader.mOpcode); - return; - } - - RefPtr res = - static_cast(aRes); - - if (!res) { - return; // Return early if no result handler has been set - } - - (this->*(HandleRsp[aHeader.mOpcode]))(aHeader, aPDU, res); -} - -// Commands -// - -nsresult -GonkSensorsRegistryModule::RegisterModuleCmd( - uint8_t aId, GonkSensorsRegistryResultHandler* aRes) -{ - MOZ_ASSERT(NS_IsMainThread()); - - UniquePtr pdu = - MakeUnique(SERVICE_ID, OPCODE_REGISTER_MODULE, 0); - - nsresult rv = PackPDU(aId, *pdu); - if (NS_FAILED(rv)) { - return rv; - } - rv = Send(pdu.get(), aRes); - if (NS_FAILED(rv)) { - return rv; - } - Unused << pdu.release(); - return NS_OK; -} - -nsresult -GonkSensorsRegistryModule::UnregisterModuleCmd( - uint8_t aId, GonkSensorsRegistryResultHandler* aRes) -{ - MOZ_ASSERT(NS_IsMainThread()); - - UniquePtr pdu = - MakeUnique(SERVICE_ID, OPCODE_UNREGISTER_MODULE, 0); - - nsresult rv = PackPDU(aId, *pdu); - if (NS_FAILED(rv)) { - return rv; - } - rv = Send(pdu.get(), aRes); - if (NS_FAILED(rv)) { - return rv; - } - Unused << pdu.release(); - return NS_OK; -} - -// Responses -// - -void -GonkSensorsRegistryModule::ErrorRsp( - const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, GonkSensorsRegistryResultHandler* aRes) -{ - ErrorRunnable::Dispatch( - aRes, &GonkSensorsRegistryResultHandler::OnError, UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsRegistryModule::RegisterModuleRsp( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - GonkSensorsRegistryResultHandler* aRes) -{ - Uint32ResultRunnable::Dispatch( - aRes, - &GonkSensorsRegistryResultHandler::RegisterModule, - UnpackPDUInitOp(aPDU)); -} - -void -GonkSensorsRegistryModule::UnregisterModuleRsp( - const DaemonSocketPDUHeader& aHeader, DaemonSocketPDU& aPDU, - GonkSensorsRegistryResultHandler* aRes) -{ - ResultRunnable::Dispatch( - aRes, - &GonkSensorsRegistryResultHandler::UnregisterModule, - UnpackPDUInitOp(aPDU)); -} - -// -// GonkSensorsRegistryInterface -// - -GonkSensorsRegistryInterface::GonkSensorsRegistryInterface( - GonkSensorsRegistryModule* aModule) - : mModule(aModule) -{ } - -GonkSensorsRegistryInterface::~GonkSensorsRegistryInterface() -{ } - -void -GonkSensorsRegistryInterface::RegisterModule( - uint8_t aId, GonkSensorsRegistryResultHandler* aRes) -{ - MOZ_ASSERT(mModule); - - nsresult rv = mModule->RegisterModuleCmd(aId, aRes); - if (NS_FAILED(rv)) { - DispatchError(aRes, rv); - } -} - -void -GonkSensorsRegistryInterface::UnregisterModule( - uint8_t aId, GonkSensorsRegistryResultHandler* aRes) -{ - MOZ_ASSERT(mModule); - - nsresult rv = mModule->UnregisterModuleCmd(aId, aRes); - if (NS_FAILED(rv)) { - DispatchError(aRes, rv); - } -} - -void -GonkSensorsRegistryInterface::DispatchError( - GonkSensorsRegistryResultHandler* aRes, SensorsError aError) -{ - DaemonResultRunnable1::Dispatch( - aRes, &GonkSensorsRegistryResultHandler::OnError, - ConstantInitOp1(aError)); -} - -void -GonkSensorsRegistryInterface::DispatchError( - GonkSensorsRegistryResultHandler* aRes, nsresult aRv) -{ - SensorsError error; - - if (NS_FAILED(Convert(aRv, error))) { - error = SENSORS_ERROR_FAIL; - } - DispatchError(aRes, error); -} - -} // namespace hal -} // namespace mozilla diff --git a/hal/gonk/GonkSensorsRegistryInterface.h b/hal/gonk/GonkSensorsRegistryInterface.h deleted file mode 100644 index a9d98d653..000000000 --- a/hal/gonk/GonkSensorsRegistryInterface.h +++ /dev/null @@ -1,182 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * The registry interface gives yo access to the Sensors daemon's Registry - * service. The purpose of the service is to register and setup all other - * services, and make them available. - * - * All public methods and callback methods run on the main thread. - */ - -#ifndef hal_gonk_GonkSensorsRegistryInterface_h -#define hal_gonk_GonkSensorsRegistryInterface_h - -#include -#include -#include "SensorsTypes.h" - -namespace mozilla { -namespace ipc { - -class DaemonSocketPDU; -class DaemonSocketPDUHeader; - -} -} - -namespace mozilla { -namespace hal { - -class SensorsInterface; - -using mozilla::ipc::DaemonSocketPDU; -using mozilla::ipc::DaemonSocketPDUHeader; -using mozilla::ipc::DaemonSocketResultHandler; - -/** - * This class is the result-handler interface for the Sensors - * Registry interface. Methods always run on the main thread. - */ -class GonkSensorsRegistryResultHandler : public DaemonSocketResultHandler -{ -public: - - /** - * Called if a registry command failed. - * - * @param aError The error code. - */ - virtual void OnError(SensorsError aError); - - /** - * The callback method for |GonkSensorsRegistryInterface::RegisterModule|. - * - * @param aProtocolVersion The daemon's protocol version. Make sure it's - * compatible with Gecko's implementation. - */ - virtual void RegisterModule(uint32_t aProtocolVersion); - - /** - * The callback method for |SensorsRegsitryInterface::UnregisterModule|. - */ - virtual void UnregisterModule(); - -protected: - virtual ~GonkSensorsRegistryResultHandler(); -}; - -/** - * This is the module class for the Sensors registry component. It handles - * PDU packing and unpacking. Methods are either executed on the main thread - * or the I/O thread. - * - * This is an internal class, use |GonkSensorsRegistryInterface| instead. - */ -class GonkSensorsRegistryModule -{ -public: - enum { - SERVICE_ID = 0x00 - }; - - enum { - OPCODE_ERROR = 0x00, - OPCODE_REGISTER_MODULE = 0x01, - OPCODE_UNREGISTER_MODULE = 0x02 - }; - - virtual nsresult Send(DaemonSocketPDU* aPDU, - DaemonSocketResultHandler* aRes) = 0; - - // - // Commands - // - - nsresult RegisterModuleCmd(uint8_t aId, - GonkSensorsRegistryResultHandler* aRes); - - nsresult UnregisterModuleCmd(uint8_t aId, - GonkSensorsRegistryResultHandler* aRes); - -protected: - virtual ~GonkSensorsRegistryModule(); - - void HandleSvc(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, DaemonSocketResultHandler* aRes); - - // - // Responses - // - - typedef mozilla::ipc::DaemonResultRunnable0< - GonkSensorsRegistryResultHandler, void> - ResultRunnable; - - typedef mozilla::ipc::DaemonResultRunnable1< - GonkSensorsRegistryResultHandler, void, uint32_t, uint32_t> - Uint32ResultRunnable; - - typedef mozilla::ipc::DaemonResultRunnable1< - GonkSensorsRegistryResultHandler, void, SensorsError, SensorsError> - ErrorRunnable; - - void ErrorRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsRegistryResultHandler* aRes); - - void RegisterModuleRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsRegistryResultHandler* aRes); - - void UnregisterModuleRsp(const DaemonSocketPDUHeader& aHeader, - DaemonSocketPDU& aPDU, - GonkSensorsRegistryResultHandler* aRes); -}; - -/** - * This class implements the public interface to the Sensors Registry - * component. Use |SensorsInterface::GetRegistryInterface| to retrieve - * an instance. All methods run on the main thread. - */ -class GonkSensorsRegistryInterface final -{ -public: - GonkSensorsRegistryInterface(GonkSensorsRegistryModule* aModule); - ~GonkSensorsRegistryInterface(); - - /** - * Sends a RegisterModule command to the Sensors daemon. When the - * result handler's |RegisterModule| method gets called, the service - * has been registered successfully and can be used. - * - * @param aId The id of the service that is to be registered. - * @param aRes The result handler. - */ - void RegisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes); - - /** - * Sends an UnregisterModule command to the Sensors daemon. The service - * should not be used afterwards until it has been registered again. - * - * @param aId The id of the service that is to be unregistered. - * @param aRes The result handler. - */ - void UnregisterModule(uint8_t aId, GonkSensorsRegistryResultHandler* aRes); - -private: - void DispatchError(GonkSensorsRegistryResultHandler* aRes, - SensorsError aError); - void DispatchError(GonkSensorsRegistryResultHandler* aRes, - nsresult aRv); - - GonkSensorsRegistryModule* mModule; -}; - -} // namespace hal -} // namespace mozilla - -#endif // hal_gonk_GonkSensorsRegistryInterface_h diff --git a/hal/gonk/GonkSwitch.cpp b/hal/gonk/GonkSwitch.cpp deleted file mode 100644 index b2c31c973..000000000 --- a/hal/gonk/GonkSwitch.cpp +++ /dev/null @@ -1,479 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include -#include - -#include "base/message_loop.h" -#include "base/task.h" - -#include "Hal.h" -#include "HalLog.h" -#include "mozilla/FileUtils.h" -#include "mozilla/RefPtr.h" -#include "mozilla/Monitor.h" -#include "nsPrintfCString.h" -#include "nsXULAppAPI.h" -#include "nsThreadUtils.h" -#include "UeventPoller.h" - -using namespace mozilla::hal; - -#define SWITCH_HEADSET_DEVPATH "/devices/virtual/switch/h2w" -#define SWITCH_USB_DEVPATH_GB "/devices/virtual/switch/usb_configuration" -#define SWITCH_USB_DEVPATH_ICS "/devices/virtual/android_usb/android0" - -namespace mozilla { -namespace hal_impl { -/** - * The uevent for a usb on GB insertion looks like: - * - * change@/devices/virtual/switch/usb_configuration - * ACTION=change - * DEVPATH=/devices/virtual/switch/usb_configuration - * SUBSYSTEM=switch - * SWITCH_NAME=usb_configuration - * SWITCH_STATE=0 - * SEQNUM=5038 - */ -class SwitchHandler -{ -public: - NS_INLINE_DECL_REFCOUNTING(SwitchHandler) - - SwitchHandler(const char* aDevPath, SwitchDevice aDevice) - : mDevPath(aDevPath), - mState(SWITCH_STATE_UNKNOWN), - mDevice(aDevice) - { - GetInitialState(); - } - - bool CheckEvent(NetlinkEvent* aEvent) - { - if (strcmp(GetSubsystem(), aEvent->getSubsystem()) || - strcmp(mDevPath, aEvent->findParam("DEVPATH"))) { - return false; - } - - mState = ConvertState(GetStateString(aEvent)); - return mState != SWITCH_STATE_UNKNOWN; - } - - SwitchState GetState() - { - return mState; - } - - SwitchDevice GetType() - { - return mDevice; - } -protected: - virtual ~SwitchHandler() - { - } - - virtual const char* GetSubsystem() - { - return "switch"; - } - - virtual const char* GetStateString(NetlinkEvent* aEvent) - { - return aEvent->findParam("SWITCH_STATE"); - } - - void GetInitialState() - { - nsPrintfCString statePath("/sys%s/state", mDevPath); - int fd = open(statePath.get(), O_RDONLY); - if (fd <= 0) { - return; - } - - ScopedClose autoClose(fd); - char state[16]; - ssize_t bytesRead = read(fd, state, sizeof(state)); - if (bytesRead < 0) { - HAL_ERR("Read data from %s fails", statePath.get()); - return; - } - - if (state[bytesRead - 1] == '\n') { - bytesRead--; - } - - state[bytesRead] = '\0'; - mState = ConvertState(state); - } - - virtual SwitchState ConvertState(const char* aState) - { - MOZ_ASSERT(aState); - return aState[0] == '0' ? SWITCH_STATE_OFF : SWITCH_STATE_ON; - } - - const char* mDevPath; - SwitchState mState; - SwitchDevice mDevice; -}; - -/** - * The uevent delivered for the USB configuration under ICS looks like, - * - * change@/devices/virtual/android_usb/android0 - * ACTION=change - * DEVPATH=/devices/virtual/android_usb/android0 - * SUBSYSTEM=android_usb - * USB_STATE=CONFIGURED - * SEQNUM=1802 - */ -class SwitchHandlerUsbIcs: public SwitchHandler -{ -public: - SwitchHandlerUsbIcs(const char* aDevPath) : SwitchHandler(aDevPath, SWITCH_USB) - { - SwitchHandler::GetInitialState(); - } - - virtual ~SwitchHandlerUsbIcs() { } - -protected: - virtual const char* GetSubsystem() - { - return "android_usb"; - } - - virtual const char* GetStateString(NetlinkEvent* aEvent) - { - return aEvent->findParam("USB_STATE"); - } - - SwitchState ConvertState(const char* aState) - { - MOZ_ASSERT(aState); - return strcmp(aState, "CONFIGURED") == 0 ? SWITCH_STATE_ON : SWITCH_STATE_OFF; - } -}; - -/** - * The uevent delivered for the headset under ICS looks like, - * - * change@/devices/virtual/switch/h2w - * ACTION=change - * DEVPATH=/devices/virtual/switch/h2w - * SUBSYSTEM=switch - * SWITCH_NAME=h2w - * SWITCH_STATE=2 // Headset with no mic - * SEQNUM=2581 - * On Otoro, SWITCH_NAME could be Headset/No Device when plug/unplug. - * change@/devices/virtual/switch/h2w - * ACTION=change - * DEVPATH=/devices/virtual/switch/h2w - * SUBSYSTEM=switch - * SWITCH_NAME=Headset - * SWITCH_STATE=1 // Headset with mic - * SEQNUM=1602 - */ -class SwitchHandlerHeadphone: public SwitchHandler -{ -public: - SwitchHandlerHeadphone(const char* aDevPath) : - SwitchHandler(aDevPath, SWITCH_HEADPHONES) - { - SwitchHandler::GetInitialState(); - } - - virtual ~SwitchHandlerHeadphone() { } - -protected: - SwitchState ConvertState(const char* aState) - { - MOZ_ASSERT(aState); - - return aState[0] == '0' ? SWITCH_STATE_OFF : - (aState[0] == '1' ? SWITCH_STATE_HEADSET : SWITCH_STATE_HEADPHONE); - } -}; - - -typedef nsTArray > SwitchHandlerArray; - -class SwitchEventRunnable : public Runnable -{ -public: - SwitchEventRunnable(SwitchEvent& aEvent) : mEvent(aEvent) - { - } - - NS_IMETHOD Run() override - { - NotifySwitchChange(mEvent); - return NS_OK; - } -private: - SwitchEvent mEvent; -}; - -class SwitchEventObserver final : public IUeventObserver -{ - ~SwitchEventObserver() - { - mHandler.Clear(); - } - -public: - NS_INLINE_DECL_REFCOUNTING(SwitchEventObserver) - SwitchEventObserver() - : mEnableCount(0), - mHeadphonesFromInputDev(false) - { - Init(); - } - - int GetEnableCount() - { - return mEnableCount; - } - - void EnableSwitch(SwitchDevice aDevice) - { - mEventInfo[aDevice].mEnabled = true; - mEnableCount++; - } - - void DisableSwitch(SwitchDevice aDevice) - { - mEventInfo[aDevice].mEnabled = false; - mEnableCount--; - } - - void Notify(const NetlinkEvent& aEvent) - { - SwitchState currState; - - SwitchDevice device = GetEventInfo(aEvent, currState); - if (device == SWITCH_DEVICE_UNKNOWN) { - return; - } - - EventInfo& info = mEventInfo[device]; - if (currState == info.mEvent.status()) { - return; - } - - info.mEvent.status() = currState; - - if (info.mEnabled) { - NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent)); - } - } - - void Notify(SwitchDevice aDevice, SwitchState aState) - { - EventInfo& info = mEventInfo[aDevice]; - if (aState == info.mEvent.status()) { - return; - } - - info.mEvent.status() = aState; - - if (info.mEnabled) { - NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent)); - } - } - - SwitchState GetCurrentInformation(SwitchDevice aDevice) - { - return mEventInfo[aDevice].mEvent.status(); - } - - void NotifyAnEvent(SwitchDevice aDevice) - { - EventInfo& info = mEventInfo[aDevice]; - if (info.mEvent.status() != SWITCH_STATE_UNKNOWN) { - NS_DispatchToMainThread(new SwitchEventRunnable(info.mEvent)); - } - } - - bool GetHeadphonesFromInputDev() - { - return mHeadphonesFromInputDev; - } - -private: - class EventInfo - { - public: - EventInfo() : mEnabled(false) - { - mEvent.status() = SWITCH_STATE_UNKNOWN; - mEvent.device() = SWITCH_DEVICE_UNKNOWN; - } - SwitchEvent mEvent; - bool mEnabled; - }; - - EventInfo mEventInfo[NUM_SWITCH_DEVICE]; - size_t mEnableCount; - SwitchHandlerArray mHandler; - bool mHeadphonesFromInputDev; - - // This function might also get called on the main thread - // (from IsHeadphoneEventFromInputDev) - void Init() - { - RefPtr switchHeadPhone = - new SwitchHandlerHeadphone(SWITCH_HEADSET_DEVPATH); - - // If the initial state is unknown, it means the headphone event is from input dev - mHeadphonesFromInputDev = switchHeadPhone->GetState() == SWITCH_STATE_UNKNOWN ? true : false; - - if (!mHeadphonesFromInputDev) { - mHandler.AppendElement(switchHeadPhone); - } else { - // If headphone status will be notified from input dev then initialize - // status to "off" and wait for event notification. - mEventInfo[SWITCH_HEADPHONES].mEvent.device() = SWITCH_HEADPHONES; - mEventInfo[SWITCH_HEADPHONES].mEvent.status() = SWITCH_STATE_OFF; - } - mHandler.AppendElement(new SwitchHandler(SWITCH_USB_DEVPATH_GB, SWITCH_USB)); - mHandler.AppendElement(new SwitchHandlerUsbIcs(SWITCH_USB_DEVPATH_ICS)); - - SwitchHandlerArray::index_type handlerIndex; - SwitchHandlerArray::size_type numHandlers = mHandler.Length(); - - for (handlerIndex = 0; handlerIndex < numHandlers; handlerIndex++) { - SwitchState state = mHandler[handlerIndex]->GetState(); - if (state == SWITCH_STATE_UNKNOWN) { - continue; - } - - SwitchDevice device = mHandler[handlerIndex]->GetType(); - mEventInfo[device].mEvent.device() = device; - mEventInfo[device].mEvent.status() = state; - } - } - - SwitchDevice GetEventInfo(const NetlinkEvent& aEvent, SwitchState& aState) - { - //working around the android code not being const-correct - NetlinkEvent *e = const_cast(&aEvent); - - for (size_t i = 0; i < mHandler.Length(); i++) { - if (mHandler[i]->CheckEvent(e)) { - aState = mHandler[i]->GetState(); - return mHandler[i]->GetType(); - } - } - return SWITCH_DEVICE_UNKNOWN; - } -}; - -static RefPtr sSwitchObserver; - -static void -InitializeResourceIfNeed() -{ - if (!sSwitchObserver) { - sSwitchObserver = new SwitchEventObserver(); - RegisterUeventListener(sSwitchObserver); - } -} - -static void -ReleaseResourceIfNeed() -{ - if (sSwitchObserver->GetEnableCount() == 0) { - UnregisterUeventListener(sSwitchObserver); - sSwitchObserver = nullptr; - } -} - -static void -EnableSwitchNotificationsIOThread(SwitchDevice aDevice, Monitor *aMonitor) -{ - InitializeResourceIfNeed(); - sSwitchObserver->EnableSwitch(aDevice); - { - MonitorAutoLock lock(*aMonitor); - lock.Notify(); - } - - // Notify the latest state if IO thread has the information. - if (sSwitchObserver->GetEnableCount() > 1) { - sSwitchObserver->NotifyAnEvent(aDevice); - } -} - -void -EnableSwitchNotifications(SwitchDevice aDevice) -{ - Monitor monitor("EnableSwitch.monitor"); - { - MonitorAutoLock lock(monitor); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(EnableSwitchNotificationsIOThread, aDevice, &monitor)); - lock.Wait(); - } -} - -static void -DisableSwitchNotificationsIOThread(SwitchDevice aDevice) -{ - MOZ_ASSERT(sSwitchObserver->GetEnableCount()); - sSwitchObserver->DisableSwitch(aDevice); - ReleaseResourceIfNeed(); -} - -void -DisableSwitchNotifications(SwitchDevice aDevice) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(DisableSwitchNotificationsIOThread, aDevice)); -} - -SwitchState -GetCurrentSwitchState(SwitchDevice aDevice) -{ - MOZ_ASSERT(sSwitchObserver && sSwitchObserver->GetEnableCount()); - return sSwitchObserver->GetCurrentInformation(aDevice); -} - -static void -NotifySwitchStateIOThread(SwitchDevice aDevice, SwitchState aState) -{ - InitializeResourceIfNeed(); - sSwitchObserver->Notify(aDevice, aState); -} - -void NotifySwitchStateFromInputDevice(SwitchDevice aDevice, SwitchState aState) -{ - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(NotifySwitchStateIOThread, aDevice, aState)); -} - -bool IsHeadphoneEventFromInputDev() -{ - // Instead of calling InitializeResourceIfNeed, create new SwitchEventObserver - // to prevent calling RegisterUeventListener in main thread. - RefPtr switchObserver = new SwitchEventObserver(); - return switchObserver->GetHeadphonesFromInputDev(); -} - -} // hal_impl -} //mozilla diff --git a/hal/gonk/SensorsTypes.h b/hal/gonk/SensorsTypes.h deleted file mode 100644 index 35c852f5a..000000000 --- a/hal/gonk/SensorsTypes.h +++ /dev/null @@ -1,140 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef hal_gonk_SensorsTypes_h -#define hal_gonk_SensorsTypes_h - -namespace mozilla { -namespace hal { - -enum SensorsDeliveryMode { - SENSORS_DELIVERY_MODE_BEST_EFFORT, - SENSORS_DELIVERY_MODE_IMMEDIATE -}; - -enum SensorsError { - SENSORS_ERROR_NONE, - SENSORS_ERROR_FAIL, - SENSORS_ERROR_NOT_READY, - SENSORS_ERROR_NOMEM, - SENSORS_ERROR_BUSY, - SENSORS_ERROR_DONE, - SENSORS_ERROR_UNSUPPORTED, - SENSORS_ERROR_PARM_INVALID -}; - -enum SensorsStatus { - SENSORS_STATUS_NO_CONTACT, - SENSORS_STATUS_UNRELIABLE, - SENSORS_STATUS_ACCURACY_LOW, - SENSORS_STATUS_ACCURACY_MEDIUM, - SENSORS_STATUS_ACCURACY_HIGH -}; - -enum SensorsTriggerMode { - SENSORS_TRIGGER_MODE_CONTINUOUS, - SENSORS_TRIGGER_MODE_ON_CHANGE, - SENSORS_TRIGGER_MODE_ONE_SHOT, - SENSORS_TRIGGER_MODE_SPECIAL -}; - -enum SensorsType { - SENSORS_TYPE_ACCELEROMETER, - SENSORS_TYPE_GEOMAGNETIC_FIELD, - SENSORS_TYPE_ORIENTATION, - SENSORS_TYPE_GYROSCOPE, - SENSORS_TYPE_LIGHT, - SENSORS_TYPE_PRESSURE, - SENSORS_TYPE_TEMPERATURE, - SENSORS_TYPE_PROXIMITY, - SENSORS_TYPE_GRAVITY, - SENSORS_TYPE_LINEAR_ACCELERATION, - SENSORS_TYPE_ROTATION_VECTOR, - SENSORS_TYPE_RELATIVE_HUMIDITY, - SENSORS_TYPE_AMBIENT_TEMPERATURE, - SENSORS_TYPE_MAGNETIC_FIELD_UNCALIBRATED, - SENSORS_TYPE_GAME_ROTATION_VECTOR, - SENSORS_TYPE_GYROSCOPE_UNCALIBRATED, - SENSORS_TYPE_SIGNIFICANT_MOTION, - SENSORS_TYPE_STEP_DETECTED, - SENSORS_TYPE_STEP_COUNTER, - SENSORS_TYPE_GEOMAGNETIC_ROTATION_VECTOR, - SENSORS_TYPE_HEART_RATE, - SENSORS_TYPE_TILT_DETECTOR, - SENSORS_TYPE_WAKE_GESTURE, - SENSORS_TYPE_GLANCE_GESTURE, - SENSORS_TYPE_PICK_UP_GESTURE, - SENSORS_TYPE_WRIST_TILT_GESTURE, - SENSORS_NUM_TYPES -}; - -struct SensorsEvent { - SensorsType mType; - SensorsStatus mStatus; - SensorsDeliveryMode mDeliveryMode; - int64_t mTimestamp; - union { - float mFloat[6]; - uint64_t mUint[1]; - } mData; -}; - -/** - * |SensorsSensor| represents a device sensor; either single or composite. - */ -struct SensorsSensor { - SensorsSensor(int32_t aId, SensorsType aType, - float aRange, float aResolution, - float aPower, int32_t aMinPeriod, - int32_t aMaxPeriod, - SensorsTriggerMode aTriggerMode, - SensorsDeliveryMode aDeliveryMode) - : mId(aId) - , mType(aType) - , mRange(aRange) - , mResolution(aResolution) - , mPower(aPower) - , mMinPeriod(aMinPeriod) - , mMaxPeriod(aMaxPeriod) - , mTriggerMode(aTriggerMode) - , mDeliveryMode(aDeliveryMode) - { } - - int32_t mId; - SensorsType mType; - float mRange; - float mResolution; - float mPower; - int32_t mMinPeriod; - int32_t mMaxPeriod; - SensorsTriggerMode mTriggerMode; - SensorsDeliveryMode mDeliveryMode; -}; - -/** - * |SensorClass| represents the status of a specific sensor type. - */ -struct SensorsSensorClass { - SensorsSensorClass() - : mActivated(0) - , mMinValue(0) - , mMaxValue(0) - { } - - void UpdateFromSensor(const SensorsSensor& aSensor) - { - mMaxValue = std::max(aSensor.mRange, mMaxValue); - } - - uint32_t mActivated; - float mMinValue; - float mMaxValue; -}; - -} // namespace hal -} // namespace mozilla - -#endif // hal_gonk_SensorsTypes_h diff --git a/hal/gonk/SystemService.cpp b/hal/gonk/SystemService.cpp deleted file mode 100644 index 2b98f5fdd..000000000 --- a/hal/gonk/SystemService.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "Hal.h" - -#include -#include -#include - -#include "HalLog.h" -#include "nsITimer.h" -#include "mozilla/Unused.h" - -namespace mozilla { -namespace hal_impl { - -static const int sRetryInterval = 100; // ms - -bool -SystemServiceIsRunning(const char* aSvcName) -{ - MOZ_ASSERT(NS_IsMainThread()); - - char key[PROPERTY_KEY_MAX]; - auto res = snprintf(key, sizeof(key), "init.svc.%s", aSvcName); - - if (res < 0) { - HAL_ERR("snprintf: %s", strerror(errno)); - return false; - } else if (static_cast(res) >= sizeof(key)) { - HAL_ERR("snprintf: trunctated service name %s", aSvcName); - return false; - } - - char value[PROPERTY_VALUE_MAX]; - Unused << NS_WARN_IF(property_get(key, value, "") < 0); - - return !strcmp(value, "running"); -} - -class StartSystemServiceTimerCallback final : public nsITimerCallback -{ - NS_DECL_THREADSAFE_ISUPPORTS; - -public: - StartSystemServiceTimerCallback(const char* aSvcName, const char* aArgs) - : mSvcName(aSvcName) - , mArgs(aArgs) - { - MOZ_COUNT_CTOR_INHERITED(StartSystemServiceTimerCallback, - nsITimerCallback); - } - - NS_IMETHOD Notify(nsITimer* aTimer) override - { - MOZ_ASSERT(NS_IsMainThread()); - - return StartSystemService(mSvcName.get(), mArgs.get()); - } - -protected: - ~StartSystemServiceTimerCallback() - { - MOZ_COUNT_DTOR_INHERITED(StartSystemServiceTimerCallback, - nsITimerCallback); - } - -private: - nsCString mSvcName; - nsCString mArgs; -}; - -NS_IMPL_ISUPPORTS0(StartSystemServiceTimerCallback); - -nsresult -StartSystemService(const char* aSvcName, const char* aArgs) -{ - MOZ_ASSERT(NS_IsMainThread()); - - char value[PROPERTY_VALUE_MAX]; - auto res = snprintf(value, sizeof(value), "%s:%s", aSvcName, aArgs); - - if (res < 0) { - HAL_ERR("snprintf: %s", strerror(errno)); - return NS_ERROR_FAILURE; - } else if (static_cast(res) >= sizeof(value)) { - HAL_ERR("snprintf: trunctated service name %s", aSvcName); - return NS_ERROR_OUT_OF_MEMORY; - } - - if (NS_WARN_IF(property_set("ctl.start", value) < 0)) { - return NS_ERROR_FAILURE; - } - - /* If the system service is not running, re-try later to start it. - * - * This condition happens when we restart a service immediately - * after it crashed, as the service state remains 'stopping' - * instead of 'stopped'. Due to the limitation of property service, - * hereby add delay. See Bug 1143925 Comment 41. - */ - if (!SystemServiceIsRunning(aSvcName)) { - nsCOMPtr timer = do_CreateInstance("@mozilla.org/timer;1"); - if (!timer) { - return NS_ERROR_FAILURE; - } - - RefPtr timerCallback = - new StartSystemServiceTimerCallback(aSvcName, aArgs); - - timer->InitWithCallback(timerCallback, - sRetryInterval, - nsITimer::TYPE_ONE_SHOT); - } - - return NS_OK; -} - -void -StopSystemService(const char* aSvcName) -{ - MOZ_ASSERT(NS_IsMainThread()); - - Unused << NS_WARN_IF(property_set("ctl.stop", aSvcName)); -} - -} // namespace hal_impl -} // namespace mozilla diff --git a/hal/gonk/UeventPoller.cpp b/hal/gonk/UeventPoller.cpp deleted file mode 100644 index 3fbe850ed..000000000 --- a/hal/gonk/UeventPoller.cpp +++ /dev/null @@ -1,312 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "HalLog.h" -#include "nsDebug.h" -#include "base/message_loop.h" -#include "base/task.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Monitor.h" -#include "nsThreadUtils.h" -#include "nsXULAppAPI.h" - -#include "UeventPoller.h" - -using namespace mozilla; - -namespace mozilla { -namespace hal_impl { - -static void ShutdownUevent(); - -class NetlinkPoller : public MessageLoopForIO::Watcher -{ -public: - NetlinkPoller() : mSocket(-1), - mIOLoop(MessageLoopForIO::current()) - { - } - - virtual ~NetlinkPoller() {} - - bool OpenSocket(); - - virtual void OnFileCanReadWithoutBlocking(int fd); - - // no writing to the netlink socket - virtual void OnFileCanWriteWithoutBlocking(int fd) - { - MOZ_CRASH("Must not write to netlink socket"); - } - - MessageLoopForIO *GetIOLoop () const { return mIOLoop; } - void RegisterObserver(IUeventObserver *aObserver) - { - mUeventObserverList.AddObserver(aObserver); - } - - void UnregisterObserver(IUeventObserver *aObserver) - { - mUeventObserverList.RemoveObserver(aObserver); - if (mUeventObserverList.Length() == 0) { - ShutdownUevent(); // this will destroy self - } - } - -private: - ScopedClose mSocket; - MessageLoopForIO* mIOLoop; - MessageLoopForIO::FileDescriptorWatcher mReadWatcher; - - const static int kBuffsize = 64 * 1024; - uint8_t mBuffer [kBuffsize]; - - typedef ObserverList UeventObserverList; - UeventObserverList mUeventObserverList; -}; - -bool -NetlinkPoller::OpenSocket() -{ - mSocket.rwget() = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); - if (mSocket.get() < 0) { - return false; - } - - int sz = kBuffsize; - - if (setsockopt(mSocket.get(), SOL_SOCKET, SO_RCVBUFFORCE, &sz, - sizeof(sz)) < 0) { - return false; - } - - // add FD_CLOEXEC flag - int flags = fcntl(mSocket.get(), F_GETFD); - if (flags == -1) { - return false; - } - flags |= FD_CLOEXEC; - if (fcntl(mSocket.get(), F_SETFD, flags) == -1) { - return false; - } - - // set non-blocking - if (fcntl(mSocket.get(), F_SETFL, O_NONBLOCK) == -1) { - return false; - } - - struct sockaddr_nl saddr; - bzero(&saddr, sizeof(saddr)); - saddr.nl_family = AF_NETLINK; - saddr.nl_groups = 1; - saddr.nl_pid = gettid(); - - do { - if (bind(mSocket.get(), (struct sockaddr *)&saddr, sizeof(saddr)) == 0) { - break; - } - - if (errno != EADDRINUSE) { - return false; - } - - if (saddr.nl_pid == 0) { - return false; - } - - // Once there was any other place in the same process assigning saddr.nl_pid by - // gettid(), we can detect it and print warning message. - HAL_LOG("The netlink socket address saddr.nl_pid=%u is in use. " - "Let the kernel re-assign.\n", saddr.nl_pid); - saddr.nl_pid = 0; - } while (true); - - if (!mIOLoop->WatchFileDescriptor(mSocket.get(), - true, - MessageLoopForIO::WATCH_READ, - &mReadWatcher, - this)) { - return false; - } - - return true; -} - -static StaticAutoPtr sPoller; - -class UeventInitTask : public Runnable -{ - NS_IMETHOD Run() override - { - if (!sPoller) { - return NS_OK; - } - if (sPoller->OpenSocket()) { - return NS_OK; - } - sPoller->GetIOLoop()->PostDelayedTask(MakeAndAddRef(), - 1000); - return NS_OK; - } -}; - -void -NetlinkPoller::OnFileCanReadWithoutBlocking(int fd) -{ - MOZ_ASSERT(fd == mSocket.get()); - while (true) { - int ret = read(fd, mBuffer, kBuffsize); - if (ret == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) { - return; - } - if (errno == EINTR) { - continue; - } - } - if (ret <= 0) { - // fatal error on netlink socket which should not happen - _exit(1); - } - NetlinkEvent netlinkEvent; - netlinkEvent.decode(reinterpret_cast(mBuffer), ret); - mUeventObserverList.Broadcast(netlinkEvent); - } -} - -static bool sShutdown = false; - -class ShutdownNetlinkPoller; -static StaticAutoPtr sShutdownPoller; -static Monitor* sMonitor = nullptr; - -class ShutdownNetlinkPoller { -public: - ~ShutdownNetlinkPoller() - { - // This is called from KillClearOnShutdown() on the main thread. - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(XRE_GetIOMessageLoop()); - - { - MonitorAutoLock lock(*sMonitor); - - XRE_GetIOMessageLoop()->PostTask( - NewRunnableFunction(ShutdownUeventIOThread)); - - while (!sShutdown) { - lock.Wait(); - } - } - - sShutdown = true; - delete sMonitor; - } - - static void MaybeInit() - { - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - if (sShutdown || sMonitor) { - // Don't init twice or init after shutdown. - return; - } - - sMonitor = new Monitor("ShutdownNetlinkPoller.monitor"); - { - ShutdownNetlinkPoller* shutdownPoller = new ShutdownNetlinkPoller(); - - nsCOMPtr runnable = NS_NewRunnableFunction([=] () -> void - { - sShutdownPoller = shutdownPoller; - ClearOnShutdown(&sShutdownPoller); // Must run on the main thread. - }); - MOZ_ASSERT(runnable); - MOZ_ALWAYS_SUCCEEDS( - NS_DispatchToMainThread(runnable, NS_DISPATCH_NORMAL)); - } - } -private: - ShutdownNetlinkPoller() = default; - static void ShutdownUeventIOThread() - { - MonitorAutoLock l(*sMonitor); - ShutdownUevent(); // Must run on the IO thread. - sShutdown = true; - l.NotifyAll(); - } -}; - -static void -InitializeUevent() -{ - MOZ_ASSERT(!sPoller); - sPoller = new NetlinkPoller(); - sPoller->GetIOLoop()->PostTask(MakeAndAddRef()); - - ShutdownNetlinkPoller::MaybeInit(); -} - -static void -ShutdownUevent() -{ - sPoller = nullptr; -} - -void -RegisterUeventListener(IUeventObserver *aObserver) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (sShutdown) { - return; - } - - if (!sPoller) { - InitializeUevent(); - } - sPoller->RegisterObserver(aObserver); -} - -void -UnregisterUeventListener(IUeventObserver *aObserver) -{ - MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); - - if (sShutdown) { - return; - } - - sPoller->UnregisterObserver(aObserver); -} - -} // hal_impl -} // mozilla - diff --git a/hal/gonk/UeventPoller.h b/hal/gonk/UeventPoller.h deleted file mode 100644 index ba121cec2..000000000 --- a/hal/gonk/UeventPoller.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef _mozilla_uevent_poller_h_ -#define _mozilla_uevent_poller_h_ - -#include -#include "mozilla/Observer.h" - -class NetlinkEvent; - -namespace mozilla { -namespace hal_impl { - -typedef mozilla::Observer IUeventObserver; - -/** - * Register for uevent notification. Note that the method should run on the - * IO Thread - * @aObserver the observer to be added. The observer's Notify() is only called - * on the IO Thread - */ -void RegisterUeventListener(IUeventObserver *aObserver); - -/** - * Unregister for uevent notification. Note that the method should run on the - * IO Thread - * @aObserver the observer to be removed - */ -void UnregisterUeventListener(IUeventObserver *aObserver); - -} -} - -#endif - diff --git a/hal/gonk/fanotify.h b/hal/gonk/fanotify.h deleted file mode 100644 index e715d3bf9..000000000 --- a/hal/gonk/fanotify.h +++ /dev/null @@ -1,118 +0,0 @@ -#ifndef _LINUX_FANOTIFY_H -#define _LINUX_FANOTIFY_H - -/* This is a Linux header generated by "make headers_install" */ - -#include - -/* the following events that user-space can register for */ -#define FAN_ACCESS 0x00000001 /* File was accessed */ -#define FAN_MODIFY 0x00000002 /* File was modified */ -#define FAN_CLOSE_WRITE 0x00000008 /* Writtable file closed */ -#define FAN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */ -#define FAN_OPEN 0x00000020 /* File was opened */ - -#define FAN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */ - -#define FAN_OPEN_PERM 0x00010000 /* File open in perm check */ -#define FAN_ACCESS_PERM 0x00020000 /* File accessed in perm check */ - -#define FAN_ONDIR 0x40000000 /* event occurred against dir */ - -#define FAN_EVENT_ON_CHILD 0x08000000 /* interested in child events */ - -/* helper events */ -#define FAN_CLOSE (FAN_CLOSE_WRITE | FAN_CLOSE_NOWRITE) /* close */ - -/* flags used for fanotify_init() */ -#define FAN_CLOEXEC 0x00000001 -#define FAN_NONBLOCK 0x00000002 - -/* These are NOT bitwise flags. Both bits are used togther. */ -#define FAN_CLASS_NOTIF 0x00000000 -#define FAN_CLASS_CONTENT 0x00000004 -#define FAN_CLASS_PRE_CONTENT 0x00000008 -#define FAN_ALL_CLASS_BITS (FAN_CLASS_NOTIF | FAN_CLASS_CONTENT | \ - FAN_CLASS_PRE_CONTENT) - -#define FAN_UNLIMITED_QUEUE 0x00000010 -#define FAN_UNLIMITED_MARKS 0x00000020 - -#define FAN_ALL_INIT_FLAGS (FAN_CLOEXEC | FAN_NONBLOCK | \ - FAN_ALL_CLASS_BITS | FAN_UNLIMITED_QUEUE |\ - FAN_UNLIMITED_MARKS) - -/* flags used for fanotify_modify_mark() */ -#define FAN_MARK_ADD 0x00000001 -#define FAN_MARK_REMOVE 0x00000002 -#define FAN_MARK_DONT_FOLLOW 0x00000004 -#define FAN_MARK_ONLYDIR 0x00000008 -#define FAN_MARK_MOUNT 0x00000010 -#define FAN_MARK_IGNORED_MASK 0x00000020 -#define FAN_MARK_IGNORED_SURV_MODIFY 0x00000040 -#define FAN_MARK_FLUSH 0x00000080 - -#define FAN_ALL_MARK_FLAGS (FAN_MARK_ADD |\ - FAN_MARK_REMOVE |\ - FAN_MARK_DONT_FOLLOW |\ - FAN_MARK_ONLYDIR |\ - FAN_MARK_MOUNT |\ - FAN_MARK_IGNORED_MASK |\ - FAN_MARK_IGNORED_SURV_MODIFY |\ - FAN_MARK_FLUSH) - -/* - * All of the events - we build the list by hand so that we can add flags in - * the future and not break backward compatibility. Apps will get only the - * events that they originally wanted. Be sure to add new events here! - */ -#define FAN_ALL_EVENTS (FAN_ACCESS |\ - FAN_MODIFY |\ - FAN_CLOSE |\ - FAN_OPEN) - -/* - * All events which require a permission response from userspace - */ -#define FAN_ALL_PERM_EVENTS (FAN_OPEN_PERM |\ - FAN_ACCESS_PERM) - -#define FAN_ALL_OUTGOING_EVENTS (FAN_ALL_EVENTS |\ - FAN_ALL_PERM_EVENTS |\ - FAN_Q_OVERFLOW) - -#define FANOTIFY_METADATA_VERSION 3 - -struct fanotify_event_metadata { - __u32 event_len; - __u8 vers; - __u8 reserved; - __u16 metadata_len; - __u64 mask; - __s32 fd; - __s32 pid; -}; - -struct fanotify_response { - __s32 fd; - __u32 response; -}; - -/* Legit userspace responses to a _PERM event */ -#define FAN_ALLOW 0x01 -#define FAN_DENY 0x02 -/* No fd set in event */ -#define FAN_NOFD -1 - -/* Helper functions to deal with fanotify_event_metadata buffers */ -#define FAN_EVENT_METADATA_LEN (sizeof(struct fanotify_event_metadata)) - -#define FAN_EVENT_NEXT(meta, len) ((len) -= (meta)->event_len, \ - (struct fanotify_event_metadata*)(((char *)(meta)) + \ - (meta)->event_len)) - -#define FAN_EVENT_OK(meta, len) ((long)(len) >= (long)FAN_EVENT_METADATA_LEN && \ - (long)(meta)->event_len >= (long)FAN_EVENT_METADATA_LEN && \ - (long)(meta)->event_len <= (long)(len)) - -#endif /* _LINUX_FANOTIFY_H */ diff --git a/hal/gonk/nsIRecoveryService.idl b/hal/gonk/nsIRecoveryService.idl deleted file mode 100644 index ecbb39c0e..000000000 --- a/hal/gonk/nsIRecoveryService.idl +++ /dev/null @@ -1,39 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(bc24fb33-a0c1-49ca-aa43-05f167e02fb6)] -interface nsIRecoveryService : nsISupports -{ - /** - * Possible values of fotaStatus.result. These should stay in sync with - * librecovery/librecovery.h - */ - const long FOTA_UPDATE_UNKNOWN = 0; - const long FOTA_UPDATE_FAIL = 1; - const long FOTA_UPDATE_SUCCESS = 2; - - /** - * Uses recovery to wipe the data and cache partitions. If this call is - * successful, the device should reboot before the function call ever returns. - * - * @throws NS_ERROR_FAILURE when rebooting into recovery fails for some reason. - */ - void factoryReset(in string reason); - - /** - * Use recovery to install an OTA update.zip. If this call is - * successful, the device should reboot before the function call ever returns. - * - * @throws NS_ERROR_FAILURE when rebooting into recovery fails for some reason. - */ - void installFotaUpdate(in string updatePath); - - /** - * @return The status of the last FOTA update. One of FOTA_UPDATE_UNKNOWN, - * FOTA_UPDATE_FAIL, FOTA_UPDATE_SUCCESS. - */ - long getFotaUpdateStatus(); -}; diff --git a/hal/gonk/tavarua.h b/hal/gonk/tavarua.h deleted file mode 100644 index 4eb3483a8..000000000 --- a/hal/gonk/tavarua.h +++ /dev/null @@ -1,484 +0,0 @@ -#ifndef __LINUX_TAVARUA_H -#define __LINUX_TAVARUA_H - -/* This is a Linux header generated by "make headers_install" */ - -#include -#include -#include - - -#undef FM_DEBUG - -/* constants */ -#define RDS_BLOCKS_NUM (4) -#define BYTES_PER_BLOCK (3) -#define MAX_PS_LENGTH (96) -#define MAX_RT_LENGTH (64) - -#define XFRDAT0 (0x20) -#define XFRDAT1 (0x21) -#define XFRDAT2 (0x22) - -#define INTDET_PEEK_MSB (0x88) -#define INTDET_PEEK_LSB (0x26) - -#define RMSSI_PEEK_MSB (0x88) -#define RMSSI_PEEK_LSB (0xA8) - -#define MPX_DCC_BYPASS_POKE_MSB (0x88) -#define MPX_DCC_BYPASS_POKE_LSB (0xC0) - -#define MPX_DCC_PEEK_MSB_REG1 (0x88) -#define MPX_DCC_PEEK_LSB_REG1 (0xC2) - -#define MPX_DCC_PEEK_MSB_REG2 (0x88) -#define MPX_DCC_PEEK_LSB_REG2 (0xC3) - -#define MPX_DCC_PEEK_MSB_REG3 (0x88) -#define MPX_DCC_PEEK_LSB_REG3 (0xC4) - -#define ON_CHANNEL_TH_MSB (0x0B) -#define ON_CHANNEL_TH_LSB (0xA8) - -#define OFF_CHANNEL_TH_MSB (0x0B) -#define OFF_CHANNEL_TH_LSB (0xAC) - -#define ENF_200Khz (1) -#define SRCH200KHZ_OFFSET (7) -#define SRCH_MASK (1 << SRCH200KHZ_OFFSET) - -/* Standard buffer size */ -#define STD_BUF_SIZE (128) -/* Search direction */ -#define SRCH_DIR_UP (0) -#define SRCH_DIR_DOWN (1) - -/* control options */ -#define CTRL_ON (1) -#define CTRL_OFF (0) - -#define US_LOW_BAND (87.5) -#define US_HIGH_BAND (108) - -/* constant for Tx */ - -#define MASK_PI (0x0000FFFF) -#define MASK_PI_MSB (0x0000FF00) -#define MASK_PI_LSB (0x000000FF) -#define MASK_PTY (0x0000001F) -#define MASK_TXREPCOUNT (0x0000000F) - -#undef FMDBG -#ifdef FM_DEBUG - #define FMDBG(fmt, args...) printk(KERN_INFO "tavarua_radio: " fmt, ##args) -#else - #define FMDBG(fmt, args...) -#endif - -#undef FMDERR -#define FMDERR(fmt, args...) printk(KERN_INFO "tavarua_radio: " fmt, ##args) - -#undef FMDBG_I2C -#ifdef FM_DEBUG_I2C - #define FMDBG_I2C(fmt, args...) printk(KERN_INFO "fm_i2c: " fmt, ##args) -#else - #define FMDBG_I2C(fmt, args...) -#endif - -/* function declarations */ -/* FM Core audio paths. */ -#define TAVARUA_AUDIO_OUT_ANALOG_OFF (0) -#define TAVARUA_AUDIO_OUT_ANALOG_ON (1) -#define TAVARUA_AUDIO_OUT_DIGITAL_OFF (0) -#define TAVARUA_AUDIO_OUT_DIGITAL_ON (1) - -int tavarua_set_audio_path(int digital_on, int analog_on); - -/* defines and enums*/ - -#define MARIMBA_A0 0x01010013 -#define MARIMBA_2_1 0x02010204 -#define BAHAMA_1_0 0x0302010A -#define BAHAMA_2_0 0x04020205 -#define WAIT_TIMEOUT 2000 -#define RADIO_INIT_TIME 15 -#define TAVARUA_DELAY 10 -/* - * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, - * 62.5 kHz otherwise. - * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. - * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW - * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 - */ -#define FREQ_MUL (1000000 / 62.5) - -enum v4l2_cid_private_tavarua_t { - V4L2_CID_PRIVATE_TAVARUA_SRCHMODE = (V4L2_CID_PRIVATE_BASE + 1), - V4L2_CID_PRIVATE_TAVARUA_SCANDWELL, - V4L2_CID_PRIVATE_TAVARUA_SRCHON, - V4L2_CID_PRIVATE_TAVARUA_STATE, - V4L2_CID_PRIVATE_TAVARUA_TRANSMIT_MODE, - V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_MASK, - V4L2_CID_PRIVATE_TAVARUA_REGION, - V4L2_CID_PRIVATE_TAVARUA_SIGNAL_TH, - V4L2_CID_PRIVATE_TAVARUA_SRCH_PTY, - V4L2_CID_PRIVATE_TAVARUA_SRCH_PI, - V4L2_CID_PRIVATE_TAVARUA_SRCH_CNT, - V4L2_CID_PRIVATE_TAVARUA_EMPHASIS, - V4L2_CID_PRIVATE_TAVARUA_RDS_STD, - V4L2_CID_PRIVATE_TAVARUA_SPACING, - V4L2_CID_PRIVATE_TAVARUA_RDSON, - V4L2_CID_PRIVATE_TAVARUA_RDSGROUP_PROC, - V4L2_CID_PRIVATE_TAVARUA_LP_MODE, - V4L2_CID_PRIVATE_TAVARUA_ANTENNA, - V4L2_CID_PRIVATE_TAVARUA_RDSD_BUF, - V4L2_CID_PRIVATE_TAVARUA_PSALL, - /*v4l2 Tx controls*/ - V4L2_CID_PRIVATE_TAVARUA_TX_SETPSREPEATCOUNT, - V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_PS_NAME, - V4L2_CID_PRIVATE_TAVARUA_STOP_RDS_TX_RT, - V4L2_CID_PRIVATE_TAVARUA_IOVERC, - V4L2_CID_PRIVATE_TAVARUA_INTDET, - V4L2_CID_PRIVATE_TAVARUA_MPX_DCC, - V4L2_CID_PRIVATE_TAVARUA_AF_JUMP, - V4L2_CID_PRIVATE_TAVARUA_RSSI_DELTA, - V4L2_CID_PRIVATE_TAVARUA_HLSI, - - /* - * Here we have IOCTl's that are specific to IRIS - * (V4L2_CID_PRIVATE_BASE + 0x1E to V4L2_CID_PRIVATE_BASE + 0x28) - */ - V4L2_CID_PRIVATE_SOFT_MUTE,/* 0x800001E*/ - V4L2_CID_PRIVATE_RIVA_ACCS_ADDR, - V4L2_CID_PRIVATE_RIVA_ACCS_LEN, - V4L2_CID_PRIVATE_RIVA_PEEK, - V4L2_CID_PRIVATE_RIVA_POKE, - V4L2_CID_PRIVATE_SSBI_ACCS_ADDR, - V4L2_CID_PRIVATE_SSBI_PEEK, - V4L2_CID_PRIVATE_SSBI_POKE, - V4L2_CID_PRIVATE_TX_TONE, - V4L2_CID_PRIVATE_RDS_GRP_COUNTERS, - V4L2_CID_PRIVATE_SET_NOTCH_FILTER,/* 0x8000028 */ - - V4L2_CID_PRIVATE_TAVARUA_SET_AUDIO_PATH,/* 0x8000029 */ - V4L2_CID_PRIVATE_TAVARUA_DO_CALIBRATION,/* 0x800002A : IRIS */ - V4L2_CID_PRIVATE_TAVARUA_SRCH_ALGORITHM,/* 0x800002B */ - V4L2_CID_PRIVATE_IRIS_GET_SINR, /* 0x800002C : IRIS */ - V4L2_CID_PRIVATE_INTF_LOW_THRESHOLD, /* 0x800002D */ - V4L2_CID_PRIVATE_INTF_HIGH_THRESHOLD, /* 0x800002E */ - V4L2_CID_PRIVATE_SINR_THRESHOLD, /* 0x800002F : IRIS */ - V4L2_CID_PRIVATE_SINR_SAMPLES, /* 0x8000030 : IRIS */ - -}; - -enum tavarua_buf_t { - TAVARUA_BUF_SRCH_LIST, - TAVARUA_BUF_EVENTS, - TAVARUA_BUF_RT_RDS, - TAVARUA_BUF_PS_RDS, - TAVARUA_BUF_RAW_RDS, - TAVARUA_BUF_AF_LIST, - TAVARUA_BUF_MAX -}; - -enum tavarua_xfr_t { - TAVARUA_XFR_SYNC, - TAVARUA_XFR_ERROR, - TAVARUA_XFR_SRCH_LIST, - TAVARUA_XFR_RT_RDS, - TAVARUA_XFR_PS_RDS, - TAVARUA_XFR_AF_LIST, - TAVARUA_XFR_MAX -}; - -enum channel_spacing { - FM_CH_SPACE_200KHZ, - FM_CH_SPACE_100KHZ, - FM_CH_SPACE_50KHZ -}; - -enum step_size { - NO_SRCH200khz, - ENF_SRCH200khz -}; - -enum emphasis { - EMP_75, - EMP_50 -}; - -enum rds_std { - RBDS_STD, - RDS_STD -}; - -/* offsets */ -#define RAW_RDS 0x0F -#define RDS_BLOCK 3 - -/* registers*/ -#define MARIMBA_XO_BUFF_CNTRL 0x07 -#define RADIO_REGISTERS 0x30 -#define XFR_REG_NUM 16 -#define STATUS_REG_NUM 3 - -/* TX constants */ -#define HEADER_SIZE 4 -#define TX_ON 0x80 -#define TAVARUA_TX_RT RDS_RT_0 -#define TAVARUA_TX_PS RDS_PS_0 - -enum register_t { - STATUS_REG1 = 0, - STATUS_REG2, - STATUS_REG3, - RDCTRL, - FREQ, - TUNECTRL, - SRCHRDS1, - SRCHRDS2, - SRCHCTRL, - IOCTRL, - RDSCTRL, - ADVCTRL, - AUDIOCTRL, - RMSSI, - IOVERC, - AUDIOIND = 0x1E, - XFRCTRL, - FM_CTL0 = 0xFF, - LEAKAGE_CNTRL = 0xFE, -}; -#define BAHAMA_RBIAS_CTL1 0x07 -#define BAHAMA_FM_MODE_REG 0xFD -#define BAHAMA_FM_CTL1_REG 0xFE -#define BAHAMA_FM_CTL0_REG 0xFF -#define BAHAMA_FM_MODE_NORMAL 0x00 -#define BAHAMA_LDO_DREG_CTL0 0xF0 -#define BAHAMA_LDO_AREG_CTL0 0xF4 - -/* Radio Control */ -#define RDCTRL_STATE_OFFSET 0 -#define RDCTRL_STATE_MASK (3 << RDCTRL_STATE_OFFSET) -#define RDCTRL_BAND_OFFSET 2 -#define RDCTRL_BAND_MASK (1 << RDCTRL_BAND_OFFSET) -#define RDCTRL_CHSPACE_OFFSET 3 -#define RDCTRL_CHSPACE_MASK (3 << RDCTRL_CHSPACE_OFFSET) -#define RDCTRL_DEEMPHASIS_OFFSET 5 -#define RDCTRL_DEEMPHASIS_MASK (1 << RDCTRL_DEEMPHASIS_OFFSET) -#define RDCTRL_HLSI_OFFSET 6 -#define RDCTRL_HLSI_MASK (3 << RDCTRL_HLSI_OFFSET) -#define RDSAF_OFFSET 6 -#define RDSAF_MASK (1 << RDSAF_OFFSET) - -/* Tune Control */ -#define TUNE_STATION 0x01 -#define ADD_OFFSET (1 << 1) -#define SIGSTATE (1 << 5) -#define MOSTSTATE (1 << 6) -#define RDSSYNC (1 << 7) -/* Search Control */ -#define SRCH_MODE_OFFSET 0 -#define SRCH_MODE_MASK (7 << SRCH_MODE_OFFSET) -#define SRCH_DIR_OFFSET 3 -#define SRCH_DIR_MASK (1 << SRCH_DIR_OFFSET) -#define SRCH_DWELL_OFFSET 4 -#define SRCH_DWELL_MASK (7 << SRCH_DWELL_OFFSET) -#define SRCH_STATE_OFFSET 7 -#define SRCH_STATE_MASK (1 << SRCH_STATE_OFFSET) - -/* I/O Control */ -#define IOC_HRD_MUTE 0x03 -#define IOC_SFT_MUTE (1 << 2) -#define IOC_MON_STR (1 << 3) -#define IOC_SIG_BLND (1 << 4) -#define IOC_INTF_BLND (1 << 5) -#define IOC_ANTENNA (1 << 6) -#define IOC_ANTENNA_OFFSET 6 -#define IOC_ANTENNA_MASK (1 << IOC_ANTENNA_OFFSET) - -/* RDS Control */ -#define RDS_ON 0x01 -#define RDSCTRL_STANDARD_OFFSET 1 -#define RDSCTRL_STANDARD_MASK (1 << RDSCTRL_STANDARD_OFFSET) - -/* Advanced features controls */ -#define RDSRTEN (1 << 3) -#define RDSPSEN (1 << 4) - -/* Audio path control */ -#define AUDIORX_ANALOG_OFFSET 0 -#define AUDIORX_ANALOG_MASK (1 << AUDIORX_ANALOG_OFFSET) -#define AUDIORX_DIGITAL_OFFSET 1 -#define AUDIORX_DIGITAL_MASK (1 << AUDIORX_DIGITAL_OFFSET) -#define AUDIOTX_OFFSET 2 -#define AUDIOTX_MASK (1 << AUDIOTX_OFFSET) -#define I2SCTRL_OFFSET 3 -#define I2SCTRL_MASK (1 << I2SCTRL_OFFSET) - -/* Search options */ -enum search_t { - SEEK, - SCAN, - SCAN_FOR_STRONG, - SCAN_FOR_WEAK, - RDS_SEEK_PTY, - RDS_SCAN_PTY, - RDS_SEEK_PI, - RDS_AF_JUMP, -}; - -enum audio_path { - FM_DIGITAL_PATH, - FM_ANALOG_PATH -}; -#define SRCH_MODE 0x07 -#define SRCH_DIR 0x08 /* 0-up 1-down */ -#define SCAN_DWELL 0x70 -#define SRCH_ON 0x80 - -/* RDS CONFIG */ -#define RDS_CONFIG_PSALL 0x01 - -#define FM_ENABLE 0x22 -#define SET_REG_FIELD(reg, val, offset, mask) \ - (reg = (reg & ~mask) | (((val) << offset) & mask)) -#define GET_REG_FIELD(reg, offset, mask) ((reg & mask) >> offset) -#define RSH_DATA(val, offset) ((val) >> (offset)) -#define LSH_DATA(val, offset) ((val) << (offset)) -#define GET_ABS_VAL(val) ((val) & (0xFF)) - -enum radio_state_t { - FM_OFF, - FM_RECV, - FM_TRANS, - FM_RESET, -}; - -#define XFRCTRL_WRITE (1 << 7) - -/* Interrupt status */ - -/* interrupt register 1 */ -#define READY (1 << 0) /* Radio ready after powerup or reset */ -#define TUNE (1 << 1) /* Tune completed */ -#define SEARCH (1 << 2) /* Search completed (read FREQ) */ -#define SCANNEXT (1 << 3) /* Scanning for next station */ -#define SIGNAL (1 << 4) /* Signal indicator change (read SIGSTATE) */ -#define INTF (1 << 5) /* Interference cnt has fallen outside range */ -#define SYNC (1 << 6) /* RDS sync state change (read RDSSYNC) */ -#define AUDIO (1 << 7) /* Audio Control indicator (read AUDIOIND) */ - -/* interrupt register 2 */ -#define RDSDAT (1 << 0) /* New unread RDS data group available */ -#define BLOCKB (1 << 1) /* Block-B match condition exists */ -#define PROGID (1 << 2) /* Block-A or Block-C matched stored PI value*/ -#define RDSPS (1 << 3) /* New RDS Program Service Table available */ -#define RDSRT (1 << 4) /* New RDS Radio Text available */ -#define RDSAF (1 << 5) /* New RDS AF List available */ -#define TXRDSDAT (1 << 6) /* Transmitted an RDS group */ -#define TXRDSDONE (1 << 7) /* RDS raw group one-shot transmit completed */ - -/* interrupt register 3 */ -#define TRANSFER (1 << 0) /* Data transfer (XFR) completed */ -#define RDSPROC (1 << 1) /* Dynamic RDS Processing complete */ -#define ERROR (1 << 7) /* Err occurred.Read code to determine cause */ - - -#define FM_TX_PWR_LVL_0 0 /* Lowest power lvl that can be set for Tx */ -#define FM_TX_PWR_LVL_MAX 7 /* Max power lvl for Tx */ -/* Transfer */ -enum tavarua_xfr_ctrl_t { - RDS_PS_0 = 0x01, - RDS_PS_1, - RDS_PS_2, - RDS_PS_3, - RDS_PS_4, - RDS_PS_5, - RDS_PS_6, - RDS_RT_0, - RDS_RT_1, - RDS_RT_2, - RDS_RT_3, - RDS_RT_4, - RDS_AF_0, - RDS_AF_1, - RDS_CONFIG, - RDS_TX_GROUPS, - RDS_COUNT_0, - RDS_COUNT_1, - RDS_COUNT_2, - RADIO_CONFIG, - RX_CONFIG, - RX_TIMERS, - RX_STATIONS_0, - RX_STATIONS_1, - INT_CTRL, - ERROR_CODE, - CHIPID, - CAL_DAT_0 = 0x20, - CAL_DAT_1, - CAL_DAT_2, - CAL_DAT_3, - CAL_CFG_0, - CAL_CFG_1, - DIG_INTF_0, - DIG_INTF_1, - DIG_AGC_0, - DIG_AGC_1, - DIG_AGC_2, - DIG_AUDIO_0, - DIG_AUDIO_1, - DIG_AUDIO_2, - DIG_AUDIO_3, - DIG_AUDIO_4, - DIG_RXRDS, - DIG_DCC, - DIG_SPUR, - DIG_MPXDCC, - DIG_PILOT, - DIG_DEMOD, - DIG_MOST, - DIG_TX_0, - DIG_TX_1, - PHY_TXGAIN = 0x3B, - PHY_CONFIG, - PHY_TXBLOCK, - PHY_TCB, - XFR_PEEK_MODE = 0x40, - XFR_POKE_MODE = 0xC0, - TAVARUA_XFR_CTRL_MAX -}; - -enum tavarua_evt_t { - TAVARUA_EVT_RADIO_READY, - TAVARUA_EVT_TUNE_SUCC, - TAVARUA_EVT_SEEK_COMPLETE, - TAVARUA_EVT_SCAN_NEXT, - TAVARUA_EVT_NEW_RAW_RDS, - TAVARUA_EVT_NEW_RT_RDS, - TAVARUA_EVT_NEW_PS_RDS, - TAVARUA_EVT_ERROR, - TAVARUA_EVT_BELOW_TH, - TAVARUA_EVT_ABOVE_TH, - TAVARUA_EVT_STEREO, - TAVARUA_EVT_MONO, - TAVARUA_EVT_RDS_AVAIL, - TAVARUA_EVT_RDS_NOT_AVAIL, - TAVARUA_EVT_NEW_SRCH_LIST, - TAVARUA_EVT_NEW_AF_LIST, - TAVARUA_EVT_TXRDSDAT, - TAVARUA_EVT_TXRDSDONE, - TAVARUA_EVT_RADIO_DISABLED -}; - -enum tavarua_region_t { - TAVARUA_REGION_US, - TAVARUA_REGION_EU, - TAVARUA_REGION_JAPAN, - TAVARUA_REGION_JAPAN_WIDE, - TAVARUA_REGION_OTHER -}; - -#endif /* __LINUX_TAVARUA_H */ diff --git a/hal/moz.build b/hal/moz.build index c17379f22..235994273 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -45,24 +45,6 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android': SOURCES += [ 'android/AndroidHal.cpp', ] -elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - UNIFIED_SOURCES += [ - 'gonk/GonkDiskSpaceWatcher.cpp', - 'gonk/GonkSensor.cpp', - 'gonk/GonkSensorsHelpers.cpp', - 'gonk/GonkSensorsInterface.cpp', - 'gonk/GonkSensorsPollInterface.cpp', - 'gonk/GonkSensorsRegistryInterface.cpp', - 'gonk/GonkSwitch.cpp', - 'gonk/SystemService.cpp', - 'gonk/UeventPoller.cpp', - 'linux/LinuxMemory.cpp', - 'linux/LinuxPower.cpp', - ] - # GonkHal.cpp cannot be built in unified mode because it relies on HalImpl.h. - SOURCES += [ - 'gonk/GonkHal.cpp', - ] elif CONFIG['OS_TARGET'] == 'Linux': UNIFIED_SOURCES += [ 'fallback/FallbackAlarm.cpp', @@ -130,19 +112,17 @@ else: 'fallback/FallbackVibration.cpp', ] -# Fallbacks for backends implemented on Gonk only. -if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk': - UNIFIED_SOURCES += [ - 'fallback/FallbackDiskSpaceWatcher.cpp', - 'fallback/FallbackFactoryReset.cpp', - 'fallback/FallbackProcessPriority.cpp', - 'fallback/FallbackScreenPower.cpp', - 'fallback/FallbackSwitch.cpp', - 'fallback/FallbackSystemService.cpp', - 'fallback/FallbackThreadPriority.cpp', - 'fallback/FallbackTime.cpp', - 'fallback/FallbackWakeLocks.cpp', - ] +UNIFIED_SOURCES += [ + 'fallback/FallbackDiskSpaceWatcher.cpp', + 'fallback/FallbackFactoryReset.cpp', + 'fallback/FallbackProcessPriority.cpp', + 'fallback/FallbackScreenPower.cpp', + 'fallback/FallbackSwitch.cpp', + 'fallback/FallbackSystemService.cpp', + 'fallback/FallbackThreadPriority.cpp', + 'fallback/FallbackTime.cpp', + 'fallback/FallbackWakeLocks.cpp', +] # Fallbacks for backends implemented on Android only. if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android': @@ -169,16 +149,6 @@ if CONFIG['MOZ_GAMEPAD']: '/dom/base', ] -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - # So that we can call nsScreenManagerGonk::GetConfiguration(). - LOCAL_INCLUDES += [ - '/widget', - '/widget/gonk', - ] - -if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - LOCAL_INCLUDES += ['%' + '%s/hardware/libhardware_legacy/include' % CONFIG['ANDROID_SOURCE']] - CFLAGS += CONFIG['GLIB_CFLAGS'] CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] CXXFLAGS += CONFIG['GLIB_CFLAGS'] diff --git a/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini b/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini index 2c9dd1dce..66a72ae4d 100644 --- a/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini +++ b/testing/marionette/harness/marionette_harness/tests/webapi-tests.ini @@ -1,4 +1,3 @@ -[include:../../../../../dom/system/gonk/tests/marionette/manifest.ini] [include:../../../../../dom/system/tests/marionette/manifest.ini] skip-if = android_version > '15' # Bug 1203072 [include:../../../../../dom/events/test/marionette/manifest.ini] diff --git a/uriloader/exthandler/gonk/nsOSHelperAppService.cpp b/uriloader/exthandler/gonk/nsOSHelperAppService.cpp deleted file mode 100644 index d1342ec18..000000000 --- a/uriloader/exthandler/gonk/nsOSHelperAppService.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsOSHelperAppService.h" -#include "nsMIMEInfoImpl.h" - -class nsGonkMIMEInfo : public nsMIMEInfoImpl { -public: - nsGonkMIMEInfo(const nsACString& aMIMEType) : nsMIMEInfoImpl(aMIMEType) { } - -protected: - virtual nsresult LoadUriInternal(nsIURI *aURI) { - return NS_ERROR_NOT_IMPLEMENTED; - } -}; - -nsOSHelperAppService::nsOSHelperAppService() : nsExternalHelperAppService() -{ -} - -nsOSHelperAppService::~nsOSHelperAppService() -{ -} - -already_AddRefed -nsOSHelperAppService::GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound) -{ - *aFound = false; - // Even if we return false for aFound, we need to return a working - // nsIMIMEInfo implementation that will be used by the caller. - RefPtr mimeInfo = new nsGonkMIMEInfo(aMIMEType); - return mimeInfo.forget(); -} - -nsresult -nsOSHelperAppService::OSProtocolHandlerExists(const char* aScheme, - bool* aExists) -{ - *aExists = false; - return NS_OK; -} diff --git a/uriloader/exthandler/gonk/nsOSHelperAppService.h b/uriloader/exthandler/gonk/nsOSHelperAppService.h deleted file mode 100644 index 99a280bfc..000000000 --- a/uriloader/exthandler/gonk/nsOSHelperAppService.h +++ /dev/null @@ -1,39 +0,0 @@ -/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsOSHelperAppService_h -#define nsOSHelperAppService_h - -#include "nsCExternalHandlerService.h" -#include "nsExternalHelperAppService.h" - -class nsOSHelperAppService : public nsExternalHelperAppService -{ -public: - nsOSHelperAppService(); - virtual ~nsOSHelperAppService(); - - virtual already_AddRefed - GetMIMEInfoFromOS(const nsACString& aMIMEType, - const nsACString& aFileExt, - bool* aFound); - - virtual MOZ_MUST_USE nsresult - OSProtocolHandlerExists(const char* aScheme, - bool* aExists); -}; - -#endif /* nsOSHelperAppService_h */ diff --git a/uriloader/exthandler/moz.build b/uriloader/exthandler/moz.build index 6a3ca08af..714b275f1 100644 --- a/uriloader/exthandler/moz.build +++ b/uriloader/exthandler/moz.build @@ -24,7 +24,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': LOCAL_INCLUDES += ['win'] elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': osdir = 'mac' -elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk', 'uikit'): +elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'uikit'): osdir = CONFIG['MOZ_WIDGET_TOOLKIT'] else: osdir = 'unix' diff --git a/widget/gonk/GeckoTouchDispatcher.cpp b/widget/gonk/GeckoTouchDispatcher.cpp deleted file mode 100644 index 0b18c91a1..000000000 --- a/widget/gonk/GeckoTouchDispatcher.cpp +++ /dev/null @@ -1,358 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* Copyright 2014 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "FrameMetrics.h" -#include "GeckoProfiler.h" -#include "GeckoTouchDispatcher.h" -#include "InputData.h" -#include "ProfilerMarkers.h" -#include "base/basictypes.h" -#include "gfxPrefs.h" -#include "libui/Input.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/Mutex.h" -#include "mozilla/TimeStamp.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/dom/Touch.h" -#include "mozilla/layers/APZThreadUtils.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "nsAppShell.h" -#include "nsDebug.h" -#include "nsThreadUtils.h" -#include "nsWindow.h" -#include -#include -#include - -#undef LOG -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) - -// uncomment to print log resample data -// #define LOG_RESAMPLE_DATA 1 - -namespace mozilla { - -// Amount of time in MS before an input is considered expired. -static const uint64_t kInputExpirationThresholdMs = 1000; - -static StaticRefPtr sTouchDispatcher; - -/* static */ GeckoTouchDispatcher* -GeckoTouchDispatcher::GetInstance() -{ - if (!sTouchDispatcher) { - sTouchDispatcher = new GeckoTouchDispatcher(); - ClearOnShutdown(&sTouchDispatcher); - } - return sTouchDispatcher; -} - -GeckoTouchDispatcher::GeckoTouchDispatcher() - : mTouchQueueLock("GeckoTouchDispatcher::mTouchQueueLock") - , mHavePendingTouchMoves(false) - , mInflightNonMoveEvents(0) - , mTouchEventsFiltered(false) -{ - // Since GeckoTouchDispatcher is initialized when input is initialized - // and reads gfxPrefs, it is the first thing to touch gfxPrefs. - // The first thing to touch gfxPrefs MUST occur on the main thread and init - // the singleton - MOZ_ASSERT(sTouchDispatcher == nullptr); - MOZ_ASSERT(NS_IsMainThread()); - gfxPrefs::GetSingleton(); - - mEnabledUniformityInfo = gfxPrefs::UniformityInfo(); - mVsyncAdjust = TimeDuration::FromMilliseconds(gfxPrefs::TouchVsyncSampleAdjust()); - mMaxPredict = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMaxPredict()); - mMinDelta = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleMinDelta()); - mOldTouchThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleOldTouchThreshold()); - mDelayedVsyncThreshold = TimeDuration::FromMilliseconds(gfxPrefs::TouchResampleVsyncDelayThreshold()); -} - -void -GeckoTouchDispatcher::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver) -{ - MOZ_ASSERT(NS_IsMainThread()); - // We assume on b2g that there is only 1 CompositorBridgeParent - MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); - mCompositorVsyncScheduler = aObserver; -} - -void -GeckoTouchDispatcher::NotifyVsync(TimeStamp aVsyncTimestamp) -{ - layers::APZThreadUtils::AssertOnControllerThread(); - DispatchTouchMoveEvents(aVsyncTimestamp); -} - -// Touch data timestamps are in milliseconds, aEventTime is in nanoseconds -void -GeckoTouchDispatcher::NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime) -{ - if (mCompositorVsyncScheduler) { - mCompositorVsyncScheduler->SetNeedsComposite(); - } - - if (aTouch.mType == MultiTouchInput::MULTITOUCH_MOVE) { - MutexAutoLock lock(mTouchQueueLock); - if (mInflightNonMoveEvents > 0) { - // If we have any pending non-move events, we shouldn't resample the - // move events because we might end up dispatching events out of order. - // Instead, fall back to a non-resampling in-order dispatch until we're - // done processing the non-move events. - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - this, &GeckoTouchDispatcher::DispatchTouchEvent, aTouch)); - return; - } - - mTouchMoveEvents.push_back(aTouch); - mHavePendingTouchMoves = true; - } else { - { // scope lock - MutexAutoLock lock(mTouchQueueLock); - mInflightNonMoveEvents++; - } - layers::APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - this, &GeckoTouchDispatcher::DispatchTouchNonMoveEvent, aTouch)); - } -} - -void -GeckoTouchDispatcher::DispatchTouchNonMoveEvent(MultiTouchInput aInput) -{ - layers::APZThreadUtils::AssertOnControllerThread(); - - // Flush pending touch move events, if there are any - // (DispatchTouchMoveEvents will check the mHavePendingTouchMoves flag and - // bail out if there's nothing to be done). - NotifyVsync(TimeStamp::Now()); - DispatchTouchEvent(aInput); - - { // scope lock - MutexAutoLock lock(mTouchQueueLock); - mInflightNonMoveEvents--; - MOZ_ASSERT(mInflightNonMoveEvents >= 0); - } -} - -void -GeckoTouchDispatcher::DispatchTouchMoveEvents(TimeStamp aVsyncTime) -{ - MultiTouchInput touchMove; - - { - MutexAutoLock lock(mTouchQueueLock); - if (!mHavePendingTouchMoves) { - return; - } - mHavePendingTouchMoves = false; - - int touchCount = mTouchMoveEvents.size(); - TimeDuration vsyncTouchDiff = aVsyncTime - mTouchMoveEvents.back().mTimeStamp; - // The delay threshold is a positive pref, but we're testing to see if the - // vsync time is delayed from the touch, so add a negative sign. - bool isDelayedVsyncEvent = vsyncTouchDiff < -mDelayedVsyncThreshold; - bool isOldTouch = vsyncTouchDiff > mOldTouchThreshold; - bool resample = (touchCount > 1) && !isDelayedVsyncEvent && !isOldTouch; - - if (!resample) { - touchMove = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - if (!isDelayedVsyncEvent && !isOldTouch) { - mTouchMoveEvents.push_back(touchMove); - } - } else { - ResampleTouchMoves(touchMove, aVsyncTime); - } - } - - DispatchTouchEvent(touchMove); -} - -static int -Interpolate(int start, int end, TimeDuration aFrameDiff, TimeDuration aTouchDiff) -{ - return start + (((end - start) * aFrameDiff.ToMicroseconds()) / aTouchDiff.ToMicroseconds()); -} - -static const SingleTouchData& -GetTouchByID(const SingleTouchData& aCurrentTouch, MultiTouchInput& aOtherTouch) -{ - int32_t index = aOtherTouch.IndexOfTouch(aCurrentTouch.mIdentifier); - if (index < 0) { - // We can have situations where a previous touch event had 2 fingers - // and we lift 1 finger off. In those cases, we won't find the touch event - // with given id, so just return the current touch, which will be resampled - // without modification and dispatched. - return aCurrentTouch; - } - return aOtherTouch.mTouches[index]; -} - - -// aTouchDiff is the duration between the base and current touch times -// aFrameDiff is the duration between the base and the time we're resampling to -static void -ResampleTouch(MultiTouchInput& aOutTouch, - MultiTouchInput& aBase, MultiTouchInput& aCurrent, - TimeDuration aFrameDiff, TimeDuration aTouchDiff) -{ - aOutTouch = aCurrent; - - // Make sure we only resample the correct finger. - for (size_t i = 0; i < aOutTouch.mTouches.Length(); i++) { - const SingleTouchData& current = aCurrent.mTouches[i]; - const SingleTouchData& base = GetTouchByID(current, aBase); - - const ScreenIntPoint& baseTouchPoint = base.mScreenPoint; - const ScreenIntPoint& currentTouchPoint = current.mScreenPoint; - - ScreenIntPoint newSamplePoint; - newSamplePoint.x = Interpolate(baseTouchPoint.x, currentTouchPoint.x, aFrameDiff, aTouchDiff); - newSamplePoint.y = Interpolate(baseTouchPoint.y, currentTouchPoint.y, aFrameDiff, aTouchDiff); - - aOutTouch.mTouches[i].mScreenPoint = newSamplePoint; - -#ifdef LOG_RESAMPLE_DATA - const char* type = "extrapolate"; - if (aFrameDiff < aTouchDiff) { - type = "interpolate"; - } - - float alpha = aFrameDiff / aTouchDiff; - LOG("%s base (%d, %d), current (%d, %d) to (%d, %d) alpha %f, touch diff %d, frame diff %d\n", - type, - baseTouchPoint.x, baseTouchPoint.y, - currentTouchPoint.x, currentTouchPoint.y, - newSamplePoint.x, newSamplePoint.y, - alpha, (int)aTouchDiff.ToMilliseconds(), (int)aFrameDiff.ToMilliseconds()); -#endif - } -} - -/* - * +> Base touch (The touch before current touch) - * | - * | +> Current touch (Latest touch) - * | | - * | | +> Maximum resample time - * | | | - * +-----+------+--------------------> Time - * ^ ^ - * | | - * +------+--> Potential vsync events which the touches are resampled to - * | | - * | +> Extrapolation - * | - * +> Interpolation - */ - -void -GeckoTouchDispatcher::ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp aVsyncTime) -{ - MOZ_RELEASE_ASSERT(mTouchMoveEvents.size() >= 2); - mTouchQueueLock.AssertCurrentThreadOwns(); - - MultiTouchInput currentTouch = mTouchMoveEvents.back(); - mTouchMoveEvents.pop_back(); - MultiTouchInput baseTouch = mTouchMoveEvents.back(); - mTouchMoveEvents.clear(); - mTouchMoveEvents.push_back(currentTouch); - - TimeStamp sampleTime = aVsyncTime - mVsyncAdjust; - TimeDuration touchDiff = currentTouch.mTimeStamp - baseTouch.mTimeStamp; - - if (touchDiff < mMinDelta) { - aOutTouch = currentTouch; - #ifdef LOG_RESAMPLE_DATA - LOG("The touches are too close, skip resampling\n"); - #endif - return; - } - - if (currentTouch.mTimeStamp < sampleTime) { - TimeDuration maxResampleTime = std::min(touchDiff / int64_t(2), mMaxPredict); - TimeStamp maxTimestamp = currentTouch.mTimeStamp + maxResampleTime; - if (sampleTime > maxTimestamp) { - sampleTime = maxTimestamp; - #ifdef LOG_RESAMPLE_DATA - LOG("Overshot extrapolation time, adjusting sample time\n"); - #endif - } - } - - ResampleTouch(aOutTouch, baseTouch, currentTouch, sampleTime - baseTouch.mTimeStamp, touchDiff); - - // Both mTimeStamp and mTime are being updated to sampleTime here. - // mTime needs to be updated using a delta since TimeStamp doesn't - // provide a way to obtain a raw value. - aOutTouch.mTime += (sampleTime - aOutTouch.mTimeStamp).ToMilliseconds(); - aOutTouch.mTimeStamp = sampleTime; -} - -static bool -IsExpired(const MultiTouchInput& aTouch) -{ - // No pending events, the filter state can be updated. - uint64_t timeNowMs = systemTime(SYSTEM_TIME_MONOTONIC) / 1000000; - return (timeNowMs - aTouch.mTime) > kInputExpirationThresholdMs; -} -void -GeckoTouchDispatcher::DispatchTouchEvent(MultiTouchInput aMultiTouch) -{ - if ((aMultiTouch.mType == MultiTouchInput::MULTITOUCH_END || - aMultiTouch.mType == MultiTouchInput::MULTITOUCH_CANCEL) && - aMultiTouch.mTouches.Length() == 1) { - MutexAutoLock lock(mTouchQueueLock); - mTouchMoveEvents.clear(); - } else if (aMultiTouch.mType == MultiTouchInput::MULTITOUCH_START && - aMultiTouch.mTouches.Length() == 1) { - mTouchEventsFiltered = IsExpired(aMultiTouch); - } - - if (mTouchEventsFiltered) { - return; - } - - nsWindow::DispatchTouchInput(aMultiTouch); - - if (mEnabledUniformityInfo && profiler_is_active()) { - const char* touchAction = "Invalid"; - switch (aMultiTouch.mType) { - case MultiTouchInput::MULTITOUCH_START: - touchAction = "Touch_Event_Down"; - break; - case MultiTouchInput::MULTITOUCH_MOVE: - touchAction = "Touch_Event_Move"; - break; - case MultiTouchInput::MULTITOUCH_END: - case MultiTouchInput::MULTITOUCH_CANCEL: - touchAction = "Touch_Event_Up"; - break; - case MultiTouchInput::MULTITOUCH_SENTINEL: - MOZ_ASSERT_UNREACHABLE("Invalid MultTouchInput."); - break; - } - - const ScreenIntPoint& touchPoint = aMultiTouch.mTouches[0].mScreenPoint; - TouchDataPayload* payload = new TouchDataPayload(touchPoint); - PROFILER_MARKER_PAYLOAD(touchAction, payload); - } -} - -} // namespace mozilla diff --git a/widget/gonk/GeckoTouchDispatcher.h b/widget/gonk/GeckoTouchDispatcher.h deleted file mode 100644 index 3c7acd0e3..000000000 --- a/widget/gonk/GeckoTouchDispatcher.h +++ /dev/null @@ -1,99 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 sts=2 et sw=2 tw=80: */ -/* Copyright 2014 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GECKO_TOUCH_INPUT_DISPATCHER_h -#define GECKO_TOUCH_INPUT_DISPATCHER_h - -#include "InputData.h" -#include "Units.h" -#include "mozilla/Mutex.h" -#include -#include "mozilla/RefPtr.h" - -class nsIWidget; - -namespace mozilla { -namespace layers { -class CompositorVsyncScheduler; -} - -// Used to resample touch events whenever a vsync event occurs. It batches -// touch moves and on every vsync, resamples the touch position to create smooth -// scrolls. We use the Android touch resample algorithm. It uses a combination of -// extrapolation and interpolation. The algorithm takes the vsync time and -// subtracts mVsyncAdjust time in ms and creates a sample time. All touch events are -// relative to this sample time. If the last touch event occurs AFTER this -// sample time, interpolate the last two touch events. If the last touch event occurs BEFORE -// this sample time, we extrapolate the last two touch events to the sample -// time. The magic numbers defined as constants are taken from android -// InputTransport.cpp. -class GeckoTouchDispatcher final -{ - NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GeckoTouchDispatcher) - -public: - static GeckoTouchDispatcher* GetInstance(); - void NotifyTouch(MultiTouchInput& aTouch, TimeStamp aEventTime); - void DispatchTouchEvent(MultiTouchInput aMultiTouch); - void DispatchTouchNonMoveEvent(MultiTouchInput aInput); - void DispatchTouchMoveEvents(TimeStamp aVsyncTime); - void NotifyVsync(TimeStamp aVsyncTimestamp); - void SetCompositorVsyncScheduler(layers::CompositorVsyncScheduler* aObserver); - -protected: - ~GeckoTouchDispatcher() {} - -private: - GeckoTouchDispatcher(); - void ResampleTouchMoves(MultiTouchInput& aOutTouch, TimeStamp vsyncTime); - void SendTouchEvent(MultiTouchInput& aData); - void DispatchMouseEvent(MultiTouchInput& aMultiTouch, - bool aForwardToChildren); - - // mTouchQueueLock is used to protect the vector and state below - // as it is accessed on multiple threads. - Mutex mTouchQueueLock; - std::vector mTouchMoveEvents; - bool mHavePendingTouchMoves; - int mInflightNonMoveEvents; - // end stuff protected by mTouchQueueLock - - bool mResamplingEnabled; - bool mTouchEventsFiltered; - bool mEnabledUniformityInfo; - - // All times below are in nanoseconds - TimeDuration mVsyncAdjust; // Time from vsync we create sample times from - TimeDuration mMaxPredict; // How far into the future we're allowed to extrapolate - TimeDuration mMinDelta; // Minimal time difference between touches for resampling - - // Amount of time between vsync and the last event that is required before we - // resample - TimeDuration mMinResampleTime; - - // Threshold if a vsync event runs too far behind touch events - TimeDuration mDelayedVsyncThreshold; - - // How far ahead can vsync events get ahead of touch events. - TimeDuration mOldTouchThreshold; - - RefPtr mCompositorVsyncScheduler; -}; - -} // namespace mozilla - -#endif // GECKO_TOUCH_INPUT_DISPATCHER_h diff --git a/widget/gonk/GfxInfo.cpp b/widget/gonk/GfxInfo.cpp deleted file mode 100644 index 7ddd39038..000000000 --- a/widget/gonk/GfxInfo.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GfxInfo.h" - -using namespace mozilla::widget; - -/* GetD2DEnabled and GetDwriteEnabled shouldn't be called until after gfxPlatform initialization - * has occurred because they depend on it for information. (See bug 591561) */ -nsresult -GfxInfo::GetD2DEnabled(bool *aEnabled) -{ - return NS_ERROR_FAILURE; -} - -nsresult -GfxInfo::GetDWriteEnabled(bool *aEnabled) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription) -{ - aAdapterDescription.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM) -{ - aAdapterRAM.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver) -{ - aAdapterDriver.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion) -{ - aAdapterDriverVersion.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate) -{ - aAdapterDriverDate.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID) -{ - aAdapterVendorID.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID) -{ - aAdapterDeviceID.Truncate(); - return NS_OK; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID) -{ - return NS_ERROR_FAILURE; -} - -NS_IMETHODIMP -GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active) -{ - return NS_ERROR_FAILURE; -} - -const nsTArray& -GfxInfo::GetGfxDriverInfo() -{ - return *mDriverInfo; -} - -uint32_t GfxInfo::OperatingSystemVersion() -{ - return 0; -} - -nsresult -GfxInfo::GetFeatureStatusImpl(int32_t /*aFeature*/, - int32_t *aStatus, - nsAString & /*aSuggestedDriverVersion*/, - const nsTArray& /*aDriverInfo*/, - nsACString& aFailureId, - OperatingSystem* /*aOS*/ /* = nullptr */) -{ - NS_ENSURE_ARG_POINTER(aStatus); - *aStatus = nsIGfxInfo::FEATURE_STATUS_OK; - - return NS_OK; -} - -#ifdef DEBUG - -// Implement nsIGfxInfoDebug - -NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString &) -{ - return NS_OK; -} - -NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString &) -{ - return NS_OK; -} - -NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString &) -{ - return NS_OK; -} - -NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t) -{ - return NS_OK; -} - -#endif diff --git a/widget/gonk/GfxInfo.h b/widget/gonk/GfxInfo.h deleted file mode 100644 index 61494713f..000000000 --- a/widget/gonk/GfxInfo.h +++ /dev/null @@ -1,69 +0,0 @@ -/* vim: se cin sw=2 ts=2 et : */ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef __mozilla_widget_GfxInfo_h__ -#define __mozilla_widget_GfxInfo_h__ - -#include "GfxInfoBase.h" -#include "GfxDriverInfo.h" - -#include "nsString.h" - -namespace mozilla { -namespace widget { - -class GfxInfo : public GfxInfoBase -{ -public: - // We only declare the subset of nsIGfxInfo that we actually implement. The - // rest is brought forward from GfxInfoBase. - NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled); - NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled); - NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion); - NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams); - NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription); - NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver); - NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID); - NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID); - NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID); - NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM); - NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion); - NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate); - NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription); - NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver); - NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID); - NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID); - NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID); - NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM); - NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion); - NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate); - NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active); - using GfxInfoBase::GetFeatureStatus; - using GfxInfoBase::GetFeatureSuggestedDriverVersion; - using GfxInfoBase::GetWebGLParameter; - - virtual uint32_t OperatingSystemVersion() override; - -#ifdef DEBUG - NS_DECL_NSIGFXINFODEBUG -#endif - -protected: - - virtual nsresult GetFeatureStatusImpl(int32_t aFeature, - int32_t *aStatus, - nsAString & aSuggestedDriverVersion, - const nsTArray& aDriverInfo, - nsACString& aFailureId, - OperatingSystem* aOS = nullptr); - virtual const nsTArray& GetGfxDriverInfo(); -}; - -} // namespace widget -} // namespace mozilla - -#endif /* __mozilla_widget_GfxInfo_h__ */ diff --git a/widget/gonk/GonkClipboardData.cpp b/widget/gonk/GonkClipboardData.cpp deleted file mode 100644 index ced6422a5..000000000 --- a/widget/gonk/GonkClipboardData.cpp +++ /dev/null @@ -1,75 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "GonkClipboardData.h" -#include "mozilla/gfx/DataSurfaceHelpers.h" - -namespace mozilla { - -void -GonkClipboardData::SetText(const nsAString &aText) -{ - mPlain = aText; -} - -bool -GonkClipboardData::HasText() const -{ - return !mPlain.IsEmpty(); -} - -const nsAString& -GonkClipboardData::GetText() const -{ - return mPlain; -} - -void -GonkClipboardData::SetHTML(const nsAString &aHTML) -{ - mHTML = aHTML; -} - -bool -GonkClipboardData::HasHTML() const -{ - return !mHTML.IsEmpty(); -} - -const nsAString& -GonkClipboardData::GetHTML() const -{ - return mHTML; -} - -void -GonkClipboardData::SetImage(gfx::DataSourceSurface* aDataSource) -{ - // Clone a new DataSourceSurface and store it. - mImage = gfx::CreateDataSourceSurfaceByCloning(aDataSource); -} - -bool -GonkClipboardData::HasImage() const -{ - return static_cast(mImage); -} - -already_AddRefed -GonkClipboardData::GetImage() const -{ - // Return cloned DataSourceSurface. - RefPtr cloned = gfx::CreateDataSourceSurfaceByCloning(mImage); - return cloned.forget(); -} - -void -GonkClipboardData::Clear() -{ - mPlain.Truncate(0); - mHTML.Truncate(0); - mImage = nullptr; -} - -} // namespace mozilla diff --git a/widget/gonk/GonkClipboardData.h b/widget/gonk/GonkClipboardData.h deleted file mode 100644 index 8bc1f1c9c..000000000 --- a/widget/gonk/GonkClipboardData.h +++ /dev/null @@ -1,49 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_GonkClipboardData -#define mozilla_GonkClipboardData - -#include "mozilla/RefPtr.h" -#include "nsString.h" - -namespace mozilla { - -namespace gfx { -class DataSourceSurface; -} - -class GonkClipboardData final -{ -public: - explicit GonkClipboardData() = default; - ~GonkClipboardData() = default; - - // For text/plain - void SetText(const nsAString &aText); - bool HasText() const; - const nsAString& GetText() const; - - // For text/html - void SetHTML(const nsAString &aHTML); - bool HasHTML() const; - const nsAString& GetHTML() const; - - // For images - void SetImage(gfx::DataSourceSurface* aDataSource); - bool HasImage() const; - already_AddRefed GetImage() const; - - // For other APIs - void Clear(); - -private: - nsAutoString mPlain; - nsAutoString mHTML; - RefPtr mImage; -}; - -} // namespace mozilla - -#endif // mozilla_GonkClipboardData diff --git a/widget/gonk/GonkKeyMapping.h b/widget/gonk/GonkKeyMapping.h deleted file mode 100644 index d5d4e7a0b..000000000 --- a/widget/gonk/GonkKeyMapping.h +++ /dev/null @@ -1,301 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GONKKEYMAPPING_H -#define GONKKEYMAPPING_H - -#include "libui/android_keycodes.h" -#include "mozilla/EventForwards.h" - -namespace mozilla { -namespace widget { - -/* See libui/KeycodeLabels.h for the mapping */ -static const unsigned long kKeyMapping[] = { - 0, - 0, // SOFT_LEFT - 0, // SOFT_RIGHT - NS_VK_HOME, // HOME - NS_VK_ESCAPE, // BACK - 0, // CALL - NS_VK_SLEEP, // ENDCALL - NS_VK_0, - NS_VK_1, - NS_VK_2, - NS_VK_3, - NS_VK_4, - NS_VK_5, - NS_VK_6, - NS_VK_7, - NS_VK_8, - NS_VK_9, - NS_VK_ASTERISK, - NS_VK_HASH, - NS_VK_UP, - NS_VK_DOWN, - NS_VK_LEFT, - NS_VK_RIGHT, - NS_VK_RETURN, - NS_VK_VOLUME_UP, - NS_VK_VOLUME_DOWN, - NS_VK_SLEEP, // POWER - NS_VK_PRINTSCREEN, // CAMERA - NS_VK_CLEAR, - NS_VK_A, - NS_VK_B, - NS_VK_C, - NS_VK_D, - NS_VK_E, - NS_VK_F, - NS_VK_G, - NS_VK_H, - NS_VK_I, - NS_VK_J, - NS_VK_K, - NS_VK_L, - NS_VK_M, - NS_VK_N, - NS_VK_O, - NS_VK_P, - NS_VK_Q, - NS_VK_R, - NS_VK_S, - NS_VK_T, - NS_VK_U, - NS_VK_V, - NS_VK_W, - NS_VK_X, - NS_VK_Y, - NS_VK_Z, - NS_VK_COMMA, - NS_VK_PERIOD, - 0, - 0, - 0, - 0, - NS_VK_TAB, - NS_VK_SPACE, - NS_VK_META, // SYM - 0, // EXPLORER - 0, // ENVELOPE - NS_VK_RETURN, // ENTER - NS_VK_BACK, - NS_VK_BACK_QUOTE, // GRAVE - NS_VK_HYPHEN_MINUS, - NS_VK_EQUALS, - NS_VK_OPEN_BRACKET, - NS_VK_CLOSE_BRACKET, - NS_VK_BACK_SLASH, - NS_VK_SEMICOLON, - NS_VK_QUOTE, - NS_VK_SLASH, - NS_VK_AT, - 0, // NUM - NS_VK_F1, // HEADSETHOOK - 0, // FOCUS - NS_VK_PLUS, - NS_VK_CONTEXT_MENU, - 0, // NOTIFICATION - NS_VK_F5, // SEARCH - 0, // MEDIA_PLAY_PAUSE - 0, // MEDIA_STOP - 0, // MEDIA_NEXT - 0, // MEDIA_PREVIOUS - 0, // MEDIA_REWIND - 0, // MEDIA_FAST_FORWARD - 0, // MUTE - NS_VK_PAGE_UP, - NS_VK_PAGE_DOWN, - 0, // PICTSYMBOLS - 0, // SWITCH_CHARSET - 0, // BUTTON_A - 0, // BUTTON_B - 0, // BUTTON_C - 0, // BUTTON_X - 0, // BUTTON_Y - 0, // BUTTON_Z - 0, // BUTTON_L1 - 0, // BUTTON_R1 - 0, // BUTTON_L2 - 0, // BUTTON_R2 - 0, // BUTTON_THUMBL - 0, // BUTTON_THUMBR - 0, // BUTTON_START - 0, // BUTTON_SELECT - 0, // BUTTON_MODE - NS_VK_ESCAPE, - NS_VK_DELETE, - 0, // CTRL_LEFT - 0, // CTRL_RIGHT - NS_VK_CAPS_LOCK, - NS_VK_SCROLL_LOCK, - 0, // META_LEFT - 0, // META_RIGHT - 0, // FUNCTION - 0, // SYSRQ - 0, // BREAK - NS_VK_HOME, // MOVE_HOME - NS_VK_END, - NS_VK_INSERT, - 0, // FORWARD - 0, // MEDIA_PLAY - 0, // MEDIA_PAUSE - 0, // MEDIA_CLOSE - 0, // MEDIA_EJECT - 0, // MEDIA_RECORD - NS_VK_F1, - NS_VK_F2, - NS_VK_F3, - NS_VK_F4, - NS_VK_F5, - NS_VK_F6, - NS_VK_F7, - NS_VK_F8, - NS_VK_F9, - NS_VK_F10, - NS_VK_F11, - NS_VK_F12, - NS_VK_NUM_LOCK, - NS_VK_NUMPAD0, - NS_VK_NUMPAD1, - NS_VK_NUMPAD2, - NS_VK_NUMPAD3, - NS_VK_NUMPAD4, - NS_VK_NUMPAD5, - NS_VK_NUMPAD6, - NS_VK_NUMPAD7, - NS_VK_NUMPAD8, - NS_VK_NUMPAD9, - NS_VK_DIVIDE, - NS_VK_MULTIPLY, - NS_VK_SUBTRACT, - NS_VK_ADD, - NS_VK_PERIOD, - NS_VK_COMMA, - NS_VK_RETURN, - NS_VK_EQUALS, - 0, // NUMPAD_LEFT_PAREN - 0, // NUMPAD_RIGHT_PAREN - NS_VK_VOLUME_MUTE, - // There are more but we don't map them -}; - -static KeyNameIndex GetKeyNameIndex(int aKeyCode) -{ - switch (aKeyCode) { -#define NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX(aNativeKey, aKeyNameIndex) \ - case aNativeKey: return aKeyNameIndex; - -#include "NativeKeyToDOMKeyName.h" - -#undef NS_NATIVE_KEY_TO_DOM_KEY_NAME_INDEX - - case AKEYCODE_0: - case AKEYCODE_1: - case AKEYCODE_2: - case AKEYCODE_3: - case AKEYCODE_4: - case AKEYCODE_5: - case AKEYCODE_6: - case AKEYCODE_7: - case AKEYCODE_8: - case AKEYCODE_9: - case AKEYCODE_STAR: - case AKEYCODE_POUND: - case AKEYCODE_A: - case AKEYCODE_B: - case AKEYCODE_C: - case AKEYCODE_D: - case AKEYCODE_E: - case AKEYCODE_F: - case AKEYCODE_G: - case AKEYCODE_H: - case AKEYCODE_I: - case AKEYCODE_J: - case AKEYCODE_K: - case AKEYCODE_L: - case AKEYCODE_M: - case AKEYCODE_N: - case AKEYCODE_O: - case AKEYCODE_P: - case AKEYCODE_Q: - case AKEYCODE_R: - case AKEYCODE_S: - case AKEYCODE_T: - case AKEYCODE_U: - case AKEYCODE_V: - case AKEYCODE_W: - case AKEYCODE_X: - case AKEYCODE_Y: - case AKEYCODE_Z: - case AKEYCODE_COMMA: - case AKEYCODE_PERIOD: - case AKEYCODE_SPACE: - case AKEYCODE_GRAVE: - case AKEYCODE_MINUS: - case AKEYCODE_EQUALS: - case AKEYCODE_LEFT_BRACKET: - case AKEYCODE_RIGHT_BRACKET: - case AKEYCODE_BACKSLASH: - case AKEYCODE_SEMICOLON: - case AKEYCODE_APOSTROPHE: - case AKEYCODE_SLASH: - case AKEYCODE_AT: - case AKEYCODE_PLUS: - case AKEYCODE_NUMPAD_0: - case AKEYCODE_NUMPAD_1: - case AKEYCODE_NUMPAD_2: - case AKEYCODE_NUMPAD_3: - case AKEYCODE_NUMPAD_4: - case AKEYCODE_NUMPAD_5: - case AKEYCODE_NUMPAD_6: - case AKEYCODE_NUMPAD_7: - case AKEYCODE_NUMPAD_8: - case AKEYCODE_NUMPAD_9: - case AKEYCODE_NUMPAD_DIVIDE: - case AKEYCODE_NUMPAD_MULTIPLY: - case AKEYCODE_NUMPAD_SUBTRACT: - case AKEYCODE_NUMPAD_ADD: - case AKEYCODE_NUMPAD_DOT: - case AKEYCODE_NUMPAD_COMMA: - case AKEYCODE_NUMPAD_EQUALS: - case AKEYCODE_NUMPAD_LEFT_PAREN: - case AKEYCODE_NUMPAD_RIGHT_PAREN: - return KEY_NAME_INDEX_USE_STRING; - - default: - return KEY_NAME_INDEX_Unidentified; - } -} - -static CodeNameIndex GetCodeNameIndex(int aScanCode) -{ - switch (aScanCode) { -#define NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX(aNativeKey, aCodeNameIndex) \ - case aNativeKey: return aCodeNameIndex; - -#include "NativeKeyToDOMCodeName.h" - -#undef NS_NATIVE_KEY_TO_DOM_CODE_NAME_INDEX - - default: - return CODE_NAME_INDEX_UNKNOWN; - } -} - -} // namespace widget -} // namespace mozilla - -#endif /* GONKKEYMAPPING_H */ diff --git a/widget/gonk/GonkMemoryPressureMonitoring.cpp b/widget/gonk/GonkMemoryPressureMonitoring.cpp deleted file mode 100644 index 0fafb37cf..000000000 --- a/widget/gonk/GonkMemoryPressureMonitoring.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include -#include -#include -#include -#include - -#include "GonkMemoryPressureMonitoring.h" -#include "mozilla/ArrayUtils.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Monitor.h" -#include "mozilla/Preferences.h" -#include "mozilla/ProcessPriorityManager.h" -#include "mozilla/Services.h" -#include "nsIObserver.h" -#include "nsIObserverService.h" -#include "nsMemoryPressure.h" -#include "nsPrintfCString.h" -#include "nsThreadUtils.h" - -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "GonkMemoryPressure" , ## args) - -using namespace mozilla; - -namespace { - -/** - * MemoryPressureWatcher watches sysfs from its own thread to notice when the - * system is under memory pressure. When we observe memory pressure, we use - * MemoryPressureRunnable to notify observers that they should release memory. - * - * When the system is under memory pressure, we don't want to constantly fire - * memory-pressure events. So instead, we try to detect when sysfs indicates - * that we're no longer under memory pressure, and only then start firing events - * again. - * - * (This is a bit problematic because we can't poll() to detect when we're no - * longer under memory pressure; instead we have to periodically read the sysfs - * node. If we remain under memory pressure for a long time, this means we'll - * continue waking up to read from the node for a long time, potentially wasting - * battery life. Hopefully we don't hit this case in practice! We write to - * logcat each time we go around this loop so it's at least noticable.) - * - * Shutting down safely is a bit of a chore. XPCOM won't shut down until all - * threads exit, so we need to exit the Run() method below on shutdown. But our - * thread might be blocked in one of two situations: We might be poll()'ing the - * sysfs node waiting for memory pressure to occur, or we might be asleep - * waiting to read() the sysfs node to see if we're no longer under memory - * pressure. - * - * To let us wake up from the poll(), we poll() not just the sysfs node but also - * a pipe, which we write to on shutdown. To let us wake up from sleeping - * between read()s, we sleep by Wait()'ing on a monitor, which we notify on - * shutdown. - */ -class MemoryPressureWatcher final - : public nsIRunnable - , public nsIObserver -{ -public: - MemoryPressureWatcher() - : mMonitor("MemoryPressureWatcher") - , mLowMemTriggerKB(0) - , mPageSize(0) - , mShuttingDown(false) - , mTriggerFd(-1) - , mShutdownPipeRead(-1) - , mShutdownPipeWrite(-1) - { - } - - NS_DECL_THREADSAFE_ISUPPORTS - - nsresult Init() - { - nsCOMPtr os = services::GetObserverService(); - NS_ENSURE_STATE(os); - - // The observer service holds us alive. - os->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, /* ownsWeak */ false); - - // Initialize the internal state - mPageSize = sysconf(_SC_PAGESIZE); - ReadPrefs(); - nsresult rv = OpenFiles(); - NS_ENSURE_SUCCESS(rv, rv); - SetLowMemTrigger(mSoftLowMemTriggerKB); - - return NS_OK; - } - - NS_IMETHOD Observe(nsISupports* aSubject, const char* aTopic, - const char16_t* aData) - { - MOZ_ASSERT(strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0); - LOG("Observed XPCOM shutdown."); - - MonitorAutoLock lock(mMonitor); - mShuttingDown = true; - mMonitor.Notify(); - - int rv; - do { - // Write something to the pipe; doesn't matter what. - uint32_t dummy = 0; - rv = write(mShutdownPipeWrite, &dummy, sizeof(dummy)); - } while(rv == -1 && errno == EINTR); - - return NS_OK; - } - - NS_IMETHOD Run() override - { - MOZ_ASSERT(!NS_IsMainThread()); - - int triggerResetTimeout = -1; - bool memoryPressure; - nsresult rv = CheckForMemoryPressure(&memoryPressure); - NS_ENSURE_SUCCESS(rv, rv); - - while (true) { - // Wait for a notification on mTriggerFd or for data to be written to - // mShutdownPipeWrite. (poll(mTriggerFd, POLLPRI) blocks until we're - // under memory pressure or until we time out, the time out is used - // to adjust the trigger level after a memory pressure event.) - struct pollfd pollfds[2]; - pollfds[0].fd = mTriggerFd; - pollfds[0].events = POLLPRI; - pollfds[1].fd = mShutdownPipeRead; - pollfds[1].events = POLLIN; - - int pollRv = MOZ_TEMP_FAILURE_RETRY( - poll(pollfds, ArrayLength(pollfds), triggerResetTimeout) - ); - - if (pollRv == 0) { - // Timed out, adjust the trigger and update the timeout. - triggerResetTimeout = AdjustTrigger(triggerResetTimeout); - continue; - } - - if (pollfds[1].revents) { - // Something was written to our shutdown pipe; we're outta here. - LOG("shutting down (1)"); - return NS_OK; - } - - // If pollfds[1] isn't happening, pollfds[0] ought to be! - if (!(pollfds[0].revents & POLLPRI)) { - LOG("Unexpected revents value after poll(): %d. " - "Shutting down GonkMemoryPressureMonitoring.", pollfds[0].revents); - return NS_ERROR_FAILURE; - } - - // POLLPRI on mTriggerFd indicates that we're in a low-memory situation. - // We could read lowMemFd to double-check, but we've observed that the - // read sometimes completes after the memory-pressure event is over, so - // let's just believe the result of poll(). - rv = DispatchMemoryPressure(MemPressure_New); - NS_ENSURE_SUCCESS(rv, rv); - - // Move to the hard level if we're on the soft one. - if (mLowMemTriggerKB > mHardLowMemTriggerKB) { - SetLowMemTrigger(mHardLowMemTriggerKB); - } - - // Manually check mTriggerFd until we observe that memory pressure is - // over. We won't fire any more low-memory events until we observe that - // we're no longer under pressure. Instead, we fire low-memory-ongoing - // events, which cause processes to keep flushing caches but will not - // trigger expensive GCs and other attempts to save memory that are - // likely futile at this point. - do { - { - MonitorAutoLock lock(mMonitor); - - // We need to check mShuttingDown before we wait here, in order to - // catch a shutdown signal sent after we poll()'ed mShutdownPipeRead - // above but before we started waiting on the monitor. But we don't - // need to check after we wait, because we'll either do another - // iteration of this inner loop, in which case we'll check - // mShuttingDown, or we'll exit this loop and do another iteration - // of the outer loop, in which case we'll check the shutdown pipe. - if (mShuttingDown) { - LOG("shutting down (2)"); - return NS_OK; - } - mMonitor.Wait(PR_MillisecondsToInterval(mPollMS)); - } - - LOG("Checking to see if memory pressure is over."); - rv = CheckForMemoryPressure(&memoryPressure); - NS_ENSURE_SUCCESS(rv, rv); - - if (memoryPressure) { - rv = DispatchMemoryPressure(MemPressure_Ongoing); - NS_ENSURE_SUCCESS(rv, rv); - continue; - } - } while (false); - - if (XRE_IsParentProcess()) { - // The main process will try to adjust the trigger. - triggerResetTimeout = mPollMS * 2; - } - - LOG("Memory pressure is over."); - } - - return NS_OK; - } - -protected: - ~MemoryPressureWatcher() {} - -private: - void ReadPrefs() { - // While we're under memory pressure, we periodically read() - // notify_trigger_active to try and see when we're no longer under memory - // pressure. mPollMS indicates how many milliseconds we wait between those - // read()s. - Preferences::AddUintVarCache(&mPollMS, - "gonk.systemMemoryPressureRecoveryPollMS", /* default */ 5000); - - // We have two values for the notify trigger, a soft one which is triggered - // before we start killing background applications and an hard one which is - // after we've killed background applications but before we start killing - // foreground ones. - Preferences::AddUintVarCache(&mSoftLowMemTriggerKB, - "gonk.notifySoftLowMemUnderKB", /* default */ 43008); - Preferences::AddUintVarCache(&mHardLowMemTriggerKB, - "gonk.notifyHardLowMemUnderKB", /* default */ 14336); - } - - nsresult OpenFiles() { - mTriggerFd = open("/sys/kernel/mm/lowmemkiller/notify_trigger_active", - O_RDONLY | O_CLOEXEC); - NS_ENSURE_STATE(mTriggerFd != -1); - - int pipes[2]; - NS_ENSURE_STATE(!pipe(pipes)); - mShutdownPipeRead = pipes[0]; - mShutdownPipeWrite = pipes[1]; - return NS_OK; - } - - /** - * Set the low memory trigger to the specified value, this can be done by - * the main process alone. - */ - void SetLowMemTrigger(uint32_t aValue) { - if (XRE_IsParentProcess()) { - nsPrintfCString str("%ld", (aValue * 1024) / mPageSize); - if (WriteSysFile("/sys/module/lowmemorykiller/parameters/notify_trigger", - str.get())) { - mLowMemTriggerKB = aValue; - } - } - } - - /** - * Read from the trigger file descriptor and determine whether we're - * currently under memory pressure. - * - * We don't expect this method to block. - */ - nsresult CheckForMemoryPressure(bool* aOut) - { - *aOut = false; - - lseek(mTriggerFd, 0, SEEK_SET); - - char buf[2]; - int nread = MOZ_TEMP_FAILURE_RETRY(read(mTriggerFd, buf, sizeof(buf))); - NS_ENSURE_STATE(nread == 2); - - // The notify_trigger_active sysfs node should contain either "0\n" or - // "1\n". The latter indicates memory pressure. - *aOut = (buf[0] == '1'); - return NS_OK; - } - - int AdjustTrigger(int timeout) - { - if (!XRE_IsParentProcess()) { - return -1; // Only the main process can adjust the trigger. - } - - struct sysinfo info; - int rv = sysinfo(&info); - if (rv < 0) { - return -1; // Without system information we're blind, bail out. - } - - size_t freeMemory = (info.freeram * info.mem_unit) / 1024; - - if (freeMemory > mSoftLowMemTriggerKB) { - SetLowMemTrigger(mSoftLowMemTriggerKB); - return -1; // Trigger adjusted, wait indefinitely. - } - - // Wait again but double the duration, max once per day. - return std::min(86400000, timeout * 2); - } - - /** - * Dispatch the specified memory pressure event unless a high-priority - * process is present. If a high-priority process is present then it's likely - * responding to an urgent event (an incoming call or message for example) so - * avoid wasting CPU time responding to low-memory events. - */ - nsresult DispatchMemoryPressure(MemoryPressureState state) - { - if (ProcessPriorityManager::AnyProcessHasHighPriority()) { - return NS_OK; - } - - return NS_DispatchMemoryPressure(state); - } - - Monitor mMonitor; - uint32_t mPollMS; // Ongoing pressure poll delay - uint32_t mSoftLowMemTriggerKB; // Soft memory pressure level - uint32_t mHardLowMemTriggerKB; // Hard memory pressure level - uint32_t mLowMemTriggerKB; // Current value of the trigger - size_t mPageSize; - bool mShuttingDown; - - ScopedClose mTriggerFd; - ScopedClose mShutdownPipeRead; - ScopedClose mShutdownPipeWrite; -}; - -NS_IMPL_ISUPPORTS(MemoryPressureWatcher, nsIRunnable, nsIObserver); - -} // namespace - -namespace mozilla { - -void -InitGonkMemoryPressureMonitoring() -{ - // memoryPressureWatcher is held alive by the observer service. - RefPtr memoryPressureWatcher = - new MemoryPressureWatcher(); - NS_ENSURE_SUCCESS_VOID(memoryPressureWatcher->Init()); - - nsCOMPtr thread; - NS_NewNamedThread("MemoryPressure", getter_AddRefs(thread), - memoryPressureWatcher); -} - -} // namespace mozilla diff --git a/widget/gonk/GonkMemoryPressureMonitoring.h b/widget/gonk/GonkMemoryPressureMonitoring.h deleted file mode 100644 index 4d5149cd6..000000000 --- a/widget/gonk/GonkMemoryPressureMonitoring.h +++ /dev/null @@ -1,14 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set ts=2 et sw=2 tw=80: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_GonkMemoryPressureMonitoring_h_ -#define mozilla_GonkMemoryPressureMonitoring_h_ - -namespace mozilla { -void InitGonkMemoryPressureMonitoring(); -} - -#endif /* mozilla_GonkMemoryPressureMonitoring_h_ */ diff --git a/widget/gonk/GonkPermission.cpp b/widget/gonk/GonkPermission.cpp deleted file mode 100644 index 8ebc43de8..000000000 --- a/widget/gonk/GonkPermission.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/* - * Copyright (C) 2012 Mozilla Foundation - * - * 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. - */ - -#include "GonkPermission.h" -#include -#include -#include -#include - -#ifndef HAVE_ANDROID_OS -#define HAVE_ANDROID_OS 1 -#endif -#include - -#include "mozilla/dom/ContentParent.h" -#include "mozilla/dom/TabParent.h" -#include "mozilla/SyncRunnable.h" -#include "nsIAppsService.h" -#include "mozIApplication.h" -#include "nsThreadUtils.h" - -#undef LOG -#include -#undef ALOGE -#define ALOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "gonkperm" , ## args) - -using namespace android; -using namespace mozilla; - -// Checking permissions needs to happen on the main thread, but the -// binder callback is called on a special binder thread, so we use -// this runnable for that. -class GonkPermissionChecker : public Runnable { - int32_t mPid; - bool mCanUseCamera; - - explicit GonkPermissionChecker(int32_t pid) - : mPid(pid) - , mCanUseCamera(false) - { - } - -public: - static already_AddRefed Inspect(int32_t pid) - { - RefPtr that = new GonkPermissionChecker(pid); - nsCOMPtr mainThread = do_GetMainThread(); - MOZ_ASSERT(mainThread); - SyncRunnable::DispatchToThread(mainThread, that); - return that.forget(); - } - - bool CanUseCamera() - { - return mCanUseCamera; - } - - NS_IMETHOD Run(); -}; - -NS_IMETHODIMP -GonkPermissionChecker::Run() -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Find our ContentParent. - dom::ContentParent *contentParent = nullptr; - { - nsTArray parents; - dom::ContentParent::GetAll(parents); - for (uint32_t i = 0; i < parents.Length(); ++i) { - if (parents[i]->Pid() == mPid) { - contentParent = parents[i]; - break; - } - } - } - if (!contentParent) { - ALOGE("pid=%d denied: can't find ContentParent", mPid); - return NS_OK; - } - - // Now iterate its apps... - const ManagedContainer& browsers = - contentParent->ManagedPBrowserParent(); - for (auto iter = browsers.ConstIter(); !iter.Done(); iter.Next()) { - dom::TabParent *tabParent = - static_cast(iter.Get()->GetKey()); - nsCOMPtr mozApp = tabParent->GetOwnOrContainingApp(); - if (!mozApp) { - continue; - } - - // ...and check if any of them has camera access. - bool appCanUseCamera; - nsresult rv = mozApp->HasPermission("camera", &appCanUseCamera); - if (NS_SUCCEEDED(rv) && appCanUseCamera) { - mCanUseCamera = true; - return NS_OK; - } - } - return NS_OK; -} - -bool -GonkPermissionService::checkPermission(const String16& permission, int32_t pid, - int32_t uid) -{ - // root can do anything. - if (0 == uid) { - return true; - } - - String8 perm8(permission); - - // Some ril implementations need android.permission.MODIFY_AUDIO_SETTINGS - if ((uid == AID_SYSTEM || uid == AID_RADIO || uid == AID_BLUETOOTH) && - perm8 == "android.permission.MODIFY_AUDIO_SETTINGS") { - return true; - } - - // No other permissions apply to non-app processes. - if (uid < AID_APP) { - ALOGE("%s for pid=%d,uid=%d denied: not an app", - String8(permission).string(), pid, uid); - return false; - } - - // Only these permissions can be granted to apps through this service. - if (perm8 != "android.permission.CAMERA" && - perm8 != "android.permission.RECORD_AUDIO") { - ALOGE("%s for pid=%d,uid=%d denied: unsupported permission", - String8(permission).string(), pid, uid); - return false; - } - - // Users granted the permission through a prompt dialog. - // Before permission managment of gUM is done, app cannot remember the - // permission. - PermissionGrant permGrant(perm8.string(), pid); - if (nsTArray::NoIndex != mGrantArray.IndexOf(permGrant)) { - mGrantArray.RemoveElement(permGrant); - return true; - } - - // Camera/audio record permissions are allowed for apps with the - // "camera" permission. - RefPtr checker = - GonkPermissionChecker::Inspect(pid); - bool canUseCamera = checker->CanUseCamera(); - if (!canUseCamera) { - ALOGE("%s for pid=%d,uid=%d denied: not granted by user or app manifest", - String8(permission).string(), pid, uid); - } - return canUseCamera; -} - -static GonkPermissionService* gGonkPermissionService = NULL; - -/* static */ -void -GonkPermissionService::instantiate() -{ - defaultServiceManager()->addService(String16(getServiceName()), - GetInstance()); -} - -/* static */ -GonkPermissionService* -GonkPermissionService::GetInstance() -{ - if (!gGonkPermissionService) { - gGonkPermissionService = new GonkPermissionService(); - } - return gGonkPermissionService; -} - -void -GonkPermissionService::addGrantInfo(const char* permission, int32_t pid) -{ - mGrantArray.AppendElement(PermissionGrant(permission, pid)); -} diff --git a/widget/gonk/GonkPermission.h b/widget/gonk/GonkPermission.h deleted file mode 100644 index d34fcd8ac..000000000 --- a/widget/gonk/GonkPermission.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2012 Mozilla Foundation - * - * 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. - */ -#ifndef GONKPERMISSION_H -#define GONKPERMISSION_H - -#include -#include "nsString.h" -#include "nsTArray.h" - -namespace mozilla { -class PermissionGrant -{ -public: - PermissionGrant(const char* perm, int32_t p) : mPid(p) - { - mPermission.Assign(perm); - } - - PermissionGrant(const nsACString& permission, int32_t pid) : mPid(pid), - mPermission(permission) - { - } - - bool operator==(const PermissionGrant& other) const - { - return (mPid == other.pid() && mPermission.Equals(other.permission())); - } - - int32_t pid() const - { - return mPid; - } - - const nsACString& permission() const - { - return mPermission; - } - -private: - int32_t mPid; - nsCString mPermission; -}; - -class PermissionGrant; - -class GonkPermissionService : - public android::BinderService, - public android::BnPermissionController -{ -public: - virtual ~GonkPermissionService() {} - static GonkPermissionService* GetInstance(); - static const char *getServiceName() { - return "permission"; - } - - static void instantiate(); - - virtual android::status_t dump(int fd, const android::Vector& args) { - return android::NO_ERROR; - } - virtual bool checkPermission(const android::String16& permission, int32_t pid, - int32_t uid); - - void addGrantInfo(const char* permission, int32_t pid); -private: - GonkPermissionService(): android::BnPermissionController() {} - nsTArray mGrantArray; -}; - -} // namespace mozilla - -#endif // GONKPERMISSION_H diff --git a/widget/gonk/HwcComposer2D.cpp b/widget/gonk/HwcComposer2D.cpp deleted file mode 100644 index 6b4c7a1cc..000000000 --- a/widget/gonk/HwcComposer2D.cpp +++ /dev/null @@ -1,971 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2012, 2013 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#include -#include - -#include "gfxPrefs.h" -#include "ImageLayers.h" -#include "libdisplay/GonkDisplay.h" -#include "HwcComposer2D.h" -#include "LayerScope.h" -#include "Units.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/LayerManagerComposite.h" -#include "mozilla/layers/PLayerTransaction.h" -#include "mozilla/layers/ShadowLayerUtilsGralloc.h" -#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL -#include "mozilla/StaticPtr.h" -#include "nsThreadUtils.h" -#include "cutils/properties.h" -#include "gfx2DGlue.h" -#include "gfxPlatform.h" -#include "VsyncSource.h" -#include "nsScreenManagerGonk.h" -#include "nsWindow.h" - -#if ANDROID_VERSION >= 17 -#include "libdisplay/DisplaySurface.h" -#endif - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "HWComposer" - -/* - * By default the debug message of hwcomposer (LOG_DEBUG level) are undefined, - * but can be enabled by uncommenting HWC_DEBUG below. - */ -//#define HWC_DEBUG - -#ifdef HWC_DEBUG -#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args) -#else -#define LOGD(args...) ((void)0) -#endif - -#define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) - -#define LAYER_COUNT_INCREMENTS 5 - -using namespace android; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace mozilla { - -static void -HookInvalidate(const struct hwc_procs* aProcs) -{ - HwcComposer2D::GetInstance()->Invalidate(); -} - -static void -HookVsync(const struct hwc_procs* aProcs, int aDisplay, - int64_t aTimestamp) -{ - HwcComposer2D::GetInstance()->Vsync(aDisplay, aTimestamp); -} - -static void -HookHotplug(const struct hwc_procs* aProcs, int aDisplay, - int aConnected) -{ - HwcComposer2D::GetInstance()->Hotplug(aDisplay, aConnected); -} - -static StaticRefPtr sInstance; - -HwcComposer2D::HwcComposer2D() - : mList(nullptr) - , mMaxLayerCount(0) - , mColorFill(false) - , mRBSwapSupport(false) - , mPrepared(false) - , mHasHWVsync(false) - , mLock("mozilla.HwcComposer2D.mLock") -{ - mHal = HwcHALBase::CreateHwcHAL(); - if (!mHal->HasHwc()) { - LOGD("no hwc support"); - return; - } - - RegisterHwcEventCallback(); - - nsIntSize screenSize; - - GonkDisplay::NativeData data = GetGonkDisplay()->GetNativeData(GonkDisplay::DISPLAY_PRIMARY); - ANativeWindow *win = data.mNativeWindow.get(); - win->query(win, NATIVE_WINDOW_WIDTH, &screenSize.width); - win->query(win, NATIVE_WINDOW_HEIGHT, &screenSize.height); - mScreenRect = gfx::IntRect(gfx::IntPoint(0, 0), screenSize); - - mColorFill = mHal->Query(HwcHALBase::QueryType::COLOR_FILL); - mRBSwapSupport = mHal->Query(HwcHALBase::QueryType::RB_SWAP); -} - -HwcComposer2D::~HwcComposer2D() -{ - free(mList); -} - -HwcComposer2D* -HwcComposer2D::GetInstance() -{ - if (!sInstance) { -#ifdef HWC_DEBUG - // Make sure only create once - static int timesCreated = 0; - ++timesCreated; - MOZ_ASSERT(timesCreated == 1); -#endif - LOGI("Creating new instance"); - sInstance = new HwcComposer2D(); - - // If anyone uses the compositor thread to create HwcComposer2D, - // we just skip this function. - // If ClearOnShutdown() can handle objects in other threads - // in the future, we can remove this check. - if (NS_IsMainThread()) { - // If we create HwcComposer2D by the main thread, we can use - // ClearOnShutdown() to make sure it will be nullified properly. - ClearOnShutdown(&sInstance); - } - } - return sInstance; -} - -bool -HwcComposer2D::EnableVsync(bool aEnable) -{ - MOZ_ASSERT(NS_IsMainThread()); - if (!mHasHWVsync) { - return false; - } - return mHal->EnableVsync(aEnable) && aEnable; -} - -bool -HwcComposer2D::RegisterHwcEventCallback() -{ - const HwcHALProcs_t cHWCProcs = { - &HookInvalidate, // 1st: void (*invalidate)(...) - &HookVsync, // 2nd: void (*vsync)(...) - &HookHotplug // 3rd: void (*hotplug)(...) - }; - mHasHWVsync = mHal->RegisterHwcEventCallback(cHWCProcs); - return mHasHWVsync; -} - -void -HwcComposer2D::Vsync(int aDisplay, nsecs_t aVsyncTimestamp) -{ - // Only support hardware vsync on kitkat, L and up due to inaccurate timings - // with JellyBean. -#if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) - TimeStamp vsyncTime = mozilla::TimeStamp::FromSystemTime(aVsyncTimestamp); - gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay().NotifyVsync(vsyncTime); -#else - // If this device doesn't support vsync, this function should not be used. - MOZ_ASSERT(false); -#endif -} - -// Called on the "invalidator" thread (run from HAL). -void -HwcComposer2D::Invalidate() -{ - if (!mHal->HasHwc()) { - LOGE("HwcComposer2D::Invalidate failed!"); - return; - } - - MutexAutoLock lock(mLock); - if (mCompositorBridgeParent) { - mCompositorBridgeParent->ScheduleRenderOnCompositorThread(); - } -} - -namespace { -class HotplugEvent : public Runnable { -public: - HotplugEvent(GonkDisplay::DisplayType aType, bool aConnected) - : mType(aType) - , mConnected(aConnected) - { - } - - NS_IMETHOD Run() override - { - RefPtr screenManager = - nsScreenManagerGonk::GetInstance(); - if (mConnected) { - screenManager->AddScreen(mType); - } else { - screenManager->RemoveScreen(mType); - } - return NS_OK; - } -private: - GonkDisplay::DisplayType mType; - bool mConnected; -}; -} // namespace - -void -HwcComposer2D::Hotplug(int aDisplay, int aConnected) -{ - NS_DispatchToMainThread(new HotplugEvent(GonkDisplay::DISPLAY_EXTERNAL, - aConnected)); -} - -void -HwcComposer2D::SetCompositorBridgeParent(CompositorBridgeParent* aCompositorBridgeParent) -{ - MutexAutoLock lock(mLock); - mCompositorBridgeParent = aCompositorBridgeParent; -} - -bool -HwcComposer2D::ReallocLayerList() -{ - int size = sizeof(HwcList) + - ((mMaxLayerCount + LAYER_COUNT_INCREMENTS) * sizeof(HwcLayer)); - - HwcList* listrealloc = (HwcList*)realloc(mList, size); - - if (!listrealloc) { - return false; - } - - if (!mList) { - //first alloc, initialize - listrealloc->numHwLayers = 0; - listrealloc->flags = 0; - } - - mList = listrealloc; - mMaxLayerCount += LAYER_COUNT_INCREMENTS; - return true; -} - -bool -HwcComposer2D::PrepareLayerList(Layer* aLayer, - const nsIntRect& aClip, - const Matrix& aParentTransform, - bool aFindSidebandStreams) -{ - // NB: we fall off this path whenever there are container layers - // that require intermediate surfaces. That means all the - // GetEffective*() coordinates are relative to the framebuffer. - - bool fillColor = false; - - const nsIntRegion visibleRegion = aLayer->GetLocalVisibleRegion().ToUnknownRegion(); - if (visibleRegion.IsEmpty()) { - return true; - } - - uint8_t opacity = std::min(0xFF, (int)(aLayer->GetEffectiveOpacity() * 256.0)); - if (opacity == 0) { - LOGD("%s Layer has zero opacity; skipping", aLayer->Name()); - return true; - } - - if (!mHal->SupportTransparency() && opacity < 0xFF && !aFindSidebandStreams) { - LOGD("%s Layer has planar semitransparency which is unsupported by hwcomposer", aLayer->Name()); - return false; - } - - if (aLayer->GetMaskLayer() && !aFindSidebandStreams) { - LOGD("%s Layer has MaskLayer which is unsupported by hwcomposer", aLayer->Name()); - return false; - } - - nsIntRect clip; - nsIntRect layerClip = aLayer->GetLocalClipRect().valueOr(ParentLayerIntRect()).ToUnknownRect(); - nsIntRect* layerClipPtr = aLayer->GetLocalClipRect() ? &layerClip : nullptr; - if (!HwcUtils::CalculateClipRect(aParentTransform, - layerClipPtr, - aClip, - &clip)) - { - LOGD("%s Clip rect is empty. Skip layer", aLayer->Name()); - return true; - } - - // HWC supports only the following 2D transformations: - // - // Scaling via the sourceCrop and displayFrame in HwcLayer - // Translation via the sourceCrop and displayFrame in HwcLayer - // Rotation (in square angles only) via the HWC_TRANSFORM_ROT_* flags - // Reflection (horizontal and vertical) via the HWC_TRANSFORM_FLIP_* flags - // - // A 2D transform with PreservesAxisAlignedRectangles() has all the attributes - // above - Matrix layerTransform; - if (!aLayer->GetEffectiveTransform().Is2D(&layerTransform) || - !layerTransform.PreservesAxisAlignedRectangles()) { - LOGD("Layer EffectiveTransform has a 3D transform or a non-square angle rotation"); - return false; - } - - Matrix layerBufferTransform; - if (!aLayer->GetEffectiveTransformForBuffer().Is2D(&layerBufferTransform) || - !layerBufferTransform.PreservesAxisAlignedRectangles()) { - LOGD("Layer EffectiveTransformForBuffer has a 3D transform or a non-square angle rotation"); - return false; - } - - if (ContainerLayer* container = aLayer->AsContainerLayer()) { - if (container->UseIntermediateSurface() && !aFindSidebandStreams) { - LOGD("Container layer needs intermediate surface"); - return false; - } - AutoTArray children; - container->SortChildrenBy3DZOrder(children); - - for (uint32_t i = 0; i < children.Length(); i++) { - if (!PrepareLayerList(children[i], clip, layerTransform, aFindSidebandStreams) && - !aFindSidebandStreams) { - return false; - } - } - return true; - } - - LayerRenderState state = aLayer->GetRenderState(); - -#if ANDROID_VERSION >= 21 - if (!state.GetGrallocBuffer() && !state.GetSidebandStream().IsValid()) { -#else - if (!state.GetGrallocBuffer()) { -#endif - if (aLayer->AsColorLayer() && mColorFill) { - fillColor = true; - } else { - LOGD("%s Layer doesn't have a gralloc buffer", aLayer->Name()); - return false; - } - } - - nsIntRect visibleRect = visibleRegion.GetBounds(); - - nsIntRect bufferRect; - if (fillColor) { - bufferRect = nsIntRect(visibleRect); - } else { - nsIntRect layerRect; - if (state.mHasOwnOffset) { - bufferRect = nsIntRect(state.mOffset.x, state.mOffset.y, - state.mSize.width, state.mSize.height); - layerRect = bufferRect; - } else { - //Since the buffer doesn't have its own offset, assign the whole - //surface size as its buffer bounds - bufferRect = nsIntRect(0, 0, state.mSize.width, state.mSize.height); - layerRect = bufferRect; - if (aLayer->GetType() == Layer::TYPE_IMAGE) { - ImageLayer* imageLayer = static_cast(aLayer); - if(imageLayer->GetScaleMode() != ScaleMode::SCALE_NONE) { - layerRect = nsIntRect(0, 0, imageLayer->GetScaleToSize().width, imageLayer->GetScaleToSize().height); - } - } - } - // In some cases the visible rect assigned to the layer can be larger - // than the layer's surface, e.g., an ImageLayer with a small Image - // in it. - visibleRect.IntersectRect(visibleRect, layerRect); - } - - // Buffer rotation is not to be confused with the angled rotation done by a transform matrix - // It's a fancy PaintedLayer feature used for scrolling - if (state.BufferRotated()) { - LOGD("%s Layer has a rotated buffer", aLayer->Name()); - return false; - } - - const bool needsYFlip = state.OriginBottomLeft() ? true - : false; - - hwc_rect_t sourceCrop, displayFrame; - if(!HwcUtils::PrepareLayerRects(visibleRect, - layerTransform, - layerBufferTransform, - clip, - bufferRect, - needsYFlip, - &(sourceCrop), - &(displayFrame))) - { - return true; - } - - // OK! We can compose this layer with hwc. - int current = mList ? mList->numHwLayers : 0; - - // Do not compose any layer below full-screen Opaque layer - // Note: It can be generalized to non-fullscreen Opaque layers. - bool isOpaque = opacity == 0xFF && - (state.mFlags & LayerRenderStateFlags::OPAQUE); - // Currently we perform opacity calculation using the *bounds* of the layer. - // We can only make this assumption if we're not dealing with a complex visible region. - bool isSimpleVisibleRegion = visibleRegion.Contains(visibleRect); - if (current && isOpaque && isSimpleVisibleRegion) { - nsIntRect displayRect = nsIntRect(displayFrame.left, displayFrame.top, - displayFrame.right - displayFrame.left, displayFrame.bottom - displayFrame.top); - if (displayRect.Contains(mScreenRect)) { - // In z-order, all previous layers are below - // the current layer. We can ignore them now. - mList->numHwLayers = current = 0; - mHwcLayerMap.Clear(); - } - } - - if (!mList || current >= mMaxLayerCount) { - if (!ReallocLayerList() || current >= mMaxLayerCount) { - LOGE("PrepareLayerList failed! Could not increase the maximum layer count"); - return false; - } - } - - HwcLayer& hwcLayer = mList->hwLayers[current]; - hwcLayer.displayFrame = displayFrame; - mHal->SetCrop(hwcLayer, sourceCrop); - buffer_handle_t handle = nullptr; -#if ANDROID_VERSION >= 21 - if (state.GetSidebandStream().IsValid()) { - handle = state.GetSidebandStream().GetRawNativeHandle(); - } else if (state.GetGrallocBuffer()) { - handle = state.GetGrallocBuffer()->getNativeBuffer()->handle; - } -#else - if (state.GetGrallocBuffer()) { - handle = state.GetGrallocBuffer()->getNativeBuffer()->handle; - } -#endif - hwcLayer.handle = handle; - - hwcLayer.flags = 0; - hwcLayer.hints = 0; - hwcLayer.blending = isOpaque ? HWC_BLENDING_NONE : HWC_BLENDING_PREMULT; -#if ANDROID_VERSION >= 17 - hwcLayer.compositionType = HWC_FRAMEBUFFER; -#if ANDROID_VERSION >= 21 - if (state.GetSidebandStream().IsValid()) { - hwcLayer.compositionType = HWC_SIDEBAND; - } -#endif - hwcLayer.acquireFenceFd = -1; - hwcLayer.releaseFenceFd = -1; -#if ANDROID_VERSION >= 18 - hwcLayer.planeAlpha = opacity; -#endif -#else - hwcLayer.compositionType = HwcUtils::HWC_USE_COPYBIT; -#endif - - if (!fillColor) { - if (state.FormatRBSwapped()) { - if (!mRBSwapSupport) { - LOGD("No R/B swap support in H/W Composer"); - return false; - } - hwcLayer.flags |= HwcUtils::HWC_FORMAT_RB_SWAP; - } - - // Translation and scaling have been addressed in PrepareLayerRects(). - // Given the above and that we checked for PreservesAxisAlignedRectangles() - // the only possible transformations left to address are - // square angle rotation and horizontal/vertical reflection. - // - // The rotation and reflection permutations total 16 but can be - // reduced to 8 transformations after eliminating redundancies. - // - // All matrices represented here are in the form - // - // | xx xy | - // | yx yy | - // - // And ignore scaling. - // - // Reflection is applied before rotation - gfx::Matrix rotation = layerTransform; - // Compute fuzzy zero like PreservesAxisAlignedRectangles() - if (fabs(rotation._11) < 1e-6) { - if (rotation._21 < 0) { - if (rotation._12 > 0) { - // 90 degree rotation - // - // | 0 -1 | - // | 1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_90; - LOGD("Layer rotated 90 degrees"); - } - else { - // Horizontal reflection then 90 degree rotation - // - // | 0 -1 | | -1 0 | = | 0 -1 | - // | 1 0 | | 0 1 | | -1 0 | - // - // same as vertical reflection then 270 degree rotation - // - // | 0 1 | | 1 0 | = | 0 -1 | - // | -1 0 | | 0 -1 | | -1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_H; - LOGD("Layer vertically reflected then rotated 270 degrees"); - } - } else { - if (rotation._12 < 0) { - // 270 degree rotation - // - // | 0 1 | - // | -1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_270; - LOGD("Layer rotated 270 degrees"); - } - else { - // Vertical reflection then 90 degree rotation - // - // | 0 1 | | -1 0 | = | 0 1 | - // | -1 0 | | 0 1 | | 1 0 | - // - // Same as horizontal reflection then 270 degree rotation - // - // | 0 -1 | | 1 0 | = | 0 1 | - // | 1 0 | | 0 -1 | | 1 0 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_90 | HWC_TRANSFORM_FLIP_V; - LOGD("Layer horizontally reflected then rotated 270 degrees"); - } - } - } else if (rotation._11 < 0) { - if (rotation._22 > 0) { - // Horizontal reflection - // - // | -1 0 | - // | 0 1 | - // - hwcLayer.transform = HWC_TRANSFORM_FLIP_H; - LOGD("Layer rotated 180 degrees"); - } - else { - // 180 degree rotation - // - // | -1 0 | - // | 0 -1 | - // - // Same as horizontal and vertical reflection - // - // | -1 0 | | 1 0 | = | -1 0 | - // | 0 1 | | 0 -1 | | 0 -1 | - // - hwcLayer.transform = HWC_TRANSFORM_ROT_180; - LOGD("Layer rotated 180 degrees"); - } - } else { - if (rotation._22 < 0) { - // Vertical reflection - // - // | 1 0 | - // | 0 -1 | - // - hwcLayer.transform = HWC_TRANSFORM_FLIP_V; - LOGD("Layer rotated 180 degrees"); - } - else { - // No rotation or reflection - // - // | 1 0 | - // | 0 1 | - // - hwcLayer.transform = 0; - } - } - - const bool needsYFlip = state.OriginBottomLeft() ? true - : false; - - if (needsYFlip) { - // Invert vertical reflection flag if it was already set - hwcLayer.transform ^= HWC_TRANSFORM_FLIP_V; - } - hwc_region_t region; - if (visibleRegion.GetNumRects() > 1) { - mVisibleRegions.push_back(HwcUtils::RectVector()); - HwcUtils::RectVector* visibleRects = &(mVisibleRegions.back()); - bool isVisible = false; - if(!HwcUtils::PrepareVisibleRegion(visibleRegion, - layerTransform, - layerBufferTransform, - clip, - bufferRect, - visibleRects, - isVisible)) { - LOGD("A region of layer is too small to be rendered by HWC"); - return false; - } - if (!isVisible) { - // Layer is not visible, no need to render it - return true; - } - region.numRects = visibleRects->size(); - region.rects = &((*visibleRects)[0]); - } else { - region.numRects = 1; - region.rects = &(hwcLayer.displayFrame); - } - hwcLayer.visibleRegionScreen = region; - } else { - hwcLayer.flags |= HwcUtils::HWC_COLOR_FILL; - ColorLayer* colorLayer = aLayer->AsColorLayer(); - if (colorLayer->GetColor().a < 1.0) { - LOGD("Color layer has semitransparency which is unsupported"); - return false; - } - hwcLayer.transform = colorLayer->GetColor().ToABGR(); - } - -#if ANDROID_VERSION >= 21 - if (aFindSidebandStreams && hwcLayer.compositionType == HWC_SIDEBAND) { - mCachedSidebandLayers.AppendElement(hwcLayer); - } -#endif - - mHwcLayerMap.AppendElement(static_cast(aLayer->ImplData())); - mList->numHwLayers++; - return true; -} - - -#if ANDROID_VERSION >= 17 -bool -HwcComposer2D::TryHwComposition(nsScreenGonk* aScreen) -{ - DisplaySurface* dispSurface = aScreen->GetDisplaySurface(); - - if (!(dispSurface && dispSurface->lastHandle)) { - LOGD("H/W Composition failed. DispSurface not initialized."); - return false; - } - - // Add FB layer - int idx = mList->numHwLayers++; - if (idx >= mMaxLayerCount) { - if (!ReallocLayerList() || idx >= mMaxLayerCount) { - LOGE("TryHwComposition failed! Could not add FB layer"); - return false; - } - } - - Prepare(dispSurface->lastHandle, -1, aScreen); - - /* Possible composition paths, after hwc prepare: - 1. GPU Composition - 2. BLIT Composition - 3. Full OVERLAY Composition - 4. Partial OVERLAY Composition (GPU + OVERLAY) */ - - bool gpuComposite = false; - bool blitComposite = false; - bool overlayComposite = true; - - for (int j=0; j < idx; j++) { - if (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER || - mList->hwLayers[j].compositionType == HWC_BLIT) { - // Full OVERLAY composition is not possible on this frame - // It is either GPU / BLIT / partial OVERLAY composition. - overlayComposite = false; - break; - } - } - - if (!overlayComposite) { - for (int k=0; k < idx; k++) { - switch (mList->hwLayers[k].compositionType) { - case HWC_FRAMEBUFFER: - gpuComposite = true; - break; - case HWC_BLIT: - blitComposite = true; - break; -#if ANDROID_VERSION >= 21 - case HWC_SIDEBAND: -#endif - case HWC_OVERLAY: { - // HWC will compose HWC_OVERLAY layers in partial - // Overlay Composition, set layer composition flag - // on mapped LayerComposite to skip GPU composition - mHwcLayerMap[k]->SetLayerComposited(true); - - uint8_t opacity = std::min(0xFF, (int)(mHwcLayerMap[k]->GetLayer()->GetEffectiveOpacity() * 256.0)); - if ((mList->hwLayers[k].hints & HWC_HINT_CLEAR_FB) && - (opacity == 0xFF)) { - // Clear visible rect on FB with transparent pixels. - hwc_rect_t r = mList->hwLayers[k].displayFrame; - mHwcLayerMap[k]->SetClearRect(nsIntRect(r.left, r.top, - r.right - r.left, - r.bottom - r.top)); - } - break; - } - default: - break; - } - } - - if (gpuComposite) { - // GPU or partial OVERLAY Composition - return false; - } else if (blitComposite) { - // BLIT Composition, flip DispSurface target - GetGonkDisplay()->UpdateDispSurface(aScreen->GetEGLDisplay(), aScreen->GetEGLSurface()); - DisplaySurface* dispSurface = aScreen->GetDisplaySurface(); - if (!dispSurface) { - LOGE("H/W Composition failed. NULL DispSurface."); - return false; - } - mList->hwLayers[idx].handle = dispSurface->lastHandle; - mList->hwLayers[idx].acquireFenceFd = dispSurface->GetPrevDispAcquireFd(); - } - } - - // BLIT or full OVERLAY Composition - return Commit(aScreen); -} - -bool -HwcComposer2D::Render(nsIWidget* aWidget) -{ - nsScreenGonk* screen = static_cast(aWidget)->GetScreen(); - - // HWC module does not exist or mList is not created yet. - if (!mHal->HasHwc() || !mList) { - return GetGonkDisplay()->SwapBuffers(screen->GetEGLDisplay(), screen->GetEGLSurface()); - } else if (!mList && !ReallocLayerList()) { - LOGE("Cannot realloc layer list"); - return false; - } - - DisplaySurface* dispSurface = screen->GetDisplaySurface(); - if (!dispSurface) { - LOGE("H/W Composition failed. DispSurface not initialized."); - return false; - } - - if (mPrepared) { - // No mHwc prepare, if already prepared in current draw cycle - mList->hwLayers[mList->numHwLayers - 1].handle = dispSurface->lastHandle; - mList->hwLayers[mList->numHwLayers - 1].acquireFenceFd = dispSurface->GetPrevDispAcquireFd(); - } else { - // Update screen rect to handle a case that TryRenderWithHwc() is not called. - mScreenRect = screen->GetNaturalBounds().ToUnknownRect(); - - mList->flags = HWC_GEOMETRY_CHANGED; - mList->numHwLayers = 2; - mList->hwLayers[0].hints = 0; - mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; - mList->hwLayers[0].flags = HWC_SKIP_LAYER; - mList->hwLayers[0].backgroundColor = {0}; - mList->hwLayers[0].acquireFenceFd = -1; - mList->hwLayers[0].releaseFenceFd = -1; - mList->hwLayers[0].displayFrame = {0, 0, mScreenRect.width, mScreenRect.height}; - -#if ANDROID_VERSION >= 21 - // Prepare layers for sideband streams - const uint32_t len = mCachedSidebandLayers.Length(); - for (uint32_t i = 0; i < len; ++i) { - ++mList->numHwLayers; - mList->hwLayers[i+1] = mCachedSidebandLayers[i]; - } -#endif - Prepare(dispSurface->lastHandle, dispSurface->GetPrevDispAcquireFd(), screen); - } - - // GPU or partial HWC Composition - return Commit(screen); -} - -void -HwcComposer2D::Prepare(buffer_handle_t dispHandle, int fence, nsScreenGonk* screen) -{ - if (mPrepared) { - LOGE("Multiple hwc prepare calls!"); - } - hwc_rect_t dispRect = {0, 0, mScreenRect.width, mScreenRect.height}; - mHal->Prepare(mList, screen->GetDisplayType(), dispRect, dispHandle, fence); - mPrepared = true; -} - -bool -HwcComposer2D::Commit(nsScreenGonk* aScreen) -{ - for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { - mList->hwLayers[j].acquireFenceFd = -1; - if (mHwcLayerMap.IsEmpty() || - (mList->hwLayers[j].compositionType == HWC_FRAMEBUFFER)) { - continue; - } - LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState(); - if (!state.mTexture) { - continue; - } - FenceHandle fence = state.mTexture->GetAndResetAcquireFenceHandle(); - if (fence.IsValid()) { - RefPtr fdObj = fence.GetAndResetFdObj(); - mList->hwLayers[j].acquireFenceFd = fdObj->GetAndResetFd(); - } - } - - int err = mHal->Set(mList, aScreen->GetDisplayType()); - - mPrevRetireFence.TransferToAnotherFenceHandle(mPrevDisplayFence); - - for (uint32_t j=0; j < (mList->numHwLayers - 1); j++) { - if (mList->hwLayers[j].releaseFenceFd >= 0) { - int fd = mList->hwLayers[j].releaseFenceFd; - mList->hwLayers[j].releaseFenceFd = -1; - RefPtr fdObj = new FenceHandle::FdObj(fd); - FenceHandle fence(fdObj); - - LayerRenderState state = mHwcLayerMap[j]->GetLayer()->GetRenderState(); - if (!state.mTexture) { - continue; - } - state.mTexture->SetReleaseFenceHandle(fence); - } - } - - if (mList->retireFenceFd >= 0) { - mPrevRetireFence = FenceHandle(new FenceHandle::FdObj(mList->retireFenceFd)); - } - - // Set DisplaySurface layer fence - DisplaySurface* displaySurface = aScreen->GetDisplaySurface(); - displaySurface->setReleaseFenceFd(mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd); - mList->hwLayers[mList->numHwLayers - 1].releaseFenceFd = -1; - - mPrepared = false; - return !err; -} -#else -bool -HwcComposer2D::TryHwComposition(nsScreenGonk* aScreen) -{ - mHal->SetEGLInfo(aScreen->GetEGLDisplay(), aScreen->GetEGLSurface()); - return !mHal->Set(mList, aScreen->GetDisplayType()); -} - -bool -HwcComposer2D::Render(nsIWidget* aWidget) -{ - nsScreenGonk* screen = static_cast(aWidget)->GetScreen(); - return GetGonkDisplay()->SwapBuffers(screen->GetEGLDisplay(), screen->GetEGLSurface()); -} -#endif - -bool -HwcComposer2D::TryRenderWithHwc(Layer* aRoot, - nsIWidget* aWidget, - bool aGeometryChanged, - bool aHasImageHostOverlays) -{ - if (!mHal->HasHwc()) { - return false; - } - - nsScreenGonk* screen = static_cast(aWidget)->GetScreen(); - - if (mList) { - mList->flags = mHal->GetGeometryChangedFlag(aGeometryChanged); - mList->numHwLayers = 0; - mHwcLayerMap.Clear(); - } - - if (mPrepared) { - mHal->ResetHwc(); - mPrepared = false; - } - - // XXX: The clear() below means all rect vectors will be have to be - // reallocated. We may want to avoid this if possible - mVisibleRegions.clear(); - - mScreenRect = screen->GetNaturalBounds().ToUnknownRect(); - MOZ_ASSERT(mHwcLayerMap.IsEmpty()); - mCachedSidebandLayers.Clear(); - if (!PrepareLayerList(aRoot, - mScreenRect, - gfx::Matrix(), - /* aFindSidebandStreams */ false)) - { - mHwcLayerMap.Clear(); - LOGD("Render aborted. Fallback to GPU Composition"); - if (aHasImageHostOverlays) { - LOGD("Prepare layers of SidebandStreams"); - // Failed to create a layer list for hwc. But we need the list - // only for handling sideband streams. Traverse layer tree without - // some early returns to make sure we can find all the layers. - // It is the best wrong thing that we can do. - PrepareLayerList(aRoot, - mScreenRect, - gfx::Matrix(), - /* aFindSidebandStreams */ true); - // Reset mPrepared to false, since we already fell back to - // gpu composition. - mPrepared = false; - } - return false; - } - - // Send data to LayerScope for debugging - SendtoLayerScope(); - - if (!TryHwComposition(screen)) { - LOGD("Full HWC Composition failed. Fallback to GPU Composition or partial OVERLAY Composition"); - LayerScope::CleanLayer(); - return false; - } - - LOGD("Frame rendered"); - return true; -} - -void -HwcComposer2D::SendtoLayerScope() -{ - if (!LayerScope::CheckSendable()) { - return; - } - - const int len = mList->numHwLayers; - for (int i = 0; i < len; ++i) { - LayerComposite* layer = mHwcLayerMap[i]; - const hwc_rect_t r = mList->hwLayers[i].displayFrame; - LayerScope::SendLayer(layer, r.right - r.left, r.bottom - r.top); - } -} - -} // namespace mozilla diff --git a/widget/gonk/HwcComposer2D.h b/widget/gonk/HwcComposer2D.h deleted file mode 100644 index 56c1d1ec1..000000000 --- a/widget/gonk/HwcComposer2D.h +++ /dev/null @@ -1,123 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2012, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcComposer2D -#define mozilla_HwcComposer2D - -#include "Composer2D.h" -#include "hwchal/HwcHALBase.h" // for HwcHAL -#include "HwcUtils.h" // for RectVector -#include "Layers.h" -#include "mozilla/Mutex.h" -#include "mozilla/layers/FenceUtils.h" // for FenceHandle -#include "mozilla/UniquePtr.h" // for HwcHAL - -#include -#include - -#include - -class nsScreenGonk; - -namespace mozilla { - -namespace gl { - class GLContext; -} - -namespace layers { -class CompositorBridgeParent; -class Layer; -} - -/* - * HwcComposer2D provides a way for gecko to render frames - * using hwcomposer.h in the AOSP HAL. - * - * hwcomposer.h defines an interface for display composition - * using dedicated hardware. This hardware is usually faster - * or more power efficient than the GPU. However, in exchange - * for better performance, generality has to be sacrificed: - * no 3d transforms, no intermediate surfaces, no special shader effects, - * and loss of other goodies depending on the platform. - * - * In general, when hwc is enabled gecko tries to compose - * its frames using HwcComposer2D first. Then if HwcComposer2D is - * unable to compose a frame then it falls back to compose it - * using the GPU with OpenGL. - * - */ -class HwcComposer2D : public mozilla::layers::Composer2D { -public: - HwcComposer2D(); - virtual ~HwcComposer2D(); - - static HwcComposer2D* GetInstance(); - - // Returns TRUE if the container has been succesfully rendered - // Returns FALSE if the container cannot be fully rendered - // by this composer so nothing was rendered at all - virtual bool TryRenderWithHwc(layers::Layer* aRoot, - nsIWidget* aWidget, - bool aGeometryChanged, - bool aHasImageHostOverlays) override; - - virtual bool Render(nsIWidget* aWidget) override; - - virtual bool HasHwc() override { return mHal->HasHwc(); } - - bool EnableVsync(bool aEnable); - bool RegisterHwcEventCallback(); - void Vsync(int aDisplay, int64_t aTimestamp); - void Invalidate(); - void Hotplug(int aDisplay, int aConnected); - void SetCompositorBridgeParent(layers::CompositorBridgeParent* aCompositorBridgeParent); - -private: - void Reset(); - void Prepare(buffer_handle_t dispHandle, int fence, nsScreenGonk* screen); - bool Commit(nsScreenGonk* aScreen); - bool TryHwComposition(nsScreenGonk* aScreen); - bool ReallocLayerList(); - bool PrepareLayerList(layers::Layer* aContainer, const nsIntRect& aClip, - const gfx::Matrix& aParentTransform, - bool aFindSidebandStreams); - void SendtoLayerScope(); - - UniquePtr mHal; - HwcList* mList; - nsIntRect mScreenRect; - int mMaxLayerCount; - bool mColorFill; - bool mRBSwapSupport; - //Holds all the dynamically allocated RectVectors needed - //to render the current frame - std::list mVisibleRegions; - layers::FenceHandle mPrevRetireFence; - layers::FenceHandle mPrevDisplayFence; - nsTArray mCachedSidebandLayers; - nsTArray mHwcLayerMap; - bool mPrepared; - bool mHasHWVsync; - layers::CompositorBridgeParent* mCompositorBridgeParent; - Mutex mLock; -}; - -} // namespace mozilla - -#endif // mozilla_HwcComposer2D diff --git a/widget/gonk/HwcUtils.cpp b/widget/gonk/HwcUtils.cpp deleted file mode 100644 index a8f030f3c..000000000 --- a/widget/gonk/HwcUtils.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Copyright (c) 2013 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#include -#include "HwcUtils.h" -#include "gfxUtils.h" -#include "gfx2DGlue.h" - -#define LOG_TAG "HwcUtils" - -#if (LOG_NDEBUG == 0) -#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, ## args) -#else -#define LOGD(args...) ((void)0) -#endif - -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) - - -namespace mozilla { - -/* Utility functions for HwcComposer */ - - - -/* static */ bool -HwcUtils::PrepareLayerRects(nsIntRect aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - bool aYFlipped, - hwc_rect_t* aSourceCrop, hwc_rect_t* aVisibleRegionScreen) { - - gfxMatrix aTransform = gfx::ThebesMatrix(aLayerTransform); - gfxRect visibleRect(ThebesRect(aVisible)); - gfxRect clip(ThebesRect(aClip)); - gfxRect visibleRectScreen = aTransform.TransformBounds(visibleRect); - // |clip| is guaranteed to be integer - visibleRectScreen.IntersectRect(visibleRectScreen, clip); - - if (visibleRectScreen.IsEmpty()) { - return false; - } - - gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform); - inverse.Invert(); - gfxRect crop = inverse.TransformBounds(visibleRectScreen); - - //clip to buffer size - crop.IntersectRect(crop, ThebesRect(aBufferRect)); - crop.Round(); - - if (crop.IsEmpty()) { - return false; - } - - //propagate buffer clipping back to visible rect - gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform); - visibleRectScreen = layerBufferTransform.TransformBounds(crop); - visibleRectScreen.Round(); - - // Map from layer space to buffer space - crop -= aBufferRect.TopLeft(); - if (aYFlipped) { - crop.y = aBufferRect.height - (crop.y + crop.height); - } - - aSourceCrop->left = crop.x; - aSourceCrop->top = crop.y; - aSourceCrop->right = crop.x + crop.width; - aSourceCrop->bottom = crop.y + crop.height; - - aVisibleRegionScreen->left = visibleRectScreen.x; - aVisibleRegionScreen->top = visibleRectScreen.y; - aVisibleRegionScreen->right = visibleRectScreen.x + visibleRectScreen.width; - aVisibleRegionScreen->bottom = visibleRectScreen.y + visibleRectScreen.height; - - return true; -} - -/* static */ bool -HwcUtils::PrepareVisibleRegion(const nsIntRegion& aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - RectVector* aVisibleRegionScreen, - bool& aIsVisible) { - const float MIN_SRC_WIDTH = 2.f; - const float MIN_SRC_HEIGHT = 2.f; - - gfxMatrix layerTransform = gfx::ThebesMatrix(aLayerTransform); - gfxMatrix layerBufferTransform = gfx::ThebesMatrix(aLayerBufferTransform); - gfxRect bufferRect = - layerBufferTransform.TransformBounds(ThebesRect(aBufferRect)); - gfxMatrix inverse = gfx::ThebesMatrix(aLayerBufferTransform); - inverse.Invert(); - aIsVisible = false; - - for (auto iter = aVisible.RectIter(); !iter.Done(); iter.Next()) { - gfxRect screenRect = - layerTransform.TransformBounds(ThebesRect(iter.Get())); - screenRect.IntersectRect(screenRect, bufferRect); - screenRect.IntersectRect(screenRect, ThebesRect(aClip)); - screenRect.Round(); - if (screenRect.IsEmpty()) { - continue; - } - - hwc_rect_t visibleRectScreen; - visibleRectScreen.left = screenRect.x; - visibleRectScreen.top = screenRect.y; - visibleRectScreen.right = screenRect.XMost(); - visibleRectScreen.bottom = screenRect.YMost(); - - gfxRect srcCrop = inverse.TransformBounds(screenRect); - // When src crop is very small, HWC could not render correctly in some cases. - // See Bug 1169093 - if(srcCrop.Width() < MIN_SRC_WIDTH || srcCrop.Height() < MIN_SRC_HEIGHT) { - return false; - } - - aVisibleRegionScreen->push_back(visibleRectScreen); - aIsVisible = true; - } - - return true; -} - -/* static */ bool -HwcUtils::CalculateClipRect(const gfx::Matrix& transform, - const nsIntRect* aLayerClip, - nsIntRect aParentClip, nsIntRect* aRenderClip) { - - gfxMatrix aTransform = gfx::ThebesMatrix(transform); - *aRenderClip = aParentClip; - - if (!aLayerClip) { - return true; - } - - if (aLayerClip->IsEmpty()) { - return false; - } - - nsIntRect clip = *aLayerClip; - - gfxRect r = ThebesRect(clip); - gfxRect trClip = aTransform.TransformBounds(r); - trClip.Round(); - gfxUtils::GfxRectToIntRect(trClip, &clip); - - aRenderClip->IntersectRect(*aRenderClip, clip); - return true; -} - -} // namespace mozilla diff --git a/widget/gonk/HwcUtils.h b/widget/gonk/HwcUtils.h deleted file mode 100644 index 876ff8e99..000000000 --- a/widget/gonk/HwcUtils.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcUtils -#define mozilla_HwcUtils - -#include "Layers.h" -#include -#include "hardware/hwcomposer.h" - -namespace mozilla { - -namespace gfx { -class Matrix; -} - -class HwcUtils { -public: - -enum { - HWC_USE_GPU = HWC_FRAMEBUFFER, - HWC_USE_OVERLAY = HWC_OVERLAY, - HWC_USE_COPYBIT -}; - -// HWC layer flags -enum { - // Draw a solid color rectangle - // The color should be set on the transform member of the hwc_layer_t struct - // The expected format is a 32 bit ABGR with 8 bits per component - HWC_COLOR_FILL = 0x8, - // Swap the RB pixels of gralloc buffer, like RGBA<->BGRA or RGBX<->BGRX - // The flag will be set inside LayerRenderState - HWC_FORMAT_RB_SWAP = 0x40 -}; - -typedef std::vector RectVector; - -/* Utility functions - implemented in HwcUtils.cpp */ - -/** - * Calculates the layer's clipping rectangle - * - * @param aTransform Input. A transformation matrix - * It transforms the clip rect to screen space - * @param aLayerClip Input. The layer's internal clipping rectangle. - * This may be NULL which means the layer has no internal clipping - * The origin is the top-left corner of the layer - * @param aParentClip Input. The parent layer's rendering clipping rectangle - * The origin is the top-left corner of the screen - * @param aRenderClip Output. The layer's rendering clipping rectangle - * The origin is the top-left corner of the screen - * @return true if the layer should be rendered. - * false if the layer can be skipped - */ -static bool CalculateClipRect(const gfx::Matrix& aTransform, - const nsIntRect* aLayerClip, - nsIntRect aParentClip, nsIntRect* aRenderClip); - - -/** - * Prepares hwc layer visible region required for hwc composition - * - * @param aVisible Input. Layer's unclipped visible region - * The origin is the top-left corner of the layer - * @param aLayerTransform Input. Layer's transformation matrix - * It transforms from layer space to screen space - * @param aLayerBufferTransform Input. Layer buffer's transformation matrix - * It transforms from layer buffer's space to screen space - * @param aClip Input. A clipping rectangle. - * The origin is the top-left corner of the screen - * @param aBufferRect Input. The layer's buffer bounds - * The origin is the top-left corner of the layer - * @param aVisibleRegionScreen Output. Visible region in screen space. - * The origin is the top-left corner of the screen - * @param aIsVisible Output. true if region is visible - * false if region is not visible - * @return true if region can be rendered by HWC. - * false if region should not be rendered by HWC - */ -static bool PrepareVisibleRegion(const nsIntRegion& aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - RectVector* aVisibleRegionScreen, - bool& aIsVisible); - - -/** - * Sets hwc layer rectangles required for hwc composition - * - * @param aVisible Input. Layer's unclipped visible rectangle - * The origin is the top-left corner of the layer - * @param aLayerTransform Input. Layer's transformation matrix - * It transforms from layer space to screen space - * @param aLayerBufferTransform Input. Layer buffer's transformation matrix - * It transforms from layer buffer's space to screen space - * @param aClip Input. A clipping rectangle. - * The origin is the top-left corner of the screen - * @param aBufferRect Input. The layer's buffer bounds - * The origin is the top-left corner of the layer - * @param aYFlipped Input. true if the buffer is rendered as Y flipped - * @param aSurceCrop Output. Area of the source to consider, - * the origin is the top-left corner of the buffer - * @param aVisibleRegionScreen Output. Visible region in screen space. - * The origin is the top-left corner of the screen - * @return true if the layer should be rendered. - * false if the layer can be skipped - */ -static bool PrepareLayerRects(nsIntRect aVisible, - const gfx::Matrix& aLayerTransform, - const gfx::Matrix& aLayerBufferTransform, - nsIntRect aClip, nsIntRect aBufferRect, - bool aYFlipped, - hwc_rect_t* aSourceCrop, - hwc_rect_t* aVisibleRegionScreen); - -}; - -} // namespace mozilla - -#endif // mozilla_HwcUtils diff --git a/widget/gonk/OrientationObserver.cpp b/widget/gonk/OrientationObserver.cpp deleted file mode 100644 index 9096404cf..000000000 --- a/widget/gonk/OrientationObserver.cpp +++ /dev/null @@ -1,332 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "base/basictypes.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/StaticPtr.h" -#include "mozilla/Hal.h" -#include "nsIScreen.h" -#include "nsIScreenManager.h" -#include "OrientationObserver.h" -#include "mozilla/HalSensor.h" -#include "ProcessOrientation.h" -#include "nsServiceManagerUtils.h" - -using namespace mozilla; -using namespace dom; - -namespace { - -struct OrientationMapping { - uint32_t mScreenRotation; - ScreenOrientationInternal mDomOrientation; -}; - -static OrientationMapping sOrientationMappings[] = { - {nsIScreen::ROTATION_0_DEG, eScreenOrientation_PortraitPrimary}, - {nsIScreen::ROTATION_180_DEG, eScreenOrientation_PortraitSecondary}, - {nsIScreen::ROTATION_90_DEG, eScreenOrientation_LandscapePrimary}, - {nsIScreen::ROTATION_270_DEG, eScreenOrientation_LandscapeSecondary}, -}; - -const static uint32_t sDefaultLandscape = 2; -const static uint32_t sDefaultPortrait = 0; - -static uint32_t sOrientationOffset = 0; - -static already_AddRefed -GetPrimaryScreen() -{ - nsCOMPtr screenMgr = - do_GetService("@mozilla.org/gfx/screenmanager;1"); - NS_ENSURE_TRUE(screenMgr, nullptr); - - nsCOMPtr screen; - screenMgr->GetPrimaryScreen(getter_AddRefs(screen)); - return screen.forget(); -} - -static void -DetectDefaultOrientation() -{ - nsCOMPtr screen = GetPrimaryScreen(); - if (!screen) { - return; - } - - int32_t left, top, width, height; - if (NS_FAILED(screen->GetRect(&left, &top, &width, &height))) { - return; - } - - uint32_t rotation; - if (NS_FAILED(screen->GetRotation(&rotation))) { - return; - } - - if (width < height) { - if (rotation == nsIScreen::ROTATION_0_DEG || - rotation == nsIScreen::ROTATION_180_DEG) { - sOrientationOffset = sDefaultPortrait; - } else { - sOrientationOffset = sDefaultLandscape; - } - } else { - if (rotation == nsIScreen::ROTATION_0_DEG || - rotation == nsIScreen::ROTATION_180_DEG) { - sOrientationOffset = sDefaultLandscape; - } else { - sOrientationOffset = sDefaultPortrait; - } - } -} - -/** - * Converts DOM orientation to nsIScreen rotation. Portrait and Landscape are - * treated as PortraitPrimary and LandscapePrimary, respectively, during - * conversion. - * - * @param aOrientation DOM orientation e.g. - * dom::eScreenOrientation_PortraitPrimary. - * @param aResult output nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG. - * @return NS_OK on success. NS_ILLEGAL_VALUE on failure. - */ -static nsresult -ConvertToScreenRotation(ScreenOrientationInternal aOrientation, uint32_t *aResult) -{ - for (uint32_t i = 0; i < ArrayLength(sOrientationMappings); i++) { - if (aOrientation & sOrientationMappings[i].mDomOrientation) { - // Shift the mappings in sOrientationMappings so devices with default - // landscape orientation map landscape-primary to 0 degree and so forth. - int adjusted = (i + sOrientationOffset) % - ArrayLength(sOrientationMappings); - *aResult = sOrientationMappings[adjusted].mScreenRotation; - return NS_OK; - } - } - - *aResult = nsIScreen::ROTATION_0_DEG; - return NS_ERROR_ILLEGAL_VALUE; -} - -/** - * Converts nsIScreen rotation to DOM orientation. - * - * @param aRotation nsIScreen rotation e.g. nsIScreen::ROTATION_0_DEG. - * @param aResult output DOM orientation e.g. - * dom::eScreenOrientation_PortraitPrimary. - * @return NS_OK on success. NS_ILLEGAL_VALUE on failure. - */ -nsresult -ConvertToDomOrientation(uint32_t aRotation, ScreenOrientationInternal *aResult) -{ - for (uint32_t i = 0; i < ArrayLength(sOrientationMappings); i++) { - if (aRotation == sOrientationMappings[i].mScreenRotation) { - // Shift the mappings in sOrientationMappings so devices with default - // landscape orientation map 0 degree to landscape-primary and so forth. - int adjusted = (i + sOrientationOffset) % - ArrayLength(sOrientationMappings); - *aResult = sOrientationMappings[adjusted].mDomOrientation; - return NS_OK; - } - } - - *aResult = eScreenOrientation_None; - return NS_ERROR_ILLEGAL_VALUE; -} - -// Note that all operations with sOrientationSensorObserver -// should be on the main thread. -static StaticAutoPtr sOrientationSensorObserver; - -} // namespace - -OrientationObserver* -OrientationObserver::GetInstance() -{ - if (!sOrientationSensorObserver) { - sOrientationSensorObserver = new OrientationObserver(); - ClearOnShutdown(&sOrientationSensorObserver); - } - - return sOrientationSensorObserver; -} - -OrientationObserver::OrientationObserver() - : mAutoOrientationEnabled(false) - , mAllowedOrientations(sDefaultOrientations) - , mOrientation(new mozilla::ProcessOrientation()) -{ - DetectDefaultOrientation(); - - EnableAutoOrientation(); -} - -OrientationObserver::~OrientationObserver() -{ - if (mAutoOrientationEnabled) { - DisableAutoOrientation(); - } -} - -/* static */ void -OrientationObserver::ShutDown() -{ - if (!sOrientationSensorObserver) { - return; - } - - if (sOrientationSensorObserver->mAutoOrientationEnabled) { - sOrientationSensorObserver->DisableAutoOrientation(); - } -} - -void -OrientationObserver::Notify(const hal::SensorData& aSensorData) -{ - // Sensor will call us on the main thread. - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aSensorData.sensor() == hal::SensorType::SENSOR_ACCELERATION); - - nsCOMPtr screen = GetPrimaryScreen(); - if (!screen) { - return; - } - - uint32_t currRotation; - if(NS_FAILED(screen->GetRotation(&currRotation))) { - return; - } - - int rotation = mOrientation->OnSensorChanged(aSensorData, static_cast(currRotation)); - if (rotation < 0 || uint32_t(rotation) == currRotation) { - return; - } - - ScreenOrientationInternal orientation; - if (NS_FAILED(ConvertToDomOrientation(rotation, &orientation))) { - return; - } - - if ((mAllowedOrientations & orientation) == eScreenOrientation_None) { - // The orientation from sensor is not allowed. - return; - } - - if (NS_FAILED(screen->SetRotation(static_cast(rotation)))) { - // Don't notify dom on rotation failure. - return; - } -} - -/** - * Register the observer. Note that the observer shouldn't be registered. - */ -void -OrientationObserver::EnableAutoOrientation() -{ - MOZ_ASSERT(NS_IsMainThread() && !mAutoOrientationEnabled); - - mOrientation->Reset(); - hal::RegisterSensorObserver(hal::SENSOR_ACCELERATION, this); - mAutoOrientationEnabled = true; -} - -/** - * Unregister the observer. Note that the observer should already be registered. - */ -void -OrientationObserver::DisableAutoOrientation() -{ - MOZ_ASSERT(NS_IsMainThread() && mAutoOrientationEnabled); - - hal::UnregisterSensorObserver(hal::SENSOR_ACCELERATION, this); - mAutoOrientationEnabled = false; -} - -bool -OrientationObserver::LockScreenOrientation(ScreenOrientationInternal aOrientation) -{ - MOZ_ASSERT(aOrientation | (eScreenOrientation_PortraitPrimary | - eScreenOrientation_PortraitSecondary | - eScreenOrientation_LandscapePrimary | - eScreenOrientation_LandscapeSecondary | - eScreenOrientation_Default)); - - if (aOrientation == eScreenOrientation_Default) { - aOrientation = (sOrientationOffset == sDefaultPortrait) ? - eScreenOrientation_PortraitPrimary : - eScreenOrientation_LandscapePrimary; - } - - // If there are multiple orientations allowed, we should enable the - // auto-rotation. - if (aOrientation != eScreenOrientation_LandscapePrimary && - aOrientation != eScreenOrientation_LandscapeSecondary && - aOrientation != eScreenOrientation_PortraitPrimary && - aOrientation != eScreenOrientation_PortraitSecondary) { - if (!mAutoOrientationEnabled) { - EnableAutoOrientation(); - } - } else if (mAutoOrientationEnabled) { - DisableAutoOrientation(); - } - - mAllowedOrientations = aOrientation; - - nsCOMPtr screen = GetPrimaryScreen(); - NS_ENSURE_TRUE(screen, false); - - uint32_t currRotation; - nsresult rv = screen->GetRotation(&currRotation); - NS_ENSURE_SUCCESS(rv, false); - - ScreenOrientationInternal currOrientation = eScreenOrientation_None; - rv = ConvertToDomOrientation(currRotation, &currOrientation); - NS_ENSURE_SUCCESS(rv, false); - - // Don't rotate if the current orientation matches one of the - // requested orientations. - if (currOrientation & aOrientation) { - return true; - } - - // Return false on invalid orientation value. - uint32_t rotation; - rv = ConvertToScreenRotation(aOrientation, &rotation); - NS_ENSURE_SUCCESS(rv, false); - - rv = screen->SetRotation(rotation); - NS_ENSURE_SUCCESS(rv, false); - - // This conversion will disambiguate aOrientation. - ScreenOrientationInternal orientation; - rv = ConvertToDomOrientation(rotation, &orientation); - NS_ENSURE_SUCCESS(rv, false); - - return true; -} - -void -OrientationObserver::UnlockScreenOrientation() -{ - if (!mAutoOrientationEnabled) { - EnableAutoOrientation(); - } - - mAllowedOrientations = sDefaultOrientations; -} diff --git a/widget/gonk/OrientationObserver.h b/widget/gonk/OrientationObserver.h deleted file mode 100644 index c841ea878..000000000 --- a/widget/gonk/OrientationObserver.h +++ /dev/null @@ -1,71 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* vim: set sw=2 ts=8 et ft=cpp : */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef OrientationObserver_h -#define OrientationObserver_h - -#include "mozilla/Observer.h" -#include "mozilla/dom/ScreenOrientation.h" -#include "mozilla/UniquePtr.h" - -namespace mozilla { -class ProcessOrientation; -namespace hal { -class SensorData; -typedef mozilla::Observer ISensorObserver; -} // namespace hal -} // namespace mozilla - -using mozilla::hal::ISensorObserver; -using mozilla::hal::SensorData; -using mozilla::dom::ScreenOrientationInternal; - -class OrientationObserver : public ISensorObserver { -public: - OrientationObserver(); - ~OrientationObserver(); - - // Call DisableAutoOrientation on the existing OrientatiOnobserver singleton, - // if it exists. If no OrientationObserver exists, do nothing. - static void ShutDown(); - - // Notification from sensor. - void Notify(const SensorData& aSensorData); - - // Methods to enable/disable automatic orientation. - void EnableAutoOrientation(); - void DisableAutoOrientation(); - - // Methods called by methods in hal_impl namespace. - bool LockScreenOrientation(ScreenOrientationInternal aOrientation); - void UnlockScreenOrientation(); - - static OrientationObserver* GetInstance(); - -private: - bool mAutoOrientationEnabled; - uint32_t mAllowedOrientations; - mozilla::UniquePtr mOrientation; - - static const uint32_t sDefaultOrientations = - mozilla::dom::eScreenOrientation_PortraitPrimary | - mozilla::dom::eScreenOrientation_PortraitSecondary | - mozilla::dom::eScreenOrientation_LandscapePrimary | - mozilla::dom::eScreenOrientation_LandscapeSecondary; -}; - -#endif diff --git a/widget/gonk/ProcessOrientation.cpp b/widget/gonk/ProcessOrientation.cpp deleted file mode 100644 index bbdcface8..000000000 --- a/widget/gonk/ProcessOrientation.cpp +++ /dev/null @@ -1,519 +0,0 @@ -/* - * Copyright (c) 2013, Linux Foundation. All rights reserved - * - * Copyright (C) 2008 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. - */ - -#include "base/basictypes.h" -#include "mozilla/Hal.h" -#include "mozilla/Unused.h" -#include "nsIScreen.h" -#include "nsIScreenManager.h" -#include "OrientationObserver.h" -#include "ProcessOrientation.h" -#include "mozilla/HalSensor.h" -#include "math.h" -#include "limits.h" -#include "android/log.h" - -#if 0 -#define LOGD(args...) __android_log_print(ANDROID_LOG_DEBUG, "ProcessOrientation" , ## args) -#else -#define LOGD(args...) -#endif - -namespace mozilla { - -// We work with all angles in degrees in this class. -#define RADIANS_TO_DEGREES (180/M_PI) - -// Number of nanoseconds per millisecond. -#define NANOS_PER_MS 1000000 - -// Indices into SensorEvent.values for the accelerometer sensor. -#define ACCELEROMETER_DATA_X 0 -#define ACCELEROMETER_DATA_Y 1 -#define ACCELEROMETER_DATA_Z 2 - -// The minimum amount of time that a predicted rotation must be stable before -// it is accepted as a valid rotation proposal. This value can be quite small -// because the low-pass filter already suppresses most of the noise so we're -// really just looking for quick confirmation that the last few samples are in -// agreement as to the desired orientation. -#define PROPOSAL_SETTLE_TIME_NANOS (40*NANOS_PER_MS) - -// The minimum amount of time that must have elapsed since the device last -// exited the flat state (time since it was picked up) before the proposed -// rotation can change. -#define PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS (500*NANOS_PER_MS) - -// The minimum amount of time that must have elapsed since the device stopped -// swinging (time since device appeared to be in the process of being put down -// or put away into a pocket) before the proposed rotation can change. -#define PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS (300*NANOS_PER_MS) - -// The minimum amount of time that must have elapsed since the device stopped -// undergoing external acceleration before the proposed rotation can change. -#define PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS (500*NANOS_PER_MS) - -// If the tilt angle remains greater than the specified angle for a minimum of -// the specified time, then the device is deemed to be lying flat -// (just chillin' on a table). -#define FLAT_ANGLE 75 -#define FLAT_TIME_NANOS (1000*NANOS_PER_MS) - -// If the tilt angle has increased by at least delta degrees within the -// specified amount of time, then the device is deemed to be swinging away -// from the user down towards flat (tilt = 90). -#define SWING_AWAY_ANGLE_DELTA 20 -#define SWING_TIME_NANOS (300*NANOS_PER_MS) - -// The maximum sample inter-arrival time in milliseconds. If the acceleration -// samples are further apart than this amount in time, we reset the state of -// the low-pass filter and orientation properties. This helps to handle -// boundary conditions when the device is turned on, wakes from suspend or -// there is a significant gap in samples. -#define MAX_FILTER_DELTA_TIME_NANOS (1000*NANOS_PER_MS) - -// The acceleration filter time constant. -// -// This time constant is used to tune the acceleration filter such that -// impulses and vibrational noise (think car dock) is suppressed before we try -// to calculate the tilt and orientation angles. -// -// The filter time constant is related to the filter cutoff frequency, which -// is the frequency at which signals are attenuated by 3dB (half the passband -// power). Each successive octave beyond this frequency is attenuated by an -// additional 6dB. -// -// Given a time constant t in seconds, the filter cutoff frequency Fc in Hertz -// is given by Fc = 1 / (2pi * t). -// -// The higher the time constant, the lower the cutoff frequency, so more noise -// will be suppressed. -// -// Filtering adds latency proportional the time constant (inversely -// proportional to the cutoff frequency) so we don't want to make the time -// constant too large or we can lose responsiveness. Likewise we don't want -// to make it too small or we do a poor job suppressing acceleration spikes. -// Empirically, 100ms seems to be too small and 500ms is too large. Android -// default is 200. -#define FILTER_TIME_CONSTANT_MS 200.0f - -// State for orientation detection. Thresholds for minimum and maximum -// allowable deviation from gravity. -// -// If the device is undergoing external acceleration (being bumped, in a car -// that is turning around a corner or a plane taking off) then the magnitude -// may be substantially more or less than gravity. This can skew our -// orientation detection by making us think that up is pointed in a different -// direction. -// -// Conversely, if the device is in freefall, then there will be no gravity to -// measure at all. This is problematic because we cannot detect the orientation -// without gravity to tell us which way is up. A magnitude near 0 produces -// singularities in the tilt and orientation calculations. -// -// In both cases, we postpone choosing an orientation. -// -// However, we need to tolerate some acceleration because the angular momentum -// of turning the device can skew the observed acceleration for a short period -// of time. -#define NEAR_ZERO_MAGNITUDE 1 // m/s^2 -#define ACCELERATION_TOLERANCE 4 // m/s^2 -#define STANDARD_GRAVITY 9.80665f -#define MIN_ACCELERATION_MAGNITUDE (STANDARD_GRAVITY-ACCELERATION_TOLERANCE) -#define MAX_ACCELERATION_MAGNITUDE (STANDARD_GRAVITY+ACCELERATION_TOLERANCE) - -// Maximum absolute tilt angle at which to consider orientation data. Beyond -// this (i.e. when screen is facing the sky or ground), we completely ignore -// orientation data. -#define MAX_TILT 75 - -// The gap angle in degrees between adjacent orientation angles for -// hysteresis.This creates a "dead zone" between the current orientation and a -// proposed adjacent orientation. No orientation proposal is made when the -// orientation angle is within the gap between the current orientation and the -// adjacent orientation. -#define ADJACENT_ORIENTATION_ANGLE_GAP 45 - -const int -ProcessOrientation::tiltTolerance[][4] = { - {-25, 70}, // ROTATION_0 - {-25, 65}, // ROTATION_90 - {-25, 60}, // ROTATION_180 - {-25, 65} // ROTATION_270 -}; - -int -ProcessOrientation::GetProposedRotation() -{ - return mProposedRotation; -} - -int -ProcessOrientation::OnSensorChanged(const SensorData& event, - int deviceCurrentRotation) -{ - // The vector given in the SensorEvent points straight up (towards the sky) - // under ideal conditions (the phone is not accelerating). I'll call this up - // vector elsewhere. - const InfallibleTArray& values = event.values(); - float x = values[ACCELEROMETER_DATA_X]; - float y = values[ACCELEROMETER_DATA_Y]; - float z = values[ACCELEROMETER_DATA_Z]; - - LOGD - ("ProcessOrientation: Raw acceleration vector: x = %f, y = %f, z = %f," - "magnitude = %f\n", x, y, z, sqrt(x * x + y * y + z * z)); - // Apply a low-pass filter to the acceleration up vector in cartesian space. - // Reset the orientation listener state if the samples are too far apart in - // time or when we see values of (0, 0, 0) which indicates that we polled the - // accelerometer too soon after turning it on and we don't have any data yet. - const int64_t now = (int64_t) event.timestamp(); - const int64_t then = mLastFilteredTimestampNanos; - const float timeDeltaMS = (now - then) * 0.000001f; - bool skipSample = false; - if (now < then - || now > then + MAX_FILTER_DELTA_TIME_NANOS - || (x == 0 && y == 0 && z == 0)) { - LOGD - ("ProcessOrientation: Resetting orientation listener."); - Reset(); - skipSample = true; - } else { - const float alpha = timeDeltaMS / (FILTER_TIME_CONSTANT_MS + timeDeltaMS); - x = alpha * (x - mLastFilteredX) + mLastFilteredX; - y = alpha * (y - mLastFilteredY) + mLastFilteredY; - z = alpha * (z - mLastFilteredZ) + mLastFilteredZ; - LOGD - ("ProcessOrientation: Filtered acceleration vector: x=%f, y=%f, z=%f," - "magnitude=%f", z, y, z, sqrt(x * x + y * y + z * z)); - skipSample = false; - } - mLastFilteredTimestampNanos = now; - mLastFilteredX = x; - mLastFilteredY = y; - mLastFilteredZ = z; - - bool isAccelerating = false; - bool isFlat = false; - bool isSwinging = false; - if (skipSample) { - return -1; - } - - // Calculate the magnitude of the acceleration vector. - const float magnitude = sqrt(x * x + y * y + z * z); - if (magnitude < NEAR_ZERO_MAGNITUDE) { - LOGD - ("ProcessOrientation: Ignoring sensor data, magnitude too close to" - " zero."); - ClearPredictedRotation(); - } else { - // Determine whether the device appears to be undergoing external - // acceleration. - if (this->IsAccelerating(magnitude)) { - isAccelerating = true; - mAccelerationTimestampNanos = now; - } - // Calculate the tilt angle. This is the angle between the up vector and - // the x-y plane (the plane of the screen) in a range of [-90, 90] - // degrees. - // -90 degrees: screen horizontal and facing the ground (overhead) - // 0 degrees: screen vertical - // 90 degrees: screen horizontal and facing the sky (on table) - const int tiltAngle = - static_cast(roundf(asin(z / magnitude) * RADIANS_TO_DEGREES)); - AddTiltHistoryEntry(now, tiltAngle); - - // Determine whether the device appears to be flat or swinging. - if (this->IsFlat(now)) { - isFlat = true; - mFlatTimestampNanos = now; - } - if (this->IsSwinging(now, tiltAngle)) { - isSwinging = true; - mSwingTimestampNanos = now; - } - // If the tilt angle is too close to horizontal then we cannot determine - // the orientation angle of the screen. - if (abs(tiltAngle) > MAX_TILT) { - LOGD - ("ProcessOrientation: Ignoring sensor data, tilt angle too high:" - " tiltAngle=%d", tiltAngle); - ClearPredictedRotation(); - } else { - // Calculate the orientation angle. - // This is the angle between the x-y projection of the up vector onto - // the +y-axis, increasing clockwise in a range of [0, 360] degrees. - int orientationAngle = - static_cast(roundf(-atan2f(-x, y) * RADIANS_TO_DEGREES)); - if (orientationAngle < 0) { - // atan2 returns [-180, 180]; normalize to [0, 360] - orientationAngle += 360; - } - // Find the nearest rotation. - int nearestRotation = (orientationAngle + 45) / 90; - if (nearestRotation == 4) { - nearestRotation = 0; - } - // Determine the predicted orientation. - if (IsTiltAngleAcceptable(nearestRotation, tiltAngle) - && - IsOrientationAngleAcceptable - (nearestRotation, orientationAngle, deviceCurrentRotation)) { - UpdatePredictedRotation(now, nearestRotation); - LOGD - ("ProcessOrientation: Predicted: tiltAngle=%d, orientationAngle=%d," - " predictedRotation=%d, predictedRotationAgeMS=%f", - tiltAngle, - orientationAngle, - mPredictedRotation, - ((now - mPredictedRotationTimestampNanos) * 0.000001f)); - } else { - LOGD - ("ProcessOrientation: Ignoring sensor data, no predicted rotation:" - " tiltAngle=%d, orientationAngle=%d", - tiltAngle, - orientationAngle); - ClearPredictedRotation(); - } - } - } - - // Determine new proposed rotation. - const int oldProposedRotation = mProposedRotation; - if (mPredictedRotation < 0 || IsPredictedRotationAcceptable(now)) { - mProposedRotation = mPredictedRotation; - } - // Write final statistics about where we are in the orientation detection - // process. - LOGD - ("ProcessOrientation: Result: oldProposedRotation=%d,currentRotation=%d, " - "proposedRotation=%d, predictedRotation=%d, timeDeltaMS=%f, " - "isAccelerating=%d, isFlat=%d, isSwinging=%d, timeUntilSettledMS=%f, " - "timeUntilAccelerationDelayExpiredMS=%f, timeUntilFlatDelayExpiredMS=%f, " - "timeUntilSwingDelayExpiredMS=%f", - oldProposedRotation, - deviceCurrentRotation, mProposedRotation, - mPredictedRotation, timeDeltaMS, isAccelerating, isFlat, - isSwinging, RemainingMS(now, - mPredictedRotationTimestampNanos + - PROPOSAL_SETTLE_TIME_NANOS), - RemainingMS(now, - mAccelerationTimestampNanos + - PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS), - RemainingMS(now, - mFlatTimestampNanos + - PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS), - RemainingMS(now, - mSwingTimestampNanos + - PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS)); - - // Avoid unused-but-set compile warnings for these variables, when LOGD is - // a no-op, as it is by default: - Unused << isAccelerating; - Unused << isFlat; - Unused << isSwinging; - - // Tell the listener. - if (mProposedRotation != oldProposedRotation && mProposedRotation >= 0) { - LOGD - ("ProcessOrientation: Proposed rotation changed! proposedRotation=%d, " - "oldProposedRotation=%d", - mProposedRotation, - oldProposedRotation); - return mProposedRotation; - } - // Don't rotate screen - return -1; -} - -bool -ProcessOrientation::IsTiltAngleAcceptable(int rotation, int tiltAngle) -{ - return (tiltAngle >= tiltTolerance[rotation][0] - && tiltAngle <= tiltTolerance[rotation][1]); -} - -bool -ProcessOrientation::IsOrientationAngleAcceptable(int rotation, - int orientationAngle, - int currentRotation) -{ - // If there is no current rotation, then there is no gap. - // The gap is used only to introduce hysteresis among advertised orientation - // changes to avoid flapping. - if (currentRotation < 0) { - return true; - } - // If the specified rotation is the same or is counter-clockwise adjacent - // to the current rotation, then we set a lower bound on the orientation - // angle. For example, if currentRotation is ROTATION_0 and proposed is - // ROTATION_90, then we want to check orientationAngle > 45 + GAP / 2. - if (rotation == currentRotation || rotation == (currentRotation + 1) % 4) { - int lowerBound = rotation * 90 - 45 + ADJACENT_ORIENTATION_ANGLE_GAP / 2; - if (rotation == 0) { - if (orientationAngle >= 315 && orientationAngle < lowerBound + 360) { - return false; - } - } else { - if (orientationAngle < lowerBound) { - return false; - } - } - } - // If the specified rotation is the same or is clockwise adjacent, then we - // set an upper bound on the orientation angle. For example, if - // currentRotation is ROTATION_0 and rotation is ROTATION_270, then we want - // to check orientationAngle < 315 - GAP / 2. - if (rotation == currentRotation || rotation == (currentRotation + 3) % 4) { - int upperBound = rotation * 90 + 45 - ADJACENT_ORIENTATION_ANGLE_GAP / 2; - if (rotation == 0) { - if (orientationAngle <= 45 && orientationAngle > upperBound) { - return false; - } - } else { - if (orientationAngle > upperBound) { - return false; - } - } - } - return true; -} - -bool -ProcessOrientation::IsPredictedRotationAcceptable(int64_t now) -{ - // The predicted rotation must have settled long enough. - if (now < mPredictedRotationTimestampNanos + PROPOSAL_SETTLE_TIME_NANOS) { - return false; - } - // The last flat state (time since picked up) must have been sufficiently long - // ago. - if (now < mFlatTimestampNanos + PROPOSAL_MIN_TIME_SINCE_FLAT_ENDED_NANOS) { - return false; - } - // The last swing state (time since last movement to put down) must have been - // sufficiently long ago. - if (now < mSwingTimestampNanos + PROPOSAL_MIN_TIME_SINCE_SWING_ENDED_NANOS) { - return false; - } - // The last acceleration state must have been sufficiently long ago. - if (now < mAccelerationTimestampNanos - + PROPOSAL_MIN_TIME_SINCE_ACCELERATION_ENDED_NANOS) { - return false; - } - // Looks good! - return true; -} - -int -ProcessOrientation::Reset() -{ - mLastFilteredTimestampNanos = std::numeric_limits::min(); - mProposedRotation = -1; - mFlatTimestampNanos = std::numeric_limits::min(); - mSwingTimestampNanos = std::numeric_limits::min(); - mAccelerationTimestampNanos = std::numeric_limits::min(); - ClearPredictedRotation(); - ClearTiltHistory(); - return -1; -} - -void -ProcessOrientation::ClearPredictedRotation() -{ - mPredictedRotation = -1; - mPredictedRotationTimestampNanos = std::numeric_limits::min(); -} - -void -ProcessOrientation::UpdatePredictedRotation(int64_t now, int rotation) -{ - if (mPredictedRotation != rotation) { - mPredictedRotation = rotation; - mPredictedRotationTimestampNanos = now; - } -} - -bool -ProcessOrientation::IsAccelerating(float magnitude) -{ - return magnitude < MIN_ACCELERATION_MAGNITUDE - || magnitude > MAX_ACCELERATION_MAGNITUDE; -} - -void -ProcessOrientation::ClearTiltHistory() -{ - mTiltHistory.history[0].timestampNanos = std::numeric_limits::min(); - mTiltHistory.index = 1; -} - -void -ProcessOrientation::AddTiltHistoryEntry(int64_t now, float tilt) -{ - mTiltHistory.history[mTiltHistory.index].tiltAngle = tilt; - mTiltHistory.history[mTiltHistory.index].timestampNanos = now; - mTiltHistory.index = (mTiltHistory.index + 1) % TILT_HISTORY_SIZE; - mTiltHistory.history[mTiltHistory.index].timestampNanos = std::numeric_limits::min(); -} - -bool -ProcessOrientation::IsFlat(int64_t now) -{ - for (int i = mTiltHistory.index; (i = NextTiltHistoryIndex(i)) >= 0;) { - if (mTiltHistory.history[i].tiltAngle < FLAT_ANGLE) { - break; - } - if (mTiltHistory.history[i].timestampNanos + FLAT_TIME_NANOS <= now) { - // Tilt has remained greater than FLAT_TILT_ANGLE for FLAT_TIME_NANOS. - return true; - } - } - return false; -} - -bool -ProcessOrientation::IsSwinging(int64_t now, float tilt) -{ - for (int i = mTiltHistory.index; (i = NextTiltHistoryIndex(i)) >= 0;) { - if (mTiltHistory.history[i].timestampNanos + SWING_TIME_NANOS < now) { - break; - } - if (mTiltHistory.history[i].tiltAngle + SWING_AWAY_ANGLE_DELTA <= tilt) { - // Tilted away by SWING_AWAY_ANGLE_DELTA within SWING_TIME_NANOS. - return true; - } - } - return false; -} - -int -ProcessOrientation::NextTiltHistoryIndex(int index) -{ - index = (index == 0 ? TILT_HISTORY_SIZE : index) - 1; - return mTiltHistory.history[index].timestampNanos != std::numeric_limits::min() ? index : -1; -} - -float -ProcessOrientation::RemainingMS(int64_t now, int64_t until) -{ - return now >= until ? 0 : (until - now) * 0.000001f; -} - -} // namespace mozilla diff --git a/widget/gonk/ProcessOrientation.h b/widget/gonk/ProcessOrientation.h deleted file mode 100644 index d6d4bc3b6..000000000 --- a/widget/gonk/ProcessOrientation.h +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2013, Linux Foundation. All rights reserved - * - * Copyright (C) 2008 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. - */ - -#ifndef ProcessOrientation_h -#define ProcessOrientation_h - -#include "mozilla/Hal.h" - -namespace mozilla { - -// History of observed tilt angles. -#define TILT_HISTORY_SIZE 40 - -class ProcessOrientation { -public: - ProcessOrientation() {}; - ~ProcessOrientation() {}; - - int OnSensorChanged(const mozilla::hal::SensorData& event, int deviceCurrentRotation); - int Reset(); - -private: - int GetProposedRotation(); - - // Returns true if the tilt angle is acceptable for a given predicted - // rotation. - bool IsTiltAngleAcceptable(int rotation, int tiltAngle); - - // Returns true if the orientation angle is acceptable for a given predicted - // rotation. This function takes into account the gap between adjacent - // orientations for hysteresis. - bool IsOrientationAngleAcceptable(int rotation, int orientationAngle, - int currentRotation); - - // Returns true if the predicted rotation is ready to be advertised as a - // proposed rotation. - bool IsPredictedRotationAcceptable(int64_t now); - - void ClearPredictedRotation(); - void UpdatePredictedRotation(int64_t now, int rotation); - bool IsAccelerating(float magnitude); - void ClearTiltHistory(); - void AddTiltHistoryEntry(int64_t now, float tilt); - bool IsFlat(int64_t now); - bool IsSwinging(int64_t now, float tilt); - int NextTiltHistoryIndex(int index); - float RemainingMS(int64_t now, int64_t until); - - // The tilt angle range in degrees for each orientation. Beyond these tilt - // angles, we don't even consider transitioning into the specified orientation. - // We place more stringent requirements on unnatural orientations than natural - // ones to make it less likely to accidentally transition into those states. - // The first value of each pair is negative so it applies a limit when the - // device is facing down (overhead reading in bed). The second value of each - // pair is positive so it applies a limit when the device is facing up - // (resting on a table). The ideal tilt angle is 0 (when the device is vertical) - // so the limits establish how close to vertical the device must be in order - // to change orientation. - static const int tiltTolerance[][4]; - - // Timestamp and value of the last accelerometer sample. - int64_t mLastFilteredTimestampNanos; - float mLastFilteredX, mLastFilteredY, mLastFilteredZ; - - // The last proposed rotation, -1 if unknown. - int mProposedRotation; - - // Value of the current predicted rotation, -1 if unknown. - int mPredictedRotation; - - // Timestamp of when the predicted rotation most recently changed. - int64_t mPredictedRotationTimestampNanos; - - // Timestamp when the device last appeared to be flat for sure (the flat delay - // elapsed). - int64_t mFlatTimestampNanos; - - // Timestamp when the device last appeared to be swinging. - int64_t mSwingTimestampNanos; - - // Timestamp when the device last appeared to be undergoing external - // acceleration. - int64_t mAccelerationTimestampNanos; - - struct { - struct { - float tiltAngle; - int64_t timestampNanos; - } history[TILT_HISTORY_SIZE]; - int index; - } mTiltHistory; -}; - -} // namespace mozilla - -#endif diff --git a/widget/gonk/WidgetTraceEvent.cpp b/widget/gonk/WidgetTraceEvent.cpp deleted file mode 100644 index 558d9313e..000000000 --- a/widget/gonk/WidgetTraceEvent.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "mozilla/WidgetTraceEvent.h" -#include "mozilla/StaticPtr.h" -#include "nsThreadUtils.h" -#include -#include - -using mozilla::CondVar; -using mozilla::Mutex; -using mozilla::MutexAutoLock; - -namespace mozilla { - class TracerRunnable : public Runnable { - public: - TracerRunnable() { - mTracerLock = new Mutex("TracerRunnable"); - mTracerCondVar = new CondVar(*mTracerLock, "TracerRunnable"); - mMainThread = do_GetMainThread(); - } - - ~TracerRunnable() { - delete mTracerCondVar; - delete mTracerLock; - mTracerLock = nullptr; - mTracerCondVar = nullptr; - } - - virtual nsresult Run() { - MutexAutoLock lock(*mTracerLock); - mHasRun = true; - mTracerCondVar->Notify(); - return NS_OK; - } - - bool Fire() { - if (!mTracerLock || !mTracerCondVar) { - return false; - } - - MutexAutoLock lock(*mTracerLock); - mHasRun = false; - mMainThread->Dispatch(this, NS_DISPATCH_NORMAL); - while (!mHasRun) { - mTracerCondVar->Wait(); - } - return true; - } - - void Signal() { - MutexAutoLock lock(*mTracerLock); - mHasRun = true; - mTracerCondVar->Notify(); - } - - private: - Mutex* mTracerLock; - CondVar* mTracerCondVar; - bool mHasRun; - nsCOMPtr mMainThread; - }; - - StaticRefPtr sTracerRunnable; - - bool InitWidgetTracing() - { - if (!sTracerRunnable) { - sTracerRunnable = new TracerRunnable(); - } - return true; - } - - void CleanUpWidgetTracing() - { - sTracerRunnable = nullptr; - } - - bool FireAndWaitForTracerEvent() - { - if (sTracerRunnable) { - return sTracerRunnable->Fire(); - } - - return false; - } - - void SignalTracerThread() - { - if (sTracerRunnable) { - return sTracerRunnable->Signal(); - } - } -} // namespace mozilla - diff --git a/widget/gonk/hwchal/HwcHAL.cpp b/widget/gonk/hwchal/HwcHAL.cpp deleted file mode 100644 index 1793b75e6..000000000 --- a/widget/gonk/hwchal/HwcHAL.cpp +++ /dev/null @@ -1,214 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#include "HwcHAL.h" -#include "libdisplay/GonkDisplay.h" -#include "mozilla/Assertions.h" - -namespace mozilla { - -HwcHAL::HwcHAL() - : HwcHALBase() -{ - // Some HALs don't want to open hwc twice. - // If GetDisplay already load hwc module, we don't need to load again - mHwc = (HwcDevice*)GetGonkDisplay()->GetHWCDevice(); - if (!mHwc) { - printf_stderr("HwcHAL Error: Cannot load hwcomposer"); - return; - } -} - -HwcHAL::~HwcHAL() -{ - mHwc = nullptr; -} - -bool -HwcHAL::Query(QueryType aType) -{ - if (!mHwc || !mHwc->query) { - return false; - } - - bool value = false; - int supported = 0; - if (mHwc->query(mHwc, static_cast(aType), &supported) == 0/*android::NO_ERROR*/) { - value = !!supported; - } - return value; -} - -int -HwcHAL::Set(HwcList *aList, - uint32_t aDisp) -{ - MOZ_ASSERT(mHwc); - if (!mHwc) { - return -1; - } - - HwcList *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; - displays[aDisp] = aList; - return mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); -} - -int -HwcHAL::ResetHwc() -{ - return Set(nullptr, HWC_DISPLAY_PRIMARY); -} - -int -HwcHAL::Prepare(HwcList *aList, - uint32_t aDisp, - hwc_rect_t aDispRect, - buffer_handle_t aHandle, - int aFenceFd) -{ - MOZ_ASSERT(mHwc); - if (!mHwc) { - printf_stderr("HwcHAL Error: HwcDevice doesn't exist. A fence might be leaked."); - return -1; - } - - HwcList *displays[HWC_NUM_DISPLAY_TYPES] = { nullptr }; - displays[aDisp] = aList; -#if ANDROID_VERSION >= 18 - aList->outbufAcquireFenceFd = -1; - aList->outbuf = nullptr; -#endif - aList->retireFenceFd = -1; - - const auto idx = aList->numHwLayers - 1; - aList->hwLayers[idx].hints = 0; - aList->hwLayers[idx].flags = 0; - aList->hwLayers[idx].transform = 0; - aList->hwLayers[idx].handle = aHandle; - aList->hwLayers[idx].blending = HWC_BLENDING_PREMULT; - aList->hwLayers[idx].compositionType = HWC_FRAMEBUFFER_TARGET; - SetCrop(aList->hwLayers[idx], aDispRect); - aList->hwLayers[idx].displayFrame = aDispRect; - aList->hwLayers[idx].visibleRegionScreen.numRects = 1; - aList->hwLayers[idx].visibleRegionScreen.rects = &aList->hwLayers[idx].displayFrame; - aList->hwLayers[idx].acquireFenceFd = aFenceFd; - aList->hwLayers[idx].releaseFenceFd = -1; -#if ANDROID_VERSION >= 18 - aList->hwLayers[idx].planeAlpha = 0xFF; -#endif - return mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); -} - -bool -HwcHAL::SupportTransparency() const -{ -#if ANDROID_VERSION >= 18 - return true; -#endif - return false; -} - -uint32_t -HwcHAL::GetGeometryChangedFlag(bool aGeometryChanged) const -{ -#if ANDROID_VERSION >= 19 - return aGeometryChanged ? HWC_GEOMETRY_CHANGED : 0; -#else - return HWC_GEOMETRY_CHANGED; -#endif -} - -void -HwcHAL::SetCrop(HwcLayer &aLayer, - const hwc_rect_t &aSrcCrop) const -{ - if (GetAPIVersion() >= HwcAPIVersion(1, 3)) { -#if ANDROID_VERSION >= 19 - aLayer.sourceCropf.left = aSrcCrop.left; - aLayer.sourceCropf.top = aSrcCrop.top; - aLayer.sourceCropf.right = aSrcCrop.right; - aLayer.sourceCropf.bottom = aSrcCrop.bottom; -#endif - } else { - aLayer.sourceCrop = aSrcCrop; - } -} - -bool -HwcHAL::EnableVsync(bool aEnable) -{ - // Only support hardware vsync on kitkat, L and up due to inaccurate timings - // with JellyBean. -#if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) - if (!mHwc) { - return false; - } - return !mHwc->eventControl(mHwc, - HWC_DISPLAY_PRIMARY, - HWC_EVENT_VSYNC, - aEnable); -#else - return false; -#endif -} - -bool -HwcHAL::RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) -{ - if (!mHwc || !mHwc->registerProcs) { - printf_stderr("Failed to get hwc\n"); - return false; - } - - // Disable Vsync first, and then register callback functions. - mHwc->eventControl(mHwc, - HWC_DISPLAY_PRIMARY, - HWC_EVENT_VSYNC, - false); - static const hwc_procs_t sHwcJBProcs = {aProcs.invalidate, - aProcs.vsync, - aProcs.hotplug}; - mHwc->registerProcs(mHwc, &sHwcJBProcs); - - // Only support hardware vsync on kitkat, L and up due to inaccurate timings - // with JellyBean. -#if (ANDROID_VERSION == 19 || ANDROID_VERSION >= 21) - return true; -#else - return false; -#endif -} - -uint32_t -HwcHAL::GetAPIVersion() const -{ - if (!mHwc) { - // default value: HWC_MODULE_API_VERSION_0_1 - return 1; - } - return mHwc->common.version; -} - -// Create HwcHAL -UniquePtr -HwcHALBase::CreateHwcHAL() -{ - return Move(MakeUnique()); -} - -} // namespace mozilla diff --git a/widget/gonk/hwchal/HwcHAL.h b/widget/gonk/hwchal/HwcHAL.h deleted file mode 100644 index 05cb6a45f..000000000 --- a/widget/gonk/hwchal/HwcHAL.h +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcHAL -#define mozilla_HwcHAL - -#include "HwcHALBase.h" - -namespace mozilla { - -class HwcHAL final : public HwcHALBase { -public: - explicit HwcHAL(); - - virtual ~HwcHAL(); - - virtual bool HasHwc() const override { return static_cast(mHwc); } - - virtual void SetEGLInfo(hwc_display_t aDpy, - hwc_surface_t aSur) override { } - - virtual bool Query(QueryType aType) override; - - virtual int Set(HwcList *aList, - uint32_t aDisp) override; - - virtual int ResetHwc() override; - - virtual int Prepare(HwcList *aList, - uint32_t aDisp, - hwc_rect_t aDispRect, - buffer_handle_t aHandle, - int aFenceFd) override; - - virtual bool SupportTransparency() const override; - - virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const override; - - virtual void SetCrop(HwcLayer &aLayer, - const hwc_rect_t &aSrcCrop) const override; - - virtual bool EnableVsync(bool aEnable) override; - - virtual bool RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) override; - -private: - uint32_t GetAPIVersion() const; - -private: - HwcDevice *mHwc = nullptr; -}; - -} // namespace mozilla - -#endif // mozilla_HwcHAL diff --git a/widget/gonk/hwchal/HwcHALBase.h b/widget/gonk/hwchal/HwcHALBase.h deleted file mode 100644 index 0ef00a325..000000000 --- a/widget/gonk/hwchal/HwcHALBase.h +++ /dev/null @@ -1,134 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:set ts=4 sw=4 sts=4 et: */ -/* - * Copyright (c) 2015 The Linux Foundation. All rights reserved. - * - * 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. - */ - -#ifndef mozilla_HwcHALBase -#define mozilla_HwcHALBase - -#include "mozilla/UniquePtr.h" -#include "nsRect.h" - -#include - -#ifndef HWC_BLIT -#if ANDROID_VERSION >= 21 -#define HWC_BLIT 0xFF -#elif ANDROID_VERSION >= 17 -#define HWC_BLIT (HWC_FRAMEBUFFER_TARGET + 1) -#else -// ICS didn't support this. However, we define this -// for passing compilation -#define HWC_BLIT 0xFF -#endif // #if ANDROID_VERSION -#endif // #ifndef HWC_BLIT - -namespace mozilla { - -#if ANDROID_VERSION >= 17 -using HwcDevice = hwc_composer_device_1_t; -using HwcList = hwc_display_contents_1_t; -using HwcLayer = hwc_layer_1_t; -#else -using HwcDevice = hwc_composer_device_t; -using HwcList = hwc_layer_list_t; -using HwcLayer = hwc_layer_t; -#endif - -// HwcHAL definition for HwcEvent callback types -// Note: hwc_procs is different between ICS and later, -// and the signature of invalidate is also different. -// Use this wrap struct to hide the detail. BTW, -// we don't have to register callback functions on ICS, so -// there is no callbacks for ICS in HwcHALProcs. -typedef struct HwcHALProcs { - void (*invalidate)(const struct hwc_procs* procs); - void (*vsync)(const struct hwc_procs* procs, int disp, int64_t timestamp); - void (*hotplug)(const struct hwc_procs* procs, int disp, int connected); -} HwcHALProcs_t; - -// HwcHAL class -// This class handle all the HAL related work -// The purpose of HwcHAL is to make HwcComposer2D simpler. -class HwcHALBase { - -public: - // Query Types. We can add more types easily in the future - enum class QueryType { - COLOR_FILL = 0x8, - RB_SWAP = 0x40 - }; - -public: - explicit HwcHALBase() = default; - - virtual ~HwcHALBase() {} - - // Create HwcHAL module, Only HwcComposer2D calls this. - // If other modules want to use HwcHAL, please use APIs in - // HwcComposer2D - static UniquePtr CreateHwcHAL(); - - // Check if mHwc exists - virtual bool HasHwc() const = 0; - - // Set EGL info (only ICS need this info) - virtual void SetEGLInfo(hwc_display_t aEGLDisplay, - hwc_surface_t aEGLSurface) = 0; - - // HwcDevice query properties - virtual bool Query(QueryType aType) = 0; - - // HwcDevice set - virtual int Set(HwcList *aList, - uint32_t aDisp) = 0; - - // Reset HwcDevice - virtual int ResetHwc() = 0; - - // HwcDevice prepare - virtual int Prepare(HwcList *aList, - uint32_t aDisp, - hwc_rect_t aDispRect, - buffer_handle_t aHandle, - int aFenceFd) = 0; - - // Check transparency support - virtual bool SupportTransparency() const = 0; - - // Get a geometry change flag - virtual uint32_t GetGeometryChangedFlag(bool aGeometryChanged) const = 0; - - // Set crop help - virtual void SetCrop(HwcLayer &aLayer, - const hwc_rect_t &aSrcCrop) const = 0; - - // Enable HW Vsync - virtual bool EnableVsync(bool aEnable) = 0; - - // Register HW event callback functions - virtual bool RegisterHwcEventCallback(const HwcHALProcs_t &aProcs) = 0; - -protected: - constexpr static uint32_t HwcAPIVersion(uint32_t aMaj, uint32_t aMin) { - // HARDWARE_MAKE_API_VERSION_2, from Android hardware.h - return (((aMaj & 0xff) << 24) | ((aMin & 0xff) << 16) | (1 & 0xffff)); - } -}; - -} // namespace mozilla - -#endif // mozilla_HwcHALBase diff --git a/widget/gonk/libdisplay/BootAnimation.cpp b/widget/gonk/libdisplay/BootAnimation.cpp deleted file mode 100644 index c275179fc..000000000 --- a/widget/gonk/libdisplay/BootAnimation.cpp +++ /dev/null @@ -1,726 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include "mozilla/FileUtils.h" -#include "png.h" - -#include "android/log.h" -#include "GonkDisplay.h" -#include "hardware/gralloc.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args) - -using namespace mozilla; -using namespace std; - -static pthread_t sAnimationThread; -static bool sRunAnimation; - -/* See http://www.pkware.com/documents/casestudies/APPNOTE.TXT */ -struct local_file_header { - uint32_t signature; - uint16_t min_version; - uint16_t general_flag; - uint16_t compression; - uint16_t lastmod_time; - uint16_t lastmod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_size; - uint16_t extra_field_size; - char data[0]; - - uint32_t GetDataSize() const - { - return letoh32(uncompressed_size); - } - - uint32_t GetSize() const - { - /* XXX account for data descriptor */ - return sizeof(local_file_header) + letoh16(filename_size) + - letoh16(extra_field_size) + GetDataSize(); - } - - const char * GetData() const - { - return data + letoh16(filename_size) + letoh16(extra_field_size); - } -} __attribute__((__packed__)); - -struct data_descriptor { - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; -} __attribute__((__packed__)); - -struct cdir_entry { - uint32_t signature; - uint16_t creator_version; - uint16_t min_version; - uint16_t general_flag; - uint16_t compression; - uint16_t lastmod_time; - uint16_t lastmod_date; - uint32_t crc32; - uint32_t compressed_size; - uint32_t uncompressed_size; - uint16_t filename_size; - uint16_t extra_field_size; - uint16_t file_comment_size; - uint16_t disk_num; - uint16_t internal_attr; - uint32_t external_attr; - uint32_t offset; - char data[0]; - - uint32_t GetDataSize() const - { - return letoh32(compressed_size); - } - - uint32_t GetSize() const - { - return sizeof(cdir_entry) + letoh16(filename_size) + - letoh16(extra_field_size) + letoh16(file_comment_size); - } - - bool Valid() const - { - return signature == htole32(0x02014b50); - } -} __attribute__((__packed__)); - -struct cdir_end { - uint32_t signature; - uint16_t disk_num; - uint16_t cdir_disk; - uint16_t disk_entries; - uint16_t cdir_entries; - uint32_t cdir_size; - uint32_t cdir_offset; - uint16_t comment_size; - char comment[0]; - - bool Valid() const - { - return signature == htole32(0x06054b50); - } -} __attribute__((__packed__)); - -/* We don't have access to libjar and the zip reader in android - * doesn't quite fit what we want to do. */ -class ZipReader { - const char *mBuf; - const cdir_end *mEnd; - const char *mCdir_limit; - uint32_t mBuflen; - -public: - ZipReader() : mBuf(nullptr) {} - ~ZipReader() { - if (mBuf) - munmap((void *)mBuf, mBuflen); - } - - bool OpenArchive(const char *path) - { - int fd; - do { - fd = open(path, O_RDONLY); - } while (fd == -1 && errno == EINTR); - if (fd == -1) - return false; - - struct stat sb; - if (fstat(fd, &sb) == -1 || sb.st_size < sizeof(cdir_end)) { - close(fd); - return false; - } - - mBuflen = sb.st_size; - mBuf = (char *)mmap(nullptr, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); - close(fd); - - if (!mBuf) { - return false; - } - - madvise(mBuf, sb.st_size, MADV_SEQUENTIAL); - - mEnd = (cdir_end *)(mBuf + mBuflen - sizeof(cdir_end)); - while (!mEnd->Valid() && - (char *)mEnd > mBuf) { - mEnd = (cdir_end *)((char *)mEnd - 1); - } - - mCdir_limit = mBuf + letoh32(mEnd->cdir_offset) + letoh32(mEnd->cdir_size); - - if (!mEnd->Valid() || mCdir_limit > (char *)mEnd) { - munmap((void *)mBuf, mBuflen); - mBuf = nullptr; - return false; - } - - return true; - } - - /* Pass null to get the first cdir entry */ - const cdir_entry * GetNextEntry(const cdir_entry *prev) - { - const cdir_entry *entry; - if (prev) - entry = (cdir_entry *)((char *)prev + prev->GetSize()); - else - entry = (cdir_entry *)(mBuf + letoh32(mEnd->cdir_offset)); - - if (((char *)entry + entry->GetSize()) > mCdir_limit || - !entry->Valid()) - return nullptr; - return entry; - } - - string GetEntryName(const cdir_entry *entry) - { - uint16_t len = letoh16(entry->filename_size); - - string name; - name.append(entry->data, len); - return name; - } - - const local_file_header * GetLocalEntry(const cdir_entry *entry) - { - const local_file_header * data = - (local_file_header *)(mBuf + letoh32(entry->offset)); - if (((char *)data + data->GetSize()) > (char *)mEnd) - return nullptr; - return data; - } -}; - -struct AnimationFrame { - char path[256]; - png_color_16 bgcolor; - char *buf; - const local_file_header *file; - uint32_t width; - uint32_t height; - uint16_t bytepp; - bool has_bgcolor; - - AnimationFrame() : buf(nullptr) {} - AnimationFrame(const AnimationFrame &frame) : buf(nullptr) { - strncpy(path, frame.path, sizeof(path)); - file = frame.file; - } - ~AnimationFrame() - { - if (buf) - free(buf); - } - - bool operator<(const AnimationFrame &other) const - { - return strcmp(path, other.path) < 0; - } - - void ReadPngFrame(int outputFormat); -}; - -struct AnimationPart { - int32_t count; - int32_t pause; - // If you alter the size of the path, change ReadFromString() as well. - char path[256]; - vector frames; - - bool - ReadFromString(const char* aLine) - { - MOZ_ASSERT(aLine); - // this 255 value must be in sync with AnimationPart::path. - return sscanf(aLine, "p %d %d %255s", &count, &pause, path) == 3; - } -}; - -struct RawReadState { - const char *start; - uint32_t offset; - uint32_t length; -}; - -static void -RawReader(png_structp png_ptr, png_bytep data, png_size_t length) -{ - RawReadState *state = (RawReadState *)png_get_io_ptr(png_ptr); - if (length > (state->length - state->offset)) - png_error(png_ptr, "PNG read overrun"); - - memcpy(data, state->start + state->offset, length); - state->offset += length; -} - -static void -TransformTo565(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - uint16_t *outbuf = (uint16_t *)data; - uint8_t *inbuf = (uint8_t *)data; - for (uint32_t i = 0; i < row_info->rowbytes; i += 3) { - *outbuf++ = ((inbuf[i] & 0xF8) << 8) | - ((inbuf[i + 1] & 0xFC) << 3) | - ((inbuf[i + 2] ) >> 3); - } -} - -static uint16_t -GetFormatBPP(int aFormat) -{ - uint16_t bpp = 0; - - switch (aFormat) { - case HAL_PIXEL_FORMAT_BGRA_8888: - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - bpp = 4; - break; - case HAL_PIXEL_FORMAT_RGB_888: - bpp = 3; - break; - default: - LOGW("Unknown pixel format %d. Assuming RGB 565.", aFormat); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGB_565: - bpp = 2; - break; - } - - return bpp; -} - -void -AnimationFrame::ReadPngFrame(int outputFormat) -{ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - static const png_byte unused_chunks[] = - { 99, 72, 82, 77, '\0', /* cHRM */ - 104, 73, 83, 84, '\0', /* hIST */ - 105, 67, 67, 80, '\0', /* iCCP */ - 105, 84, 88, 116, '\0', /* iTXt */ - 111, 70, 70, 115, '\0', /* oFFs */ - 112, 67, 65, 76, '\0', /* pCAL */ - 115, 67, 65, 76, '\0', /* sCAL */ - 112, 72, 89, 115, '\0', /* pHYs */ - 115, 66, 73, 84, '\0', /* sBIT */ - 115, 80, 76, 84, '\0', /* sPLT */ - 116, 69, 88, 116, '\0', /* tEXt */ - 116, 73, 77, 69, '\0', /* tIME */ - 122, 84, 88, 116, '\0'}; /* zTXt */ - static const png_byte tRNS_chunk[] = - {116, 82, 78, 83, '\0'}; /* tRNS */ -#endif - - png_structp pngread = png_create_read_struct(PNG_LIBPNG_VER_STRING, - nullptr, nullptr, nullptr); - - if (!pngread) - return; - - png_infop pnginfo = png_create_info_struct(pngread); - - if (!pnginfo) { - png_destroy_read_struct(&pngread, &pnginfo, nullptr); - return; - } - - if (setjmp(png_jmpbuf(pngread))) { - // libpng reported an error and longjumped here. Clean up and return. - png_destroy_read_struct(&pngread, &pnginfo, nullptr); - return; - } - - RawReadState state; - state.start = file->GetData(); - state.length = file->GetDataSize(); - state.offset = 0; - - png_set_read_fn(pngread, &state, RawReader); - -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - /* Ignore unused chunks */ - png_set_keep_unknown_chunks(pngread, 1, unused_chunks, - (int)sizeof(unused_chunks)/5); - - /* Ignore the tRNS chunk if we only want opaque output */ - if (outputFormat == HAL_PIXEL_FORMAT_RGB_888 || - outputFormat == HAL_PIXEL_FORMAT_RGB_565) { - png_set_keep_unknown_chunks(pngread, 1, tRNS_chunk, 1); - } -#endif - - png_read_info(pngread, pnginfo); - - png_color_16p colorp; - has_bgcolor = (PNG_INFO_bKGD == png_get_bKGD(pngread, pnginfo, &colorp)); - bgcolor = has_bgcolor ? *colorp : png_color_16(); - width = png_get_image_width(pngread, pnginfo); - height = png_get_image_height(pngread, pnginfo); - - LOG("Decoded %s: %d x %d frame with bgcolor? %s (%#x, %#x, %#x; gray:%#x)", - path, width, height, has_bgcolor ? "yes" : "no", - bgcolor.red, bgcolor.green, bgcolor.blue, bgcolor.gray); - - bytepp = GetFormatBPP(outputFormat); - - switch (outputFormat) { - case HAL_PIXEL_FORMAT_BGRA_8888: - png_set_bgr(pngread); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - png_set_filler(pngread, 0xFF, PNG_FILLER_AFTER); - break; - case HAL_PIXEL_FORMAT_RGB_888: - png_set_strip_alpha(pngread); - break; - default: - LOGW("Unknown pixel format %d. Assuming RGB 565.", outputFormat); - // FALL THROUGH - case HAL_PIXEL_FORMAT_RGB_565: - png_set_strip_alpha(pngread); - png_set_read_user_transform_fn(pngread, TransformTo565); - break; - } - - // An extra row is added to give libpng enough space when - // decoding 3/4 bytepp inputs for 2 bytepp output surfaces - buf = (char *)malloc(width * (height + 1) * bytepp); - - vector rows(height + 1); - uint32_t stride = width * bytepp; - for (uint32_t i = 0; i < height; i++) { - rows[i] = buf + (stride * i); - } - rows[height] = nullptr; - png_set_strip_16(pngread); - png_set_palette_to_rgb(pngread); - png_set_gray_to_rgb(pngread); - png_read_image(pngread, (png_bytepp)&rows.front()); - png_destroy_read_struct(&pngread, &pnginfo, nullptr); -} - -/** - * Return a wchar_t that when used to |wmemset()| an image buffer will - * fill it with the color defined by |color16|. The packed wchar_t - * may comprise one or two pixels depending on |outputFormat|. - */ -static wchar_t -AsBackgroundFill(const png_color_16& color16, int outputFormat) -{ - static_assert(sizeof(wchar_t) == sizeof(uint32_t), - "TODO: support 2-byte wchar_t"); - union { - uint32_t r8g8b8; - struct { - uint8_t b8; - uint8_t g8; - uint8_t r8; - uint8_t x8; - }; - } color; - color.b8 = color16.blue; - color.g8 = color16.green; - color.r8 = color16.red; - color.x8 = 0xFF; - - switch (outputFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - case HAL_PIXEL_FORMAT_RGBX_8888: - return color.r8g8b8; - - case HAL_PIXEL_FORMAT_BGRA_8888: - swap(color.r8, color.b8); - return color.r8g8b8; - - case HAL_PIXEL_FORMAT_RGB_565: { - // NB: we could do a higher-quality downsample here, but we - // want the results to be a pixel-perfect match with the fast - // downsample in TransformTo565(). - uint16_t color565 = ((color.r8 & 0xF8) << 8) | - ((color.g8 & 0xFC) << 3) | - ((color.b8 ) >> 3); - return (color565 << 16) | color565; - } - default: - LOGW("Unhandled pixel format %d; falling back on black", outputFormat); - return 0; - } -} - -void -ShowSolidColorFrame(GonkDisplay *aDisplay, - const gralloc_module_t *grallocModule, - int32_t aFormat) -{ - LOGW("Show solid color frame for bootAnim"); - - ANativeWindowBuffer *buffer = aDisplay->DequeueBuffer(); - void *mappedAddress = nullptr; - - if (!buffer) { - LOGW("Failed to get an ANativeWindowBuffer"); - return; - } - - if (!grallocModule->lock(grallocModule, buffer->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, buffer->width, buffer->height, &mappedAddress)) { - // Just show a black solid color frame. - memset(mappedAddress, 0, buffer->height * buffer->stride * GetFormatBPP(aFormat)); - grallocModule->unlock(grallocModule, buffer->handle); - } - - aDisplay->QueueBuffer(buffer); -} - -static void * -AnimationThread(void *) -{ - GonkDisplay *display = GetGonkDisplay(); - int32_t format = display->surfaceformat; - - const hw_module_t *module = nullptr; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) { - LOGW("Could not get gralloc module"); - return nullptr; - } - const gralloc_module_t *grmodule = - reinterpret_cast(module); - - ZipReader reader; - if (!reader.OpenArchive("/system/media/bootanimation.zip")) { - LOGW("Could not open boot animation"); - ShowSolidColorFrame(display, grmodule, format); - return nullptr; - } - - const cdir_entry *entry = nullptr; - const local_file_header *file = nullptr; - while ((entry = reader.GetNextEntry(entry))) { - string name = reader.GetEntryName(entry); - if (!name.compare("desc.txt")) { - file = reader.GetLocalEntry(entry); - break; - } - } - - if (!file) { - LOGW("Could not find desc.txt in boot animation"); - ShowSolidColorFrame(display, grmodule, format); - return nullptr; - } - - string descCopy; - descCopy.append(file->GetData(), entry->GetDataSize()); - int32_t width, height, fps; - const char *line = descCopy.c_str(); - const char *end; - bool headerRead = true; - vector parts; - bool animPlayed = false; - - /* - * bootanimation.zip - * - * This is the boot animation file format that Android uses. - * It's a zip file with a directories containing png frames - * and a desc.txt that describes how they should be played. - * - * desc.txt contains two types of lines - * 1. [width] [height] [fps] - * There is one of these lines per bootanimation. - * If the width and height are smaller than the screen, - * the frames are centered on a black background. - * XXX: Currently we stretch instead of centering the frame. - * 2. p [count] [pause] [path] - * This describes one animation part. - * Each animation part is played in sequence. - * An animation part contains all the files/frames in the - * directory specified in [path] - * [count] indicates the number of times this part repeats. - * [pause] indicates the number of frames that this part - * should pause for after playing the full sequence but - * before repeating. - */ - - do { - end = strstr(line, "\n"); - - AnimationPart part; - if (headerRead && - sscanf(line, "%d %d %d", &width, &height, &fps) == 3) { - headerRead = false; - } else if (part.ReadFromString(line)) { - parts.push_back(part); - } - } while (end && *(line = end + 1)); - - for (uint32_t i = 0; i < parts.size(); i++) { - AnimationPart &part = parts[i]; - entry = nullptr; - char search[256]; - snprintf(search, sizeof(search), "%s/", part.path); - while ((entry = reader.GetNextEntry(entry))) { - string name = reader.GetEntryName(entry); - if (name.find(search) || - !entry->GetDataSize() || - name.length() >= 256) - continue; - - part.frames.resize(part.frames.size() + 1); - AnimationFrame &frame = part.frames.back(); - strcpy(frame.path, name.c_str()); - frame.file = reader.GetLocalEntry(entry); - } - - sort(part.frames.begin(), part.frames.end()); - } - - long int frameDelayUs = 1000000 / fps; - - for (uint32_t i = 0; i < parts.size(); i++) { - AnimationPart &part = parts[i]; - - int32_t j = 0; - while (sRunAnimation && (!part.count || j++ < part.count)) { - for (uint32_t k = 0; k < part.frames.size(); k++) { - struct timeval tv1, tv2; - gettimeofday(&tv1, nullptr); - AnimationFrame &frame = part.frames[k]; - if (!frame.buf) { - frame.ReadPngFrame(format); - } - - ANativeWindowBuffer *buf = display->DequeueBuffer(); - if (!buf) { - LOGW("Failed to get an ANativeWindowBuffer"); - break; - } - - void *vaddr; - if (grmodule->lock(grmodule, buf->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, width, height, &vaddr)) { - LOGW("Failed to lock buffer_handle_t"); - display->QueueBuffer(buf); - break; - } - - if (frame.has_bgcolor) { - wchar_t bgfill = AsBackgroundFill(frame.bgcolor, format); - wmemset((wchar_t*)vaddr, bgfill, - (buf->height * buf->stride * frame.bytepp) / sizeof(wchar_t)); - } - - if ((uint32_t)buf->height == frame.height && (uint32_t)buf->stride == frame.width) { - memcpy(vaddr, frame.buf, - frame.width * frame.height * frame.bytepp); - } else if ((uint32_t)buf->height >= frame.height && - (uint32_t)buf->width >= frame.width) { - int startx = (buf->width - frame.width) / 2; - int starty = (buf->height - frame.height) / 2; - - int src_stride = frame.width * frame.bytepp; - int dst_stride = buf->stride * frame.bytepp; - - char *src = frame.buf; - char *dst = (char *) vaddr + starty * dst_stride + startx * frame.bytepp; - - for (uint32_t i = 0; i < frame.height; i++) { - memcpy(dst, src, src_stride); - src += src_stride; - dst += dst_stride; - } - } - grmodule->unlock(grmodule, buf->handle); - - gettimeofday(&tv2, nullptr); - - timersub(&tv2, &tv1, &tv2); - - if (tv2.tv_usec < frameDelayUs) { - usleep(frameDelayUs - tv2.tv_usec); - } else { - LOGW("Frame delay is %ld us but decoding took %ld us", - frameDelayUs, tv2.tv_usec); - } - - animPlayed = true; - display->QueueBuffer(buf); - - if (part.count && j >= part.count) { - free(frame.buf); - frame.buf = nullptr; - } - } - usleep(frameDelayUs * part.pause); - } - } - - if (!animPlayed) { - ShowSolidColorFrame(display, grmodule, format); - } - - return nullptr; -} - -namespace mozilla { - -__attribute__ ((visibility ("default"))) -void -StartBootAnimation() -{ - GetGonkDisplay(); // Ensure GonkDisplay exist - sRunAnimation = true; - pthread_create(&sAnimationThread, nullptr, AnimationThread, nullptr); -} - -__attribute__ ((visibility ("default"))) -void -StopBootAnimation() -{ - if (sRunAnimation) { - sRunAnimation = false; - pthread_join(sAnimationThread, nullptr); - GetGonkDisplay()->NotifyBootAnimationStopped(); - } -} - -} // namespace mozilla diff --git a/widget/gonk/libdisplay/BootAnimation.h b/widget/gonk/libdisplay/BootAnimation.h deleted file mode 100644 index 9fdc20eca..000000000 --- a/widget/gonk/libdisplay/BootAnimation.h +++ /dev/null @@ -1,30 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef BOOTANIMATION_H -#define BOOTANIMATION_H - -namespace mozilla { - -MOZ_EXPORT __attribute__ ((weak)) -void StartBootAnimation(); - -/* Stop the boot animation if it's still running. */ -MOZ_EXPORT __attribute__ ((weak)) -void StopBootAnimation(); - -} // namespace mozilla - -#endif /* BOOTANIMATION_H */ diff --git a/widget/gonk/libdisplay/DisplaySurface.h b/widget/gonk/libdisplay/DisplaySurface.h deleted file mode 100644 index 398541c49..000000000 --- a/widget/gonk/libdisplay/DisplaySurface.h +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 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. - */ - -#ifndef ANDROID_SF_DISPLAY_SURFACE_H -#define ANDROID_SF_DISPLAY_SURFACE_H - -#include -#include -#include -#include -#include - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -class IGraphicBufferProducer; -class String8; - -#if ANDROID_VERSION >= 21 -typedef IGraphicBufferConsumer StreamConsumer; -#else -typedef BufferQueue StreamConsumer; -#endif - -class DisplaySurface : public ConsumerBase { -public: - // beginFrame is called at the beginning of the composition loop, before - // the configuration is known. The DisplaySurface should do anything it - // needs to do to enable HWComposer to decide how to compose the frame. - // We pass in mustRecompose so we can keep VirtualDisplaySurface's state - // machine happy without actually queueing a buffer if nothing has changed. - virtual status_t beginFrame(bool mustRecompose) = 0; - - // prepareFrame is called after the composition configuration is known but - // before composition takes place. The DisplaySurface can use the - // composition type to decide how to manage the flow of buffers between - // GLES and HWC for this frame. - enum CompositionType { - COMPOSITION_UNKNOWN = 0, - COMPOSITION_GLES = 1, - COMPOSITION_HWC = 2, - COMPOSITION_MIXED = COMPOSITION_GLES | COMPOSITION_HWC - }; - virtual status_t prepareFrame(CompositionType compositionType) = 0; - - // Should be called when composition rendering is complete for a frame (but - // eglSwapBuffers hasn't necessarily been called). Required by certain - // older drivers for synchronization. - // TODO: Remove this when we drop support for HWC 1.0. - virtual status_t compositionComplete() = 0; - - // Inform the surface that GLES composition is complete for this frame, and - // the surface should make sure that HWComposer has the correct buffer for - // this frame. Some implementations may only push a new buffer to - // HWComposer if GLES composition took place, others need to push a new - // buffer on every frame. - // - // advanceFrame must be followed by a call to onFrameCommitted before - // advanceFrame may be called again. - virtual status_t advanceFrame() = 0; - - // onFrameCommitted is called after the frame has been committed to the - // hardware composer. The surface collects the release fence for this - // frame's buffer. - virtual void onFrameCommitted() = 0; - - virtual void resizeBuffers(const uint32_t w, const uint32_t h) = 0; - - // setReleaseFenceFd stores a fence file descriptor that will signal when the - // current buffer is no longer being read. This fence will be returned to - // the producer when the current buffer is released by updateTexImage(). - // Multiple fences can be set for a given buffer; they will be merged into - // a single union fence. The SurfaceTexture will close the file descriptor - // when finished with it. - virtual status_t setReleaseFenceFd(int fenceFd) = 0; - - virtual int GetPrevDispAcquireFd() = 0; - - buffer_handle_t lastHandle; - -protected: - DisplaySurface(const sp& sc) -#if ANDROID_VERSION >= 19 - : ConsumerBase(sc, true) -#else - : ConsumerBase(sc) -#endif - , lastHandle(0) - { } - virtual ~DisplaySurface() {} -}; - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_DISPLAY_SURFACE_H - diff --git a/widget/gonk/libdisplay/FramebufferSurface.cpp b/widget/gonk/libdisplay/FramebufferSurface.cpp deleted file mode 100644 index a289acbb8..000000000 --- a/widget/gonk/libdisplay/FramebufferSurface.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* - ** - ** Copyright 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. - */ - -#include -#include -#include -#include - -#include - -#include - -#include - -#include - -#include -#if ANDROID_VERSION == 17 -#include -#endif -#include - -#include "FramebufferSurface.h" -#include "GraphicBufferAlloc.h" - -#ifndef NUM_FRAMEBUFFER_SURFACE_BUFFERS -#define NUM_FRAMEBUFFER_SURFACE_BUFFERS (2) -#endif - -// ---------------------------------------------------------------------------- -namespace android { -// ---------------------------------------------------------------------------- - -/* - * This implements the (main) framebuffer management. This class - * was adapted from the version in SurfaceFlinger - */ -FramebufferSurface::FramebufferSurface(int disp, - uint32_t width, - uint32_t height, - uint32_t format, - const sp& sc) - : DisplaySurface(sc) - , mDisplayType(disp) - , mCurrentBufferSlot(-1) - , mCurrentBuffer(0) -{ - mName = "FramebufferSurface"; - -#if ANDROID_VERSION >= 19 - sp consumer = mConsumer; -#else - sp consumer = mBufferQueue; - consumer->setSynchronousMode(true); -#endif - consumer->setConsumerName(mName); - consumer->setConsumerUsageBits(GRALLOC_USAGE_HW_FB | - GRALLOC_USAGE_HW_RENDER | - GRALLOC_USAGE_HW_COMPOSER); - consumer->setDefaultBufferFormat(format); - consumer->setDefaultBufferSize(width, height); - consumer->setDefaultMaxBufferCount(NUM_FRAMEBUFFER_SURFACE_BUFFERS); -} - -status_t FramebufferSurface::beginFrame(bool /*mustRecompose*/) { - return NO_ERROR; -} - -status_t FramebufferSurface::prepareFrame(CompositionType /*compositionType*/) { - return NO_ERROR; -} - -status_t FramebufferSurface::advanceFrame() { - // Once we remove FB HAL support, we can call nextBuffer() from here - // instead of using onFrameAvailable(). No real benefit, except it'll be - // more like VirtualDisplaySurface. - return NO_ERROR; -} - -status_t FramebufferSurface::nextBuffer(sp& outBuffer, sp& outFence) { - Mutex::Autolock lock(mMutex); - - BufferQueue::BufferItem item; -#if ANDROID_VERSION >= 19 - status_t err = acquireBufferLocked(&item, 0); -#else - status_t err = acquireBufferLocked(&item); -#endif - if (err == BufferQueue::NO_BUFFER_AVAILABLE) { - outBuffer = mCurrentBuffer; - return NO_ERROR; - } else if (err != NO_ERROR) { - ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err); - return err; - } - - // If the BufferQueue has freed and reallocated a buffer in mCurrentSlot - // then we may have acquired the slot we already own. If we had released - // our current buffer before we call acquireBuffer then that release call - // would have returned STALE_BUFFER_SLOT, and we would have called - // freeBufferLocked on that slot. Because the buffer slot has already - // been overwritten with the new buffer all we have to do is skip the - // releaseBuffer call and we should be in the same state we'd be in if we - // had released the old buffer first. - if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT && - item.mBuf != mCurrentBufferSlot) { - // Release the previous buffer. -#if ANDROID_VERSION >= 19 - err = releaseBufferLocked(mCurrentBufferSlot, mCurrentBuffer, - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); -#else - err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY, - EGL_NO_SYNC_KHR); -#endif - if (err != NO_ERROR && err != StreamConsumer::STALE_BUFFER_SLOT) { - ALOGE("error releasing buffer: %s (%d)", strerror(-err), err); - return err; - } - } - mCurrentBufferSlot = item.mBuf; - mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer; - outFence = item.mFence; - outBuffer = mCurrentBuffer; - return NO_ERROR; -} - -// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl. -#if ANDROID_VERSION >= 22 -void FramebufferSurface::onFrameAvailable(const ::android::BufferItem &item) { -#else -void FramebufferSurface::onFrameAvailable() { -#endif - sp buf; - sp acquireFence; - status_t err = nextBuffer(buf, acquireFence); - if (err != NO_ERROR) { - ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)", - strerror(-err), err); - return; - } - if (acquireFence.get() && acquireFence->isValid()) - mPrevFBAcquireFence = new Fence(acquireFence->dup()); - else - mPrevFBAcquireFence = Fence::NO_FENCE; - - lastHandle = buf->handle; -} - -void FramebufferSurface::freeBufferLocked(int slotIndex) { - ConsumerBase::freeBufferLocked(slotIndex); - if (slotIndex == mCurrentBufferSlot) { - mCurrentBufferSlot = BufferQueue::INVALID_BUFFER_SLOT; - } -} - -status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) { - status_t err = NO_ERROR; - if (fenceFd >= 0) { - sp fence(new Fence(fenceFd)); - if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) { -#if ANDROID_VERSION >= 19 - status_t err = addReleaseFence(mCurrentBufferSlot, mCurrentBuffer, fence); -#else - status_t err = addReleaseFence(mCurrentBufferSlot, fence); -#endif - ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)", - strerror(-err), err); - } - } - return err; -} - -int FramebufferSurface::GetPrevDispAcquireFd() { - if (mPrevFBAcquireFence.get() && mPrevFBAcquireFence->isValid()) { - return mPrevFBAcquireFence->dup(); - } - return -1; -} - -void FramebufferSurface::onFrameCommitted() { - // XXX This role is almost same to setReleaseFenceFd(). -} - -status_t FramebufferSurface::compositionComplete() -{ - // Actual implementaiton is in GonkDisplay::SwapBuffers() - // XXX need to move that to here. - return NO_ERROR; -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- diff --git a/widget/gonk/libdisplay/FramebufferSurface.h b/widget/gonk/libdisplay/FramebufferSurface.h deleted file mode 100644 index c1cc84272..000000000 --- a/widget/gonk/libdisplay/FramebufferSurface.h +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2007 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. - */ - -#ifndef ANDROID_SF_FRAMEBUFFER_SURFACE_H -#define ANDROID_SF_FRAMEBUFFER_SURFACE_H - -#include -#include - -#include "DisplaySurface.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -class Rect; -class String8; - -// --------------------------------------------------------------------------- - -class FramebufferSurface : public DisplaySurface { -public: - FramebufferSurface(int disp, uint32_t width, uint32_t height, uint32_t format, const sp& sc); - - // From DisplaySurface - virtual status_t beginFrame(bool mustRecompose); - virtual status_t prepareFrame(CompositionType compositionType); - virtual status_t compositionComplete(); - virtual status_t advanceFrame(); - virtual void onFrameCommitted(); - // Cannot resize a buffers in a FramebufferSurface. Only works with virtual - // displays. - virtual void resizeBuffers(const uint32_t /*w*/, const uint32_t /*h*/) { }; - - // setReleaseFenceFd stores a fence file descriptor that will signal when the - // current buffer is no longer being read. This fence will be returned to - // the producer when the current buffer is released by updateTexImage(). - // Multiple fences can be set for a given buffer; they will be merged into - // a single union fence. The SurfaceTexture will close the file descriptor - // when finished with it. - status_t setReleaseFenceFd(int fenceFd); - - virtual int GetPrevDispAcquireFd(); - -private: - virtual ~FramebufferSurface() { }; // this class cannot be overloaded - -#if ANDROID_VERSION >= 22 - virtual void onFrameAvailable(const ::android::BufferItem &item); -#else - virtual void onFrameAvailable(); -#endif - virtual void freeBufferLocked(int slotIndex); - - // nextBuffer waits for and then latches the next buffer from the - // BufferQueue and releases the previously latched buffer to the - // BufferQueue. The new buffer is returned in the 'buffer' argument. - status_t nextBuffer(sp& outBuffer, sp& outFence); - - // mDisplayType must match one of the HWC display types - int mDisplayType; - - // mCurrentBufferIndex is the slot index of the current buffer or - // INVALID_BUFFER_SLOT to indicate that either there is no current buffer - // or the buffer is not associated with a slot. - int mCurrentBufferSlot; - - // mCurrentBuffer is the current buffer or NULL to indicate that there is - // no current buffer. - sp mCurrentBuffer; - - android::sp mPrevFBAcquireFence; -}; - -// --------------------------------------------------------------------------- -}; // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_FRAMEBUFFER_SURFACE_H - diff --git a/widget/gonk/libdisplay/GonkDisplay.h b/widget/gonk/libdisplay/GonkDisplay.h deleted file mode 100644 index 96978a6e9..000000000 --- a/widget/gonk/libdisplay/GonkDisplay.h +++ /dev/null @@ -1,91 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GONKDISPLAY_H -#define GONKDISPLAY_H - -#include -#include -#include "mozilla/Types.h" - -namespace android { -class DisplaySurface; -class IGraphicBufferProducer; -} - -namespace mozilla { - -typedef void * EGLDisplay; -typedef void * EGLSurface; - -class MOZ_EXPORT GonkDisplay { -public: - /** - * This enum is for types of display. DISPLAY_PRIMARY refers to the default - * built-in display, DISPLAY_EXTERNAL refers to displays connected with - * HDMI, and DISPLAY_VIRTUAL are displays which makes composited output - * available within the system. Currently, displays of external are detected - * via the hotplug detection in HWC, and displays of virtual are connected - * via Wifi Display. - */ - enum DisplayType { - DISPLAY_PRIMARY, - DISPLAY_EXTERNAL, - DISPLAY_VIRTUAL, - NUM_DISPLAY_TYPES - }; - - struct NativeData { - android::sp mNativeWindow; -#if ANDROID_VERSION >= 17 - android::sp mDisplaySurface; -#endif - float mXdpi; - }; - - virtual void SetEnabled(bool enabled) = 0; - - typedef void (*OnEnabledCallbackType)(bool enabled); - - virtual void OnEnabled(OnEnabledCallbackType callback) = 0; - - virtual void* GetHWCDevice() = 0; - - /** - * Only GonkDisplayICS uses arguments. - */ - virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur) = 0; - - virtual ANativeWindowBuffer* DequeueBuffer() = 0; - - virtual bool QueueBuffer(ANativeWindowBuffer* buf) = 0; - - virtual void UpdateDispSurface(EGLDisplay dpy, EGLSurface sur) = 0; - - virtual NativeData GetNativeData( - GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink = nullptr) = 0; - - virtual void NotifyBootAnimationStopped() = 0; - - float xdpi; - int32_t surfaceformat; -}; - -MOZ_EXPORT __attribute__ ((weak)) -GonkDisplay* GetGonkDisplay(); - -} -#endif /* GONKDISPLAY_H */ diff --git a/widget/gonk/libdisplay/GonkDisplayJB.cpp b/widget/gonk/libdisplay/GonkDisplayJB.cpp deleted file mode 100644 index 197b85a47..000000000 --- a/widget/gonk/libdisplay/GonkDisplayJB.cpp +++ /dev/null @@ -1,461 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "GonkDisplayJB.h" -#if ANDROID_VERSION == 17 -#include -#else -#include -#include -#endif - -#include -#include -#include -#include - -#if ANDROID_VERSION >= 19 -#include "VirtualDisplaySurface.h" -#endif -#include "FramebufferSurface.h" -#if ANDROID_VERSION == 17 -#include "GraphicBufferAlloc.h" -#endif -#include "mozilla/Assertions.h" - -#define DEFAULT_XDPI 75.0 - -using namespace android; - -namespace mozilla { - -static GonkDisplayJB* sGonkDisplay = nullptr; - -GonkDisplayJB::GonkDisplayJB() - : mModule(nullptr) - , mFBModule(nullptr) - , mHwc(nullptr) - , mFBDevice(nullptr) - , mPowerModule(nullptr) - , mList(nullptr) - , mWidth(0) - , mHeight(0) - , mEnabledCallback(nullptr) -{ - int err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mFBModule); - ALOGW_IF(err, "%s module not found", GRALLOC_HARDWARE_MODULE_ID); - if (!err) { - err = framebuffer_open(mFBModule, &mFBDevice); - ALOGW_IF(err, "could not open framebuffer"); - } - - if (!err && mFBDevice) { - mWidth = mFBDevice->width; - mHeight = mFBDevice->height; - xdpi = mFBDevice->xdpi; - /* The emulator actually reports RGBA_8888, but EGL doesn't return - * any matching configuration. We force RGBX here to fix it. */ - surfaceformat = HAL_PIXEL_FORMAT_RGBX_8888; - } - - err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule); - ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID); - if (!err) { - err = hwc_open_1(mModule, &mHwc); - ALOGE_IF(err, "%s device failed to initialize (%s)", - HWC_HARDWARE_COMPOSER, strerror(-err)); - } - - /* Fallback on the FB rendering path instead of trying to support HWC 1.0 */ - if (!err && mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) { - hwc_close_1(mHwc); - mHwc = nullptr; - } - - if (!err && mHwc) { - if (mFBDevice) { - framebuffer_close(mFBDevice); - mFBDevice = nullptr; - } - - int32_t values[3]; - const uint32_t attrs[] = { - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_NO_ATTRIBUTE - }; - mHwc->getDisplayAttributes(mHwc, 0, 0, attrs, values); - - mWidth = values[0]; - mHeight = values[1]; - xdpi = values[2] / 1000.0f; - surfaceformat = HAL_PIXEL_FORMAT_RGBA_8888; - } - - err = hw_get_module(POWER_HARDWARE_MODULE_ID, - (hw_module_t const**)&mPowerModule); - if (!err) - mPowerModule->init(mPowerModule); - ALOGW_IF(err, "Couldn't load %s module (%s)", POWER_HARDWARE_MODULE_ID, strerror(-err)); - - mAlloc = new GraphicBufferAlloc(); - - CreateFramebufferSurface(mSTClient, mDispSurface, mWidth, mHeight); - - mList = (hwc_display_contents_1_t *)calloc(1, sizeof(*mList) + (sizeof(hwc_layer_1_t)*2)); - - uint32_t usage = GRALLOC_USAGE_HW_FB | GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER; - if (mFBDevice) { - // If device uses fb, they can not use single buffer for boot animation - mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_BUFFER_COUNT, 2); - mSTClient->perform(mSTClient.get(), NATIVE_WINDOW_SET_USAGE, usage); - } else if (mHwc) { - PowerOnDisplay(HWC_DISPLAY_PRIMARY); - // For devices w/ hwc v1.0 or no hwc, this buffer can not be created, - // only create this buffer for devices w/ hwc version > 1.0. - CreateFramebufferSurface(mBootAnimSTClient, mBootAnimDispSurface, mWidth, mHeight); - } -} - -GonkDisplayJB::~GonkDisplayJB() -{ - if (mHwc) - hwc_close_1(mHwc); - if (mFBDevice) - framebuffer_close(mFBDevice); - free(mList); -} - -void -GonkDisplayJB::CreateFramebufferSurface(android::sp& aNativeWindow, - android::sp& aDisplaySurface, - uint32_t aWidth, - uint32_t aHeight) -{ -#if ANDROID_VERSION >= 21 - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer, mAlloc); -#elif ANDROID_VERSION >= 19 - sp consumer = new BufferQueue(mAlloc); - sp producer = consumer; -#elif ANDROID_VERSION >= 18 - sp consumer = new BufferQueue(true, mAlloc); - sp producer = consumer; -#else - sp consumer = new BufferQueue(true, mAlloc); -#endif - - aDisplaySurface = new FramebufferSurface(0, aWidth, aHeight, surfaceformat, consumer); - -#if ANDROID_VERSION == 17 - aNativeWindow = new SurfaceTextureClient( - static_cast>(aDisplaySurface->getBufferQueue())); -#else - aNativeWindow = new Surface(producer); -#endif -} - -void -GonkDisplayJB::CreateVirtualDisplaySurface(android::IGraphicBufferProducer* aSink, - android::sp& aNativeWindow, - android::sp& aDisplaySurface) -{ -#if ANDROID_VERSION >= 21 - sp producer; - sp consumer; - BufferQueue::createBufferQueue(&producer, &consumer, mAlloc); -#elif ANDROID_VERSION >= 19 - sp consumer = new BufferQueue(mAlloc); - sp producer = consumer; -#endif - -#if ANDROID_VERSION >= 19 - sp virtualDisplay; - virtualDisplay = new VirtualDisplaySurface(-1, aSink, producer, consumer, String8("VirtualDisplaySurface")); - aDisplaySurface = virtualDisplay; - aNativeWindow = new Surface(virtualDisplay); -#endif -} - -void -GonkDisplayJB::SetEnabled(bool enabled) -{ - if (enabled) { - autosuspend_disable(); - mPowerModule->setInteractive(mPowerModule, true); - } - - if (!enabled && mEnabledCallback) { - mEnabledCallback(enabled); - } - -#if ANDROID_VERSION >= 21 - if (mHwc) { - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) { - mHwc->setPowerMode(mHwc, HWC_DISPLAY_PRIMARY, - (enabled ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF)); - } else { - mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled); - } - } else if (mFBDevice && mFBDevice->enableScreen) { - mFBDevice->enableScreen(mFBDevice, enabled); - } -#else - if (mHwc && mHwc->blank) { - mHwc->blank(mHwc, HWC_DISPLAY_PRIMARY, !enabled); - } else if (mFBDevice && mFBDevice->enableScreen) { - mFBDevice->enableScreen(mFBDevice, enabled); - } -#endif - - if (enabled && mEnabledCallback) { - mEnabledCallback(enabled); - } - - if (!enabled) { - autosuspend_enable(); - mPowerModule->setInteractive(mPowerModule, false); - } -} - -void -GonkDisplayJB::OnEnabled(OnEnabledCallbackType callback) -{ - mEnabledCallback = callback; -} - -void* -GonkDisplayJB::GetHWCDevice() -{ - return mHwc; -} - -bool -GonkDisplayJB::SwapBuffers(EGLDisplay dpy, EGLSurface sur) -{ - // Should be called when composition rendering is complete for a frame. - // Only HWC v1.0 needs this call. - // HWC > v1.0 case, do not call compositionComplete(). - // mFBDevice is present only when HWC is v1.0. - if (mFBDevice && mFBDevice->compositionComplete) { - mFBDevice->compositionComplete(mFBDevice); - } - return Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd()); -} - -bool -GonkDisplayJB::Post(buffer_handle_t buf, int fence) -{ - if (!mHwc) { - if (fence >= 0) - close(fence); - return !mFBDevice->post(mFBDevice, buf); - } - - hwc_display_contents_1_t *displays[HWC_NUM_DISPLAY_TYPES] = {NULL}; - const hwc_rect_t r = { 0, 0, static_cast(mWidth), static_cast(mHeight) }; - displays[HWC_DISPLAY_PRIMARY] = mList; - mList->retireFenceFd = -1; - mList->numHwLayers = 2; - mList->flags = HWC_GEOMETRY_CHANGED; -#if ANDROID_VERSION >= 18 - mList->outbuf = nullptr; - mList->outbufAcquireFenceFd = -1; -#endif - mList->hwLayers[0].compositionType = HWC_FRAMEBUFFER; - mList->hwLayers[0].hints = 0; - /* Skip this layer so the hwc module doesn't complain about null handles */ - mList->hwLayers[0].flags = HWC_SKIP_LAYER; - mList->hwLayers[0].backgroundColor = {0}; - mList->hwLayers[0].acquireFenceFd = -1; - mList->hwLayers[0].releaseFenceFd = -1; - /* hwc module checks displayFrame even though it shouldn't */ - mList->hwLayers[0].displayFrame = r; - mList->hwLayers[1].compositionType = HWC_FRAMEBUFFER_TARGET; - mList->hwLayers[1].hints = 0; - mList->hwLayers[1].flags = 0; - mList->hwLayers[1].handle = buf; - mList->hwLayers[1].transform = 0; - mList->hwLayers[1].blending = HWC_BLENDING_NONE; -#if ANDROID_VERSION >= 19 - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_3) { - mList->hwLayers[1].sourceCropf.left = 0; - mList->hwLayers[1].sourceCropf.top = 0; - mList->hwLayers[1].sourceCropf.right = mWidth; - mList->hwLayers[1].sourceCropf.bottom = mHeight; - } else { - mList->hwLayers[1].sourceCrop = r; - } -#else - mList->hwLayers[1].sourceCrop = r; -#endif - mList->hwLayers[1].displayFrame = r; - mList->hwLayers[1].visibleRegionScreen.numRects = 1; - mList->hwLayers[1].visibleRegionScreen.rects = &mList->hwLayers[1].displayFrame; - mList->hwLayers[1].acquireFenceFd = fence; - mList->hwLayers[1].releaseFenceFd = -1; -#if ANDROID_VERSION >= 18 - mList->hwLayers[1].planeAlpha = 0xFF; -#endif - mHwc->prepare(mHwc, HWC_NUM_DISPLAY_TYPES, displays); - int err = mHwc->set(mHwc, HWC_NUM_DISPLAY_TYPES, displays); - - if (!mBootAnimDispSurface.get()) { - mDispSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd); - } else { - mBootAnimDispSurface->setReleaseFenceFd(mList->hwLayers[1].releaseFenceFd); - } - - if (mList->retireFenceFd >= 0) - close(mList->retireFenceFd); - return !err; -} - -ANativeWindowBuffer* -GonkDisplayJB::DequeueBuffer() -{ - // Check for bootAnim or normal display flow. - sp nativeWindow = - !mBootAnimSTClient.get() ? mSTClient : mBootAnimSTClient; - - ANativeWindowBuffer *buf; - int fenceFd = -1; - nativeWindow->dequeueBuffer(nativeWindow.get(), &buf, &fenceFd); - sp fence(new Fence(fenceFd)); -#if ANDROID_VERSION == 17 - fence->waitForever(1000, "GonkDisplayJB_DequeueBuffer"); - // 1000 is what Android uses. It is a warning timeout in ms. - // This timeout was removed in ANDROID_VERSION 18. -#else - fence->waitForever("GonkDisplayJB_DequeueBuffer"); -#endif - return buf; -} - -bool -GonkDisplayJB::QueueBuffer(ANativeWindowBuffer* buf) -{ - bool success = false; - int error = DoQueueBuffer(buf); - // Check for bootAnim or normal display flow. - if (!mBootAnimSTClient.get()) { - success = Post(mDispSurface->lastHandle, mDispSurface->GetPrevDispAcquireFd()); - } else { - success = Post(mBootAnimDispSurface->lastHandle, mBootAnimDispSurface->GetPrevDispAcquireFd()); - } - return error == 0 && success; -} - -int -GonkDisplayJB::DoQueueBuffer(ANativeWindowBuffer* buf) -{ - int error = 0; - // Check for bootAnim or normal display flow. - if (!mBootAnimSTClient.get()) { - error = mSTClient->queueBuffer(mSTClient.get(), buf, -1); - } else { - error = mBootAnimSTClient->queueBuffer(mBootAnimSTClient.get(), buf, -1); - } - return error; -} - -void -GonkDisplayJB::UpdateDispSurface(EGLDisplay dpy, EGLSurface sur) -{ - if (sur != EGL_NO_SURFACE) { - eglSwapBuffers(dpy, sur); - } else { - // When BasicCompositor is used as Compositor, - // EGLSurface does not exit. - ANativeWindowBuffer* buf = DequeueBuffer(); - DoQueueBuffer(buf); - } -} - -void -GonkDisplayJB::NotifyBootAnimationStopped() -{ - if (mBootAnimSTClient.get()) { - mBootAnimSTClient = nullptr; - mBootAnimDispSurface = nullptr; - } -} - -void -GonkDisplayJB::PowerOnDisplay(int aDpy) -{ - MOZ_ASSERT(mHwc); -#if ANDROID_VERSION >= 21 - if (mHwc->common.version >= HWC_DEVICE_API_VERSION_1_4) { - mHwc->setPowerMode(mHwc, aDpy, HWC_POWER_MODE_NORMAL); - } else { - mHwc->blank(mHwc, aDpy, 0); - } -#else - mHwc->blank(mHwc, aDpy, 0); -#endif -} - -GonkDisplay::NativeData -GonkDisplayJB::GetNativeData(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink) -{ - NativeData data; - - if (aDisplayType == DISPLAY_PRIMARY) { - data.mNativeWindow = mSTClient; - data.mDisplaySurface = mDispSurface; - data.mXdpi = xdpi; - } else if (aDisplayType == DISPLAY_EXTERNAL) { - int32_t values[3]; - const uint32_t attrs[] = { - HWC_DISPLAY_WIDTH, - HWC_DISPLAY_HEIGHT, - HWC_DISPLAY_DPI_X, - HWC_DISPLAY_NO_ATTRIBUTE - }; - mHwc->getDisplayAttributes(mHwc, aDisplayType, 0, attrs, values); - int width = values[0]; - int height = values[1]; - // FIXME!! values[2] returns 0 for external display, which doesn't - // sound right, Bug 1169176 is the follow-up bug for this issue. - data.mXdpi = values[2] ? values[2] / 1000.f : DEFAULT_XDPI; - PowerOnDisplay(HWC_DISPLAY_EXTERNAL); - CreateFramebufferSurface(data.mNativeWindow, - data.mDisplaySurface, - width, - height); - } else if (aDisplayType == DISPLAY_VIRTUAL) { - data.mXdpi = xdpi; - CreateVirtualDisplaySurface(aSink, - data.mNativeWindow, - data.mDisplaySurface); - } - - return data; -} - -__attribute__ ((visibility ("default"))) -GonkDisplay* -GetGonkDisplay() -{ - if (!sGonkDisplay) - sGonkDisplay = new GonkDisplayJB(); - return sGonkDisplay; -} - -} // namespace mozilla diff --git a/widget/gonk/libdisplay/GonkDisplayJB.h b/widget/gonk/libdisplay/GonkDisplayJB.h deleted file mode 100644 index 60bcdffc4..000000000 --- a/widget/gonk/libdisplay/GonkDisplayJB.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef GONKDISPLAYJB_H -#define GONKDISPLAYJB_H - -#include "DisplaySurface.h" -#include "GonkDisplay.h" -#include "hardware/hwcomposer.h" -#include "hardware/power.h" -#include "ui/Fence.h" -#include "utils/RefBase.h" - -namespace mozilla { - -class MOZ_EXPORT GonkDisplayJB : public GonkDisplay { -public: - GonkDisplayJB(); - ~GonkDisplayJB(); - - virtual void SetEnabled(bool enabled); - - virtual void OnEnabled(OnEnabledCallbackType callback); - - virtual void* GetHWCDevice(); - - virtual bool SwapBuffers(EGLDisplay dpy, EGLSurface sur); - - virtual ANativeWindowBuffer* DequeueBuffer(); - - virtual bool QueueBuffer(ANativeWindowBuffer* buf); - - virtual void UpdateDispSurface(EGLDisplay dpy, EGLSurface sur); - - bool Post(buffer_handle_t buf, int fence); - - virtual NativeData GetNativeData( - GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink = nullptr); - - virtual void NotifyBootAnimationStopped(); - -private: - void CreateFramebufferSurface(android::sp& aNativeWindow, - android::sp& aDisplaySurface, - uint32_t aWidth, uint32_t aHeight); - void CreateVirtualDisplaySurface(android::IGraphicBufferProducer* aSink, - android::sp& aNativeWindow, - android::sp& aDisplaySurface); - - void PowerOnDisplay(int aDpy); - - int DoQueueBuffer(ANativeWindowBuffer* buf); - - hw_module_t const* mModule; - hw_module_t const* mFBModule; - hwc_composer_device_1_t* mHwc; - framebuffer_device_t* mFBDevice; - power_module_t* mPowerModule; - android::sp mDispSurface; - android::sp mSTClient; - android::sp mBootAnimDispSurface; - android::sp mBootAnimSTClient; - android::sp mAlloc; - hwc_display_contents_1_t* mList; - uint32_t mWidth; - uint32_t mHeight; - OnEnabledCallbackType mEnabledCallback; -}; - -} - -#endif /* GONKDISPLAYJB_H */ diff --git a/widget/gonk/libdisplay/GraphicBufferAlloc.cpp b/widget/gonk/libdisplay/GraphicBufferAlloc.cpp deleted file mode 100644 index 5722b7fe3..000000000 --- a/widget/gonk/libdisplay/GraphicBufferAlloc.cpp +++ /dev/null @@ -1,53 +0,0 @@ -/* - ** - ** Copyright 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. - */ - -#include - -#include - -#include "GraphicBufferAlloc.h" - -// ---------------------------------------------------------------------------- -namespace android { -// ---------------------------------------------------------------------------- - -GraphicBufferAlloc::GraphicBufferAlloc() { -} - -GraphicBufferAlloc::~GraphicBufferAlloc() { -} - -sp GraphicBufferAlloc::createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error) { - sp graphicBuffer(new GraphicBuffer(w, h, format, usage)); - status_t err = graphicBuffer->initCheck(); - *error = err; - if (err != 0 || graphicBuffer->handle == 0) { - if (err == NO_MEMORY) { - GraphicBuffer::dumpAllocationsToSystemLog(); - } - ALOGE("GraphicBufferAlloc::createGraphicBuffer(w=%d, h=%d) " - "failed (%s), handle=%p", - w, h, strerror(-err), graphicBuffer->handle); - return 0; - } - return graphicBuffer; -} - -// ---------------------------------------------------------------------------- -}; // namespace android -// ---------------------------------------------------------------------------- diff --git a/widget/gonk/libdisplay/GraphicBufferAlloc.h b/widget/gonk/libdisplay/GraphicBufferAlloc.h deleted file mode 100644 index b08750c2f..000000000 --- a/widget/gonk/libdisplay/GraphicBufferAlloc.h +++ /dev/null @@ -1,44 +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. - */ - -#ifndef ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H -#define ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H - -#include -#include - -#include -#include -#include - -namespace android { -// --------------------------------------------------------------------------- - -class GraphicBuffer; - -class GraphicBufferAlloc : public BnGraphicBufferAlloc { -public: - GraphicBufferAlloc(); - virtual ~GraphicBufferAlloc(); - virtual sp createGraphicBuffer(uint32_t w, uint32_t h, - PixelFormat format, uint32_t usage, status_t* error); -}; - - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_SF_GRAPHIC_BUFFER_ALLOC_H diff --git a/widget/gonk/libdisplay/VirtualDisplaySurface.cpp b/widget/gonk/libdisplay/VirtualDisplaySurface.cpp deleted file mode 100644 index 746707885..000000000 --- a/widget/gonk/libdisplay/VirtualDisplaySurface.cpp +++ /dev/null @@ -1,635 +0,0 @@ -/* - * Copyright 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. - */ - -// #define LOG_NDEBUG 0 -#include "VirtualDisplaySurface.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -#if defined(FORCE_HWC_COPY_FOR_VIRTUAL_DISPLAYS) -static const bool sForceHwcCopy = true; -#else -static const bool sForceHwcCopy = false; -#endif - -#define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \ - mDisplayName.string(), ##__VA_ARGS__) -#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \ - mDisplayName.string(), ##__VA_ARGS__) -#define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \ - mDisplayName.string(), ##__VA_ARGS__) - -__attribute__((unused)) -static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) { - switch (type) { - case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN"; - case DisplaySurface::COMPOSITION_GLES: return "GLES"; - case DisplaySurface::COMPOSITION_HWC: return "HWC"; - case DisplaySurface::COMPOSITION_MIXED: return "MIXED"; - default: return ""; - } -} - -VirtualDisplaySurface::VirtualDisplaySurface(int32_t dispId, - const sp& sink, - const sp& bqProducer, - const sp& bqConsumer, - const String8& name) -: DisplaySurface(bqConsumer), - mDisplayId(dispId), - mDisplayName(name), - mOutputUsage(GRALLOC_USAGE_HW_COMPOSER), - mProducerSlotSource(0), - mDbgState(DBG_STATE_IDLE), - mDbgLastCompositionType(COMPOSITION_UNKNOWN), - mMustRecompose(false) -{ - mSource[SOURCE_SINK] = sink; - mSource[SOURCE_SCRATCH] = bqProducer; - - resetPerFrameState(); - - int sinkWidth, sinkHeight; - sink->query(NATIVE_WINDOW_WIDTH, &sinkWidth); - sink->query(NATIVE_WINDOW_HEIGHT, &sinkHeight); - mSinkBufferWidth = sinkWidth; - mSinkBufferHeight = sinkHeight; - - // Pick the buffer format to request from the sink when not rendering to it - // with GLES. If the consumer needs CPU access, use the default format - // set by the consumer. Otherwise allow gralloc to decide the format based - // on usage bits. - int sinkUsage; - sink->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS, &sinkUsage); - if (sinkUsage & (GRALLOC_USAGE_SW_READ_MASK | GRALLOC_USAGE_SW_WRITE_MASK)) { - int sinkFormat; - sink->query(NATIVE_WINDOW_FORMAT, &sinkFormat); - mDefaultOutputFormat = sinkFormat; - } else { - mDefaultOutputFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED; - } - mOutputFormat = mDefaultOutputFormat; - - ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string()); - mConsumer->setConsumerName(ConsumerBase::mName); - mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); - mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight); - mConsumer->setDefaultMaxBufferCount(2); -} - -VirtualDisplaySurface::~VirtualDisplaySurface() { -} - -status_t VirtualDisplaySurface::beginFrame(bool mustRecompose) { - if (mDisplayId < 0) - return NO_ERROR; - - mMustRecompose = mustRecompose; - - VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE, - "Unexpected beginFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_BEGUN; - - return refreshOutputBuffer(); -} - -status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) { - if (mDisplayId < 0) - return NO_ERROR; - - VDS_LOGW_IF(mDbgState != DBG_STATE_BEGUN, - "Unexpected prepareFrame() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_PREPARED; - - mCompositionType = compositionType; - if (sForceHwcCopy && mCompositionType == COMPOSITION_GLES) { - // Some hardware can do RGB->YUV conversion more efficiently in hardware - // controlled by HWC than in hardware controlled by the video encoder. - // Forcing GLES-composed frames to go through an extra copy by the HWC - // allows the format conversion to happen there, rather than passing RGB - // directly to the consumer. - // - // On the other hand, when the consumer prefers RGB or can consume RGB - // inexpensively, this forces an unnecessary copy. - mCompositionType = COMPOSITION_MIXED; - } - - if (mCompositionType != mDbgLastCompositionType) { - VDS_LOGV("prepareFrame: composition type changed to %s", - dbgCompositionTypeStr(mCompositionType)); - mDbgLastCompositionType = mCompositionType; - } - - if (mCompositionType != COMPOSITION_GLES && - (mOutputFormat != mDefaultOutputFormat || - mOutputUsage != GRALLOC_USAGE_HW_COMPOSER)) { - // We must have just switched from GLES-only to MIXED or HWC - // composition. Stop using the format and usage requested by the GLES - // driver; they may be suboptimal when HWC is writing to the output - // buffer. For example, if the output is going to a video encoder, and - // HWC can write directly to YUV, some hardware can skip a - // memory-to-memory RGB-to-YUV conversion step. - // - // If we just switched *to* GLES-only mode, we'll change the - // format/usage and get a new buffer when the GLES driver calls - // dequeueBuffer(). - mOutputFormat = mDefaultOutputFormat; - mOutputUsage = GRALLOC_USAGE_HW_COMPOSER; - refreshOutputBuffer(); - } - - return NO_ERROR; -} - -status_t VirtualDisplaySurface::compositionComplete() { - return NO_ERROR; -} - -status_t VirtualDisplaySurface::advanceFrame() { - return NO_ERROR; - -// XXX Add HWC support - -#if 0 - if (mDisplayId < 0) - return NO_ERROR; - - if (mCompositionType == COMPOSITION_HWC) { - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected advanceFrame() in %s state on HWC frame", - dbgStateStr()); - } else { - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE, - "Unexpected advanceFrame() in %s state on GLES/MIXED frame", - dbgStateStr()); - } - mDbgState = DBG_STATE_HWC; - - if (mOutputProducerSlot < 0 || - (mCompositionType != COMPOSITION_HWC && mFbProducerSlot < 0)) { - // Last chance bailout if something bad happened earlier. For example, - // in a GLES configuration, if the sink disappears then dequeueBuffer - // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger - // will soldier on. So we end up here without a buffer. There should - // be lots of scary messages in the log just before this. - VDS_LOGE("advanceFrame: no buffer, bailing out"); - return NO_MEMORY; - } - - sp fbBuffer = mFbProducerSlot >= 0 ? - mProducerBuffers[mFbProducerSlot] : sp(NULL); - sp outBuffer = mProducerBuffers[mOutputProducerSlot]; - VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)", - mFbProducerSlot, fbBuffer.get(), - mOutputProducerSlot, outBuffer.get()); - - // At this point we know the output buffer acquire fence, - // so update HWC state with it. - mHwc.setOutputBuffer(mDisplayId, mOutputFence, outBuffer); - - status_t result = NO_ERROR; - if (fbBuffer != NULL) { - result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer); - } - - return result; -#endif -} - -void VirtualDisplaySurface::onFrameCommitted() { - return; - -// XXX Add HWC support - -#if 0 - if (mDisplayId < 0) - return; - - VDS_LOGW_IF(mDbgState != DBG_STATE_HWC, - "Unexpected onFrameCommitted() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_IDLE; - - sp fbFence = mHwc.getAndResetReleaseFence(mDisplayId); - if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) { - // release the scratch buffer back to the pool - Mutex::Autolock lock(mMutex); - int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot); - VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot); - addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence); - releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot], - EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); - } - - if (mOutputProducerSlot >= 0) { - int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot); - QueueBufferOutput qbo; - sp outFence = mHwc.getLastRetireFence(mDisplayId); - VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot); - if (mMustRecompose) { - status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot, - QueueBufferInput( - systemTime(), false /* isAutoTimestamp */, - Rect(mSinkBufferWidth, mSinkBufferHeight), - NATIVE_WINDOW_SCALING_MODE_FREEZE, 0 /* transform */, - true /* async*/, - outFence), - &qbo); - if (result == NO_ERROR) { - updateQueueBufferOutput(qbo); - } - } else { - // If the surface hadn't actually been updated, then we only went - // through the motions of updating the display to keep our state - // machine happy. We cancel the buffer to avoid triggering another - // re-composition and causing an infinite loop. - mSource[SOURCE_SINK]->cancelBuffer(sslot, outFence); - } - } - - resetPerFrameState(); -#endif -} - -void VirtualDisplaySurface::resizeBuffers(const uint32_t w, const uint32_t h) { - uint32_t tmpW, tmpH, transformHint, numPendingBuffers; - mQueueBufferOutput.deflate(&tmpW, &tmpH, &transformHint, &numPendingBuffers); - mQueueBufferOutput.inflate(w, h, transformHint, numPendingBuffers); - - mSinkBufferWidth = w; - mSinkBufferHeight = h; -} - -status_t VirtualDisplaySurface::requestBuffer(int pslot, - sp* outBuf) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->requestBuffer(pslot, outBuf); - - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, - "Unexpected requestBuffer pslot=%d in %s state", - pslot, dbgStateStr()); - - *outBuf = mProducerBuffers[pslot]; - return NO_ERROR; -} - -status_t VirtualDisplaySurface::setBufferCount(int bufferCount) { - return mSource[SOURCE_SINK]->setBufferCount(bufferCount); -} - -status_t VirtualDisplaySurface::dequeueBuffer(Source source, - uint32_t format, uint32_t usage, int* sslot, sp* fence) { - LOG_FATAL_IF(mDisplayId < 0, "mDisplayId=%d but should not be < 0.", mDisplayId); - // Don't let a slow consumer block us - bool async = (source == SOURCE_SINK); - - status_t result = mSource[source]->dequeueBuffer(sslot, fence, async, - mSinkBufferWidth, mSinkBufferHeight, format, usage); - if (result < 0) - return result; - int pslot = mapSource2ProducerSlot(source, *sslot); - VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d", - dbgSourceStr(source), *sslot, pslot, result); - uint64_t sourceBit = static_cast(source) << pslot; - - if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) { - // This slot was previously dequeued from the other source; must - // re-request the buffer. - result |= BUFFER_NEEDS_REALLOCATION; - mProducerSlotSource &= ~(1ULL << pslot); - mProducerSlotSource |= sourceBit; - } - - if (result & RELEASE_ALL_BUFFERS) { - for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { - if ((mProducerSlotSource & (1ULL << i)) == sourceBit) - mProducerBuffers[i].clear(); - } - } - if (result & BUFFER_NEEDS_REALLOCATION) { - result = mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]); - if (result < 0) { - mProducerBuffers[pslot].clear(); - mSource[source]->cancelBuffer(*sslot, *fence); - return result; - } - VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p fmt=%d usage=%#x", - dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(), - mProducerBuffers[pslot]->getPixelFormat(), - mProducerBuffers[pslot]->getUsage()); - } - - return result; -} - -status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->dequeueBuffer(pslot, fence, async, w, h, format, usage); - - VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED, - "Unexpected dequeueBuffer() in %s state", dbgStateStr()); - mDbgState = DBG_STATE_GLES; - - VDS_LOGW_IF(!async, "EGL called dequeueBuffer with !async despite eglSwapInterval(0)"); - VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage); - - status_t result = NO_ERROR; - Source source = fbSourceForCompositionType(mCompositionType); - - if (source == SOURCE_SINK) { - - if (mOutputProducerSlot < 0) { - // Last chance bailout if something bad happened earlier. For example, - // in a GLES configuration, if the sink disappears then dequeueBuffer - // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger - // will soldier on. So we end up here without a buffer. There should - // be lots of scary messages in the log just before this. - VDS_LOGE("dequeueBuffer: no buffer, bailing out"); - return NO_MEMORY; - } - - // We already dequeued the output buffer. If the GLES driver wants - // something incompatible, we have to cancel and get a new one. This - // will mean that HWC will see a different output buffer between - // prepare and set, but since we're in GLES-only mode already it - // shouldn't matter. - - usage |= GRALLOC_USAGE_HW_COMPOSER; - const sp& buf = mProducerBuffers[mOutputProducerSlot]; - if ((usage & ~buf->getUsage()) != 0 || - (format != 0 && format != (uint32_t)buf->getPixelFormat()) || - (w != 0 && w != mSinkBufferWidth) || - (h != 0 && h != mSinkBufferHeight)) { - VDS_LOGV("dequeueBuffer: dequeueing new output buffer: " - "want %dx%d fmt=%d use=%#x, " - "have %dx%d fmt=%d use=%#x", - w, h, format, usage, - mSinkBufferWidth, mSinkBufferHeight, - buf->getPixelFormat(), buf->getUsage()); - mOutputFormat = format; - mOutputUsage = usage; - result = refreshOutputBuffer(); - if (result < 0) - return result; - } - } - - if (source == SOURCE_SINK) { - *pslot = mOutputProducerSlot; - *fence = mOutputFence; - } else { - int sslot; - result = dequeueBuffer(source, format, usage, &sslot, fence); - if (result >= 0) { - *pslot = mapSource2ProducerSlot(source, sslot); - } - } - return result; -} - -status_t VirtualDisplaySurface::detachBuffer(int /* slot */) { - VDS_LOGE("detachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; -} - -status_t VirtualDisplaySurface::detachNextBuffer( - sp* /* outBuffer */, sp* /* outFence */) { - VDS_LOGE("detachNextBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; -} - -status_t VirtualDisplaySurface::attachBuffer(int* /* outSlot */, - const sp& /* buffer */) { - VDS_LOGE("attachBuffer is not available for VirtualDisplaySurface"); - return INVALID_OPERATION; -} - -status_t VirtualDisplaySurface::queueBuffer(int pslot, - const QueueBufferInput& input, QueueBufferOutput* output) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->queueBuffer(pslot, input, output); - - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, - "Unexpected queueBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - mDbgState = DBG_STATE_GLES_DONE; - - VDS_LOGV("queueBuffer pslot=%d", pslot); - - status_t result; - if (mCompositionType == COMPOSITION_MIXED) { - // Queue the buffer back into the scratch pool - QueueBufferOutput scratchQBO; - int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot); - result = mSource[SOURCE_SCRATCH]->queueBuffer(sslot, input, &scratchQBO); - if (result != NO_ERROR) - return result; - - // Now acquire the buffer from the scratch pool -- should be the same - // slot and fence as we just queued. - Mutex::Autolock lock(mMutex); - BufferQueue::BufferItem item; - result = acquireBufferLocked(&item, 0); - if (result != NO_ERROR) - return result; - VDS_LOGW_IF(item.mBuf != sslot, - "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d", - item.mBuf, sslot); - mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf); - mFbFence = mSlots[item.mBuf].mFence; - - } else { - LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES, - "Unexpected queueBuffer in state %s for compositionType %s", - dbgStateStr(), dbgCompositionTypeStr(mCompositionType)); - - // Extract the GLES release fence for HWC to acquire - int64_t timestamp; - bool isAutoTimestamp; - Rect crop; - int scalingMode; - uint32_t transform; - bool async; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, - &transform, &async, &mFbFence); - - mFbProducerSlot = pslot; - mOutputFence = mFbFence; - } - - *output = mQueueBufferOutput; - return NO_ERROR; -} - -void VirtualDisplaySurface::cancelBuffer(int pslot, const sp& fence) { - if (mDisplayId < 0) - return mSource[SOURCE_SINK]->cancelBuffer(mapProducer2SourceSlot(SOURCE_SINK, pslot), fence); - - VDS_LOGW_IF(mDbgState != DBG_STATE_GLES, - "Unexpected cancelBuffer(pslot=%d) in %s state", pslot, - dbgStateStr()); - VDS_LOGV("cancelBuffer pslot=%d", pslot); - Source source = fbSourceForCompositionType(mCompositionType); - return mSource[source]->cancelBuffer( - mapProducer2SourceSlot(source, pslot), fence); -} - -int VirtualDisplaySurface::query(int what, int* value) { - switch (what) { - case NATIVE_WINDOW_WIDTH: - *value = mSinkBufferWidth; - break; - case NATIVE_WINDOW_HEIGHT: - *value = mSinkBufferHeight; - break; - default: - return mSource[SOURCE_SINK]->query(what, value); - } - return NO_ERROR; -} - -#if ANDROID_VERSION >= 21 -status_t VirtualDisplaySurface::connect(const sp& listener, - int api, bool producerControlledByApp, - QueueBufferOutput* output) { - QueueBufferOutput qbo; - status_t result = mSource[SOURCE_SINK]->connect(listener, api, - producerControlledByApp, &qbo); - if (result == NO_ERROR) { - updateQueueBufferOutput(qbo); - *output = mQueueBufferOutput; - } - return result; -} -#else -status_t VirtualDisplaySurface::connect(const sp& token, - int api, bool producerControlledByApp, - QueueBufferOutput* output) { - QueueBufferOutput qbo; - status_t result = mSource[SOURCE_SINK]->connect(token, api, producerControlledByApp, &qbo); - if (result == NO_ERROR) { - updateQueueBufferOutput(qbo); - *output = mQueueBufferOutput; - } - return result; -} -#endif - -status_t VirtualDisplaySurface::disconnect(int api) { - return mSource[SOURCE_SINK]->disconnect(api); -} - -#if ANDROID_VERSION >= 21 -status_t VirtualDisplaySurface::setSidebandStream(const sp& /*stream*/) { - return INVALID_OPERATION; -} -#endif - -void VirtualDisplaySurface::allocateBuffers(bool /* async */, - uint32_t /* width */, uint32_t /* height */, uint32_t /* format */, - uint32_t /* usage */) { - // TODO: Should we actually allocate buffers for a virtual display? -} - -void VirtualDisplaySurface::updateQueueBufferOutput( - const QueueBufferOutput& qbo) { - uint32_t w, h, transformHint, numPendingBuffers; - qbo.deflate(&w, &h, &transformHint, &numPendingBuffers); - mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers); -} - -void VirtualDisplaySurface::resetPerFrameState() { - mCompositionType = COMPOSITION_UNKNOWN; - mFbFence = Fence::NO_FENCE; - mOutputFence = Fence::NO_FENCE; - mOutputProducerSlot = -1; - mFbProducerSlot = -1; -} - -status_t VirtualDisplaySurface::refreshOutputBuffer() { - - return INVALID_OPERATION; - -// XXX Add HWC support - -#if 0 - if (mOutputProducerSlot >= 0) { - mSource[SOURCE_SINK]->cancelBuffer( - mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot), - mOutputFence); - } - - int sslot; - status_t result = dequeueBuffer(SOURCE_SINK, mOutputFormat, mOutputUsage, - &sslot, &mOutputFence); - if (result < 0) - return result; - mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot); - - // On GLES-only frames, we don't have the right output buffer acquire fence - // until after GLES calls queueBuffer(). So here we just set the buffer - // (for use in HWC prepare) but not the fence; we'll call this again with - // the proper fence once we have it. - result = mHwc.setOutputBuffer(mDisplayId, Fence::NO_FENCE, - mProducerBuffers[mOutputProducerSlot]); - - return result; -#endif -} - -// This slot mapping function is its own inverse, so two copies are unnecessary. -// Both are kept to make the intent clear where the function is called, and for -// the (unlikely) chance that we switch to a different mapping function. -int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) { - if (source == SOURCE_SCRATCH) { - return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1; - } else { - return sslot; - } -} -int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) { - return mapSource2ProducerSlot(source, pslot); -} - -VirtualDisplaySurface::Source -VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) { - return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK; -} - -const char* VirtualDisplaySurface::dbgStateStr() const { - switch (mDbgState) { - case DBG_STATE_IDLE: return "IDLE"; - case DBG_STATE_PREPARED: return "PREPARED"; - case DBG_STATE_GLES: return "GLES"; - case DBG_STATE_GLES_DONE: return "GLES_DONE"; - case DBG_STATE_HWC: return "HWC"; - default: return "INVALID"; - } -} - -const char* VirtualDisplaySurface::dbgSourceStr(Source s) { - switch (s) { - case SOURCE_SINK: return "SINK"; - case SOURCE_SCRATCH: return "SCRATCH"; - default: return "INVALID"; - } -} - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- diff --git a/widget/gonk/libdisplay/VirtualDisplaySurface.h b/widget/gonk/libdisplay/VirtualDisplaySurface.h deleted file mode 100644 index 9125d8751..000000000 --- a/widget/gonk/libdisplay/VirtualDisplaySurface.h +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright 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. - */ - -#ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H -#define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H - -#include - -#include "DisplaySurface.h" - -// --------------------------------------------------------------------------- -namespace android { -// --------------------------------------------------------------------------- - -class HWComposer; -class IProducerListener; - -/* This DisplaySurface implementation supports virtual displays, where GLES - * and/or HWC compose into a buffer that is then passed to an arbitrary - * consumer (the sink) running in another process. - * - * The simplest case is when the virtual display will never use the h/w - * composer -- either the h/w composer doesn't support writing to buffers, or - * there are more virtual displays than it supports simultaneously. In this - * case, the GLES driver works directly with the output buffer queue, and - * calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do - * nothing. - * - * If h/w composer might be used, then each frame will fall into one of three - * configurations: GLES-only, HWC-only, and MIXED composition. In all of these, - * we must provide a FB target buffer and output buffer for the HWC set() call. - * - * In GLES-only composition, the GLES driver is given a buffer from the sink to - * render into. When the GLES driver queues the buffer to the - * VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of - * immediately queueing it to the sink. The buffer is used as both the FB - * target and output buffer for HWC, though on these frames the HWC doesn't - * do any work for this display and doesn't write to the output buffer. After - * composition is complete, the buffer is queued to the sink. - * - * In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from - * the sink and passes it to HWC as both the FB target buffer and output - * buffer. The HWC doesn't need to read from the FB target buffer, but does - * write to the output buffer. After composition is complete, the buffer is - * queued to the sink. - * - * On MIXED frames, things become more complicated, since some h/w composer - * implementations can't read from and write to the same buffer. This class has - * an internal BufferQueue that it uses as a scratch buffer pool. The GLES - * driver is given a scratch buffer to render into. When it finishes rendering, - * the buffer is queued and then immediately acquired by the - * VirtualDisplaySurface. The scratch buffer is then used as the FB target - * buffer for HWC, and a separate buffer is dequeued from the sink and used as - * the HWC output buffer. When HWC composition is complete, the scratch buffer - * is released and the output buffer is queued to the sink. - */ -class VirtualDisplaySurface : public DisplaySurface, - public BnGraphicBufferProducer { -public: - VirtualDisplaySurface(int32_t dispId, - const sp& sink, - const sp& bqProducer, - const sp& bqConsumer, - const String8& name); - - // - // DisplaySurface interface - // - virtual status_t beginFrame(bool mustRecompose); - virtual status_t prepareFrame(CompositionType compositionType); - virtual status_t compositionComplete(); - virtual status_t advanceFrame(); - virtual void onFrameCommitted(); - virtual void resizeBuffers(const uint32_t w, const uint32_t h); - - virtual status_t setReleaseFenceFd(int fenceFd) { return INVALID_OPERATION; } - virtual int GetPrevDispAcquireFd() { return -1; }; - -private: - enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1}; - - virtual ~VirtualDisplaySurface(); - - // - // IGraphicBufferProducer interface, used by the GLES driver. - // - virtual status_t requestBuffer(int pslot, sp* outBuf); - virtual status_t setBufferCount(int bufferCount); - virtual status_t dequeueBuffer(int* pslot, sp* fence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage); - virtual status_t detachBuffer(int slot); - virtual status_t detachNextBuffer(sp* outBuffer, - sp* outFence); - virtual status_t attachBuffer(int* slot, const sp& buffer); - virtual status_t queueBuffer(int pslot, - const QueueBufferInput& input, QueueBufferOutput* output); - virtual void cancelBuffer(int pslot, const sp& fence); - virtual int query(int what, int* value); -#if ANDROID_VERSION >= 21 - virtual status_t connect(const sp& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output); -#else - virtual status_t connect(const sp& token, - int api, bool producerControlledByApp, QueueBufferOutput* output); -#endif - virtual status_t disconnect(int api); -#if ANDROID_VERSION >= 21 - virtual status_t setSidebandStream(const sp& stream); -#endif - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); - - // - // Utility methods - // - static Source fbSourceForCompositionType(CompositionType type); - status_t dequeueBuffer(Source source, uint32_t format, uint32_t usage, - int* sslot, sp* fence); - void updateQueueBufferOutput(const QueueBufferOutput& qbo); - void resetPerFrameState(); - status_t refreshOutputBuffer(); - - // Both the sink and scratch buffer pools have their own set of slots - // ("source slots", or "sslot"). We have to merge these into the single - // set of slots used by the GLES producer ("producer slots" or "pslot") and - // internally in the VirtualDisplaySurface. To minimize the number of times - // a producer slot switches which source it comes from, we map source slot - // numbers to producer slot numbers differently for each source. - static int mapSource2ProducerSlot(Source source, int sslot); - static int mapProducer2SourceSlot(Source source, int pslot); - - // - // Immutable after construction - // - const int32_t mDisplayId; - const String8 mDisplayName; - sp mSource[2]; // indexed by SOURCE_* - uint32_t mDefaultOutputFormat; - - // - // Inter-frame state - // - - // To avoid buffer reallocations, we track the buffer usage and format - // we used on the previous frame and use it again on the new frame. If - // the composition type changes or the GLES driver starts requesting - // different usage/format, we'll get a new buffer. - uint32_t mOutputFormat; - uint32_t mOutputUsage; - - // Since we present a single producer interface to the GLES driver, but - // are internally muxing between the sink and scratch producers, we have - // to keep track of which source last returned each producer slot from - // dequeueBuffer. Each bit in mProducerSlotSource corresponds to a producer - // slot. Both mProducerSlotSource and mProducerBuffers are indexed by a - // "producer slot"; see the mapSlot*() functions. - uint64_t mProducerSlotSource; - sp mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS]; - - // The QueueBufferOutput with the latest info from the sink, and with the - // transform hint cleared. Since we defer queueBuffer from the GLES driver - // to the sink, we have to return the previous version. - QueueBufferOutput mQueueBufferOutput; - - // Details of the current sink buffer. These become valid when a buffer is - // dequeued from the sink, and are used when queueing the buffer. - uint32_t mSinkBufferWidth, mSinkBufferHeight; - - // - // Intra-frame state - // - - // Composition type and GLES buffer source for the current frame. - // Valid after prepareFrame(), cleared in onFrameCommitted. - CompositionType mCompositionType; - - // mFbFence is the fence HWC should wait for before reading the framebuffer - // target buffer. - sp mFbFence; - - // mOutputFence is the fence HWC should wait for before writing to the - // output buffer. - sp mOutputFence; - - // Producer slot numbers for the buffers to use for HWC framebuffer target - // and output. - int mFbProducerSlot; - int mOutputProducerSlot; - - // Debug only -- track the sequence of events in each frame so we can make - // sure they happen in the order we expect. This class implicitly models - // a state machine; this enum/variable makes it explicit. - // - // +-----------+-------------------+-------------+ - // | State | Event || Next State | - // +-----------+-------------------+-------------+ - // | IDLE | beginFrame || BEGUN | - // | BEGUN | prepareFrame || PREPARED | - // | PREPARED | dequeueBuffer [1] || GLES | - // | PREPARED | advanceFrame [2] || HWC | - // | GLES | queueBuffer || GLES_DONE | - // | GLES_DONE | advanceFrame || HWC | - // | HWC | onFrameCommitted || IDLE | - // +-----------+-------------------++------------+ - // [1] COMPOSITION_GLES and COMPOSITION_MIXED frames. - // [2] COMPOSITION_HWC frames. - // - enum DbgState { - // no buffer dequeued, don't know anything about the next frame - DBG_STATE_IDLE, - // output buffer dequeued, framebuffer source not yet known - DBG_STATE_BEGUN, - // output buffer dequeued, framebuffer source known but not provided - // to GLES yet. - DBG_STATE_PREPARED, - // GLES driver has a buffer dequeued - DBG_STATE_GLES, - // GLES driver has queued the buffer, we haven't sent it to HWC yet - DBG_STATE_GLES_DONE, - // HWC has the buffer for this frame - DBG_STATE_HWC, - }; - DbgState mDbgState; - CompositionType mDbgLastCompositionType; - - const char* dbgStateStr() const; - static const char* dbgSourceStr(Source s); - - bool mMustRecompose; -}; - -// --------------------------------------------------------------------------- -} // namespace android -// --------------------------------------------------------------------------- - -#endif // ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H - diff --git a/widget/gonk/libdisplay/moz.build b/widget/gonk/libdisplay/moz.build deleted file mode 100644 index 917320592..000000000 --- a/widget/gonk/libdisplay/moz.build +++ /dev/null @@ -1,59 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -SOURCES += [ - 'BootAnimation.cpp', -] - -if CONFIG['ANDROID_VERSION'] >= '19': - SOURCES += [ - 'FramebufferSurface.cpp', - 'GonkDisplayJB.cpp', - 'VirtualDisplaySurface.cpp', - ] -elif CONFIG['ANDROID_VERSION'] == '18': - SOURCES += [ - 'FramebufferSurface.cpp', - 'GonkDisplayJB.cpp', - ] -elif CONFIG['ANDROID_VERSION'] == '17': - SOURCES += [ - 'FramebufferSurface.cpp', - 'GonkDisplayJB.cpp', - 'GraphicBufferAlloc.cpp', - ] -elif CONFIG['ANDROID_VERSION'] and CONFIG['COMPILE_ENVIRONMENT']: - error('Unsupported platform version: %s' % (CONFIG['ANDROID_VERSION'])) - -Library('display') - -include('/ipc/chromium/chromium-config.mozbuild') - -FORCE_STATIC_LIB = True - -DEFINES['XPCOM_GLUE'] = True - -DISABLE_STL_WRAPPING = True - -LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/include/gui', - 'frameworks/native/opengl/include', - 'hardware/libhardware/include', - 'hardware/libhardware_legacy/include', - 'system/core/libsuspend/include', - ] -] diff --git a/widget/gonk/libui/EventHub.cpp b/widget/gonk/libui/EventHub.cpp deleted file mode 100644 index 9da29bbeb..000000000 --- a/widget/gonk/libui/EventHub.cpp +++ /dev/null @@ -1,1549 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -#define LOG_TAG "EventHub" - -// #define LOG_NDEBUG 0 -#include "cutils_log.h" - -#include "EventHub.h" - -#include - -#include -#include "cutils_log.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include "KeyLayoutMap.h" -#include "KeyCharacterMap.h" -#include "VirtualKeyMap.h" - -#include -#include -#include - -#include -#include -#include -#include -#include "sha1.h" - -/* this macro is used to tell if "bit" is set in "array" - * it selects a byte from the array, and does a boolean AND - * operation with a byte that only has the relevant bit set. - * eg. to check for the 12th bit, we do (array[1] & 1<<4) - */ -#define test_bit(bit, array) (array[bit/8] & (1<<(bit%8))) - -/* this macro computes the number of bytes needed to represent a bit array of the specified size */ -#define sizeof_bit_array(bits) ((bits + 7) / 8) - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " - -namespace android { - -static const char *WAKE_LOCK_ID = "KeyEvents"; -static const char *DEVICE_PATH = "/dev/input"; - -/* return the larger integer */ -static inline int max(int v1, int v2) -{ - return (v1 > v2) ? v1 : v2; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static String8 sha1(const String8& in) { - SHA1_CTX ctx; - SHA1Init(&ctx); - SHA1Update(&ctx, reinterpret_cast(in.string()), in.size()); - u_char digest[SHA1_DIGEST_LENGTH]; - SHA1Final(digest, &ctx); - - String8 out; - for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) { - out.appendFormat("%02x", digest[i]); - } - return out; -} - -static void setDescriptor(InputDeviceIdentifier& identifier) { - // Compute a device descriptor that uniquely identifies the device. - // The descriptor is assumed to be a stable identifier. Its value should not - // change between reboots, reconnections, firmware updates or new releases of Android. - // Ideally, we also want the descriptor to be short and relatively opaque. - String8 rawDescriptor; - rawDescriptor.appendFormat(":%04x:%04x:", identifier.vendor, identifier.product); - if (!identifier.uniqueId.isEmpty()) { - rawDescriptor.append("uniqueId:"); - rawDescriptor.append(identifier.uniqueId); - } if (identifier.vendor == 0 && identifier.product == 0) { - // If we don't know the vendor and product id, then the device is probably - // built-in so we need to rely on other information to uniquely identify - // the input device. Usually we try to avoid relying on the device name or - // location but for built-in input device, they are unlikely to ever change. - if (!identifier.name.isEmpty()) { - rawDescriptor.append("name:"); - rawDescriptor.append(identifier.name); - } else if (!identifier.location.isEmpty()) { - rawDescriptor.append("location:"); - rawDescriptor.append(identifier.location); - } - } - identifier.descriptor = sha1(rawDescriptor); - ALOGV("Created descriptor: raw=%s, cooked=%s", rawDescriptor.string(), - identifier.descriptor.string()); -} - -// --- Global Functions --- - -uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { - // Touch devices get dibs on touch-related axes. - if (deviceClasses & INPUT_DEVICE_CLASS_TOUCH) { - switch (axis) { - case ABS_X: - case ABS_Y: - case ABS_PRESSURE: - case ABS_TOOL_WIDTH: - case ABS_DISTANCE: - case ABS_TILT_X: - case ABS_TILT_Y: - case ABS_MT_SLOT: - case ABS_MT_TOUCH_MAJOR: - case ABS_MT_TOUCH_MINOR: - case ABS_MT_WIDTH_MAJOR: - case ABS_MT_WIDTH_MINOR: - case ABS_MT_ORIENTATION: - case ABS_MT_POSITION_X: - case ABS_MT_POSITION_Y: - case ABS_MT_TOOL_TYPE: - case ABS_MT_BLOB_ID: - case ABS_MT_TRACKING_ID: - case ABS_MT_PRESSURE: - case ABS_MT_DISTANCE: - return INPUT_DEVICE_CLASS_TOUCH; - } - } - - // Joystick devices get the rest. - return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; -} - -// --- EventHub::Device --- - -EventHub::Device::Device(int fd, int32_t id, const String8& path, - const InputDeviceIdentifier& identifier) : - next(NULL), - fd(fd), id(id), path(path), identifier(identifier), - classes(0), configuration(NULL), virtualKeyMap(NULL), - ffEffectPlaying(false), ffEffectId(-1), - timestampOverrideSec(0), timestampOverrideUsec(0) { - memset(keyBitmask, 0, sizeof(keyBitmask)); - memset(absBitmask, 0, sizeof(absBitmask)); - memset(relBitmask, 0, sizeof(relBitmask)); - memset(swBitmask, 0, sizeof(swBitmask)); - memset(ledBitmask, 0, sizeof(ledBitmask)); - memset(ffBitmask, 0, sizeof(ffBitmask)); - memset(propBitmask, 0, sizeof(propBitmask)); -} - -EventHub::Device::~Device() { - close(); - delete configuration; - delete virtualKeyMap; -} - -void EventHub::Device::close() { - if (fd >= 0) { - ::close(fd); - fd = -1; - } -} - - -// --- EventHub --- - -const uint32_t EventHub::EPOLL_ID_INOTIFY; -const uint32_t EventHub::EPOLL_ID_WAKE; -const int EventHub::EPOLL_SIZE_HINT; -const int EventHub::EPOLL_MAX_EVENTS; - -EventHub::EventHub(void) : - mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), - mOpeningDevices(0), mClosingDevices(0), - mNeedToSendFinishedDeviceScan(false), - mNeedToReopenDevices(false), mNeedToScanDevices(true), - mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) { - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - - mEpollFd = epoll_create(EPOLL_SIZE_HINT); - LOG_ALWAYS_FATAL_IF(mEpollFd < 0, "Could not create epoll instance. errno=%d", errno); - - mINotifyFd = inotify_init(); - int result = inotify_add_watch(mINotifyFd, DEVICE_PATH, IN_DELETE | IN_CREATE); - LOG_ALWAYS_FATAL_IF(result < 0, "Could not register INotify for %s. errno=%d", - DEVICE_PATH, errno); - - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - eventItem.data.u32 = EPOLL_ID_INOTIFY; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mINotifyFd, &eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add INotify to epoll instance. errno=%d", errno); - - int wakeFds[2]; - result = pipe(wakeFds); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not create wake pipe. errno=%d", errno); - - mWakeReadPipeFd = wakeFds[0]; - mWakeWritePipeFd = wakeFds[1]; - - result = fcntl(mWakeReadPipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake read pipe non-blocking. errno=%d", - errno); - - result = fcntl(mWakeWritePipeFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not make wake write pipe non-blocking. errno=%d", - errno); - - eventItem.data.u32 = EPOLL_ID_WAKE; - result = epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeReadPipeFd, &eventItem); - LOG_ALWAYS_FATAL_IF(result != 0, "Could not add wake read pipe to epoll instance. errno=%d", - errno); -} - -EventHub::~EventHub(void) { - closeAllDevicesLocked(); - - while (mClosingDevices) { - Device* device = mClosingDevices; - mClosingDevices = device->next; - delete device; - } - - ::close(mEpollFd); - ::close(mINotifyFd); - ::close(mWakeReadPipeFd); - ::close(mWakeWritePipeFd); - - release_wake_lock(WAKE_LOCK_ID); -} - -InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return InputDeviceIdentifier(); - return device->identifier; -} - -uint32_t EventHub::getDeviceClasses(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device == NULL) return 0; - return device->classes; -} - -void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->configuration) { - *outConfiguration = *device->configuration; - } else { - outConfiguration->clear(); - } -} - -status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const { - outAxisInfo->clear(); - - if (axis >= 0 && axis <= ABS_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { - struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.string(), device->fd, errno); - return -errno; - } - - if (info.minimum != info.maximum) { - outAxisInfo->valid = true; - outAxisInfo->minValue = info.minimum; - outAxisInfo->maxValue = info.maximum; - outAxisInfo->flat = info.flat; - outAxisInfo->fuzz = info.fuzz; - outAxisInfo->resolution = info.resolution; - } - return OK; - } - } - return -1; -} - -bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const { - if (axis >= 0 && axis <= REL_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device) { - return test_bit(axis, device->relBitmask); - } - } - return false; -} - -bool EventHub::hasInputProperty(int32_t deviceId, int property) const { - if (property >= 0 && property <= INPUT_PROP_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device) { - return test_bit(property, device->propBitmask); - } - } - return false; -} - -int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const { - if (scanCode >= 0 && scanCode <= KEY_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(scanCode, device->keyBitmask)) { - uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; - memset(keyState, 0, sizeof(keyState)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { - return test_bit(scanCode, keyState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && device->keyMap.haveKeyLayout()) { - Vector scanCodes; - device->keyMap.keyLayoutMap->findScanCodesForKey(keyCode, &scanCodes); - if (scanCodes.size() != 0) { - uint8_t keyState[sizeof_bit_array(KEY_MAX + 1)]; - memset(keyState, 0, sizeof(keyState)); - if (ioctl(device->fd, EVIOCGKEY(sizeof(keyState)), keyState) >= 0) { - for (size_t i = 0; i < scanCodes.size(); i++) { - int32_t sc = scanCodes.itemAt(i); - if (sc >= 0 && sc <= KEY_MAX && test_bit(sc, keyState)) { - return AKEY_STATE_DOWN; - } - } - return AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const { - if (sw >= 0 && sw <= SW_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(sw, device->swBitmask)) { - uint8_t swState[sizeof_bit_array(SW_MAX + 1)]; - memset(swState, 0, sizeof(swState)); - if (ioctl(device->fd, EVIOCGSW(sizeof(swState)), swState) >= 0) { - return test_bit(sw, swState) ? AKEY_STATE_DOWN : AKEY_STATE_UP; - } - } - } - return AKEY_STATE_UNKNOWN; -} - -status_t EventHub::getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const { - *outValue = 0; - - if (axis >= 0 && axis <= ABS_MAX) { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && test_bit(axis, device->absBitmask)) { - struct input_absinfo info; - if(ioctl(device->fd, EVIOCGABS(axis), &info)) { - ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d", - axis, device->identifier.name.string(), device->fd, errno); - return -errno; - } - - *outValue = info.value; - return OK; - } - } - return -1; -} - -bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const { - AutoMutex _l(mLock); - - Device* device = getDeviceLocked(deviceId); - if (device && device->keyMap.haveKeyLayout()) { - Vector scanCodes; - for (size_t codeIndex = 0; codeIndex < numCodes; codeIndex++) { - scanCodes.clear(); - - status_t err = device->keyMap.keyLayoutMap->findScanCodesForKey( - keyCodes[codeIndex], &scanCodes); - if (! err) { - // check the possible scan codes identified by the layout map against the - // map of codes actually emitted by the driver - for (size_t sc = 0; sc < scanCodes.size(); sc++) { - if (test_bit(scanCodes[sc], device->keyBitmask)) { - outFlags[codeIndex] = 1; - break; - } - } - } - } - return true; - } - return false; -} - -status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device) { - // Check the key character map first. - sp kcm = device->getKeyCharacterMap(); - if (kcm != NULL) { - if (!kcm->mapKey(scanCode, usageCode, outKeycode)) { - *outFlags = 0; - return NO_ERROR; - } - } - - // Check the key layout next. - if (device->keyMap.haveKeyLayout()) { - if (!device->keyMap.keyLayoutMap->mapKey( - scanCode, usageCode, outKeycode, outFlags)) { - return NO_ERROR; - } - } - } - - *outKeycode = 0; - *outFlags = 0; - return NAME_NOT_FOUND; -} - -status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - - if (device && device->keyMap.haveKeyLayout()) { - status_t err = device->keyMap.keyLayoutMap->mapAxis(scanCode, outAxisInfo); - if (err == NO_ERROR) { - return NO_ERROR; - } - } - - return NAME_NOT_FOUND; -} - -void EventHub::setExcludedDevices(const Vector& devices) { - AutoMutex _l(mLock); - - mExcludedDevices = devices; -} - -bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && scanCode >= 0 && scanCode <= KEY_MAX) { - if (test_bit(scanCode, device->keyBitmask)) { - return true; - } - } - return false; -} - -bool EventHub::hasLed(int32_t deviceId, int32_t led) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && led >= 0 && led <= LED_MAX) { - if (test_bit(led, device->ledBitmask)) { - return true; - } - } - return false; -} - -void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual() && led >= 0 && led <= LED_MAX) { - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_LED; - ev.code = led; - ev.value = on ? 1 : 0; - - ssize_t nWrite; - do { - nWrite = write(device->fd, &ev, sizeof(struct input_event)); - } while (nWrite == -1 && errno == EINTR); - } -} - -void EventHub::getVirtualKeyDefinitions(int32_t deviceId, - Vector& outVirtualKeys) const { - outVirtualKeys.clear(); - - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && device->virtualKeyMap) { - outVirtualKeys.appendVector(device->virtualKeyMap->getVirtualKeys()); - } -} - -sp EventHub::getKeyCharacterMap(int32_t deviceId) const { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - return device->getKeyCharacterMap(); - } - return NULL; -} - -bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, - const sp& map) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device) { - if (map != device->overlayKeyMap) { - device->overlayKeyMap = map; - device->combinedKeyMap = KeyCharacterMap::combine( - device->keyMap.keyCharacterMap, map); - return true; - } - } - return false; -} - -void EventHub::vibrate(int32_t deviceId, nsecs_t duration) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { - ff_effect effect; - memset(&effect, 0, sizeof(effect)); - effect.type = FF_RUMBLE; - effect.id = device->ffEffectId; - effect.u.rumble.strong_magnitude = 0xc000; - effect.u.rumble.weak_magnitude = 0xc000; - effect.replay.length = (duration + 999999LL) / 1000000LL; - effect.replay.delay = 0; - if (ioctl(device->fd, EVIOCSFF, &effect)) { - ALOGW("Could not upload force feedback effect to device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - device->ffEffectId = effect.id; - - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_FF; - ev.code = device->ffEffectId; - ev.value = 1; - if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { - ALOGW("Could not start force feedback effect on device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - device->ffEffectPlaying = true; - } -} - -void EventHub::cancelVibrate(int32_t deviceId) { - AutoMutex _l(mLock); - Device* device = getDeviceLocked(deviceId); - if (device && !device->isVirtual()) { - if (device->ffEffectPlaying) { - device->ffEffectPlaying = false; - - struct input_event ev; - ev.time.tv_sec = 0; - ev.time.tv_usec = 0; - ev.type = EV_FF; - ev.code = device->ffEffectId; - ev.value = 0; - if (write(device->fd, &ev, sizeof(ev)) != sizeof(ev)) { - ALOGW("Could not stop force feedback effect on device %s due to error %d.", - device->identifier.name.string(), errno); - return; - } - } - } -} - -EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const { - if (deviceId == BUILT_IN_KEYBOARD_ID) { - deviceId = mBuiltInKeyboardId; - } - ssize_t index = mDevices.indexOfKey(deviceId); - return index >= 0 ? mDevices.valueAt(index) : NULL; -} - -EventHub::Device* EventHub::getDeviceByPathLocked(const char* devicePath) const { - for (size_t i = 0; i < mDevices.size(); i++) { - Device* device = mDevices.valueAt(i); - if (device->path == devicePath) { - return device; - } - } - return NULL; -} - -size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) { - ALOG_ASSERT(bufferSize >= 1); - - AutoMutex _l(mLock); - - struct input_event readBuffer[bufferSize]; - - RawEvent* event = buffer; - size_t capacity = bufferSize; - bool awoken = false; - for (;;) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - // Reopen input devices if needed. - if (mNeedToReopenDevices) { - mNeedToReopenDevices = false; - - ALOGI("Reopening all input devices due to a configuration change."); - - closeAllDevicesLocked(); - mNeedToScanDevices = true; - break; // return to the caller before we actually rescan - } - - // Report any devices that had last been added/removed. - while (mClosingDevices) { - Device* device = mClosingDevices; - ALOGV("Reporting device closed: id=%d, name=%s\n", - device->id, device->path.string()); - mClosingDevices = device->next; - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? BUILT_IN_KEYBOARD_ID : device->id; - event->type = DEVICE_REMOVED; - event += 1; - delete device; - mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { - break; - } - } - - if (mNeedToScanDevices) { - mNeedToScanDevices = false; - scanDevicesLocked(); - mNeedToSendFinishedDeviceScan = true; - } - - while (mOpeningDevices != NULL) { - Device* device = mOpeningDevices; - ALOGV("Reporting device opened: id=%d, name=%s\n", - device->id, device->path.string()); - mOpeningDevices = device->next; - event->when = now; - event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - event->type = DEVICE_ADDED; - event += 1; - mNeedToSendFinishedDeviceScan = true; - if (--capacity == 0) { - break; - } - } - - if (mNeedToSendFinishedDeviceScan) { - mNeedToSendFinishedDeviceScan = false; - event->when = now; - event->type = FINISHED_DEVICE_SCAN; - event += 1; - if (--capacity == 0) { - break; - } - } - - // Grab the next input event. - bool deviceChanged = false; - while (mPendingEventIndex < mPendingEventCount) { - const struct epoll_event& eventItem = mPendingEventItems[mPendingEventIndex++]; - if (eventItem.data.u32 == EPOLL_ID_INOTIFY) { - if (eventItem.events & EPOLLIN) { - mPendingINotify = true; - } else { - ALOGW("Received unexpected epoll event 0x%08x for INotify.", eventItem.events); - } - continue; - } - - if (eventItem.data.u32 == EPOLL_ID_WAKE) { - if (eventItem.events & EPOLLIN) { - ALOGV("awoken after wake()"); - awoken = true; - char buffer[16]; - ssize_t nRead; - do { - nRead = read(mWakeReadPipeFd, buffer, sizeof(buffer)); - } while ((nRead == -1 && errno == EINTR) || nRead == sizeof(buffer)); - } else { - ALOGW("Received unexpected epoll event 0x%08x for wake read pipe.", - eventItem.events); - } - continue; - } - - ssize_t deviceIndex = mDevices.indexOfKey(eventItem.data.u32); - if (deviceIndex < 0) { - ALOGW("Received unexpected epoll event 0x%08x for unknown device id %d.", - eventItem.events, eventItem.data.u32); - continue; - } - - Device* device = mDevices.valueAt(deviceIndex); - if (eventItem.events & EPOLLIN) { - int32_t readSize = read(device->fd, readBuffer, - sizeof(struct input_event) * capacity); - if (readSize == 0 || (readSize < 0 && errno == ENODEV)) { - // Device was removed before INotify noticed. - ALOGW("could not get event, removed? (fd: %d size: %d bufferSize: %d " - "capacity: %d errno: %d)\n", - device->fd, readSize, bufferSize, capacity, errno); - deviceChanged = true; - closeDeviceLocked(device); - } else if (readSize < 0) { - if (errno != EAGAIN && errno != EINTR) { - ALOGW("could not get event (errno=%d)", errno); - } - } else if ((readSize % sizeof(struct input_event)) != 0) { - ALOGE("could not get event (wrong size: %d)", readSize); - } else { - int32_t deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id; - - size_t count = size_t(readSize) / sizeof(struct input_event); - for (size_t i = 0; i < count; i++) { - struct input_event& iev = readBuffer[i]; - ALOGV("%s got: time=%d.%06d, type=%d, code=%d, value=%d", - device->path.string(), - (int) iev.time.tv_sec, (int) iev.time.tv_usec, - iev.type, iev.code, iev.value); - - // Some input devices may have a better concept of the time - // when an input event was actually generated than the kernel - // which simply timestamps all events on entry to evdev. - // This is a custom Android extension of the input protocol - // mainly intended for use with uinput based device drivers. - if (iev.type == EV_MSC) { - if (iev.code == MSC_ANDROID_TIME_SEC) { - device->timestampOverrideSec = iev.value; - continue; - } else if (iev.code == MSC_ANDROID_TIME_USEC) { - device->timestampOverrideUsec = iev.value; - continue; - } - } - if (device->timestampOverrideSec || device->timestampOverrideUsec) { - iev.time.tv_sec = device->timestampOverrideSec; - iev.time.tv_usec = device->timestampOverrideUsec; - if (iev.type == EV_SYN && iev.code == SYN_REPORT) { - device->timestampOverrideSec = 0; - device->timestampOverrideUsec = 0; - } - ALOGV("applied override time %d.%06d", - int(iev.time.tv_sec), int(iev.time.tv_usec)); - } - -#ifdef HAVE_POSIX_CLOCKS - // Use the time specified in the event instead of the current time - // so that downstream code can get more accurate estimates of - // event dispatch latency from the time the event is enqueued onto - // the evdev client buffer. - // - // The event's timestamp fortuitously uses the same monotonic clock - // time base as the rest of Android. The kernel event device driver - // (drivers/input/evdev.c) obtains timestamps using ktime_get_ts(). - // The systemTime(SYSTEM_TIME_MONOTONIC) function we use everywhere - // calls clock_gettime(CLOCK_MONOTONIC) which is implemented as a - // system call that also queries ktime_get_ts(). - event->when = nsecs_t(iev.time.tv_sec) * 1000000000LL - + nsecs_t(iev.time.tv_usec) * 1000LL; - ALOGV("event time %lld, now %lld", event->when, now); - - // Bug 7291243: Add a guard in case the kernel generates timestamps - // that appear to be far into the future because they were generated - // using the wrong clock source. - // - // This can happen because when the input device is initially opened - // it has a default clock source of CLOCK_REALTIME. Any input events - // enqueued right after the device is opened will have timestamps - // generated using CLOCK_REALTIME. We later set the clock source - // to CLOCK_MONOTONIC but it is already too late. - // - // Invalid input event timestamps can result in ANRs, crashes and - // and other issues that are hard to track down. We must not let them - // propagate through the system. - // - // Log a warning so that we notice the problem and recover gracefully. - if (event->when >= now + 10 * 1000000000LL) { - // Double-check. Time may have moved on. - nsecs_t time = systemTime(SYSTEM_TIME_MONOTONIC); - if (event->when > time) { - ALOGW("An input event from %s has a timestamp that appears to " - "have been generated using the wrong clock source " - "(expected CLOCK_MONOTONIC): " - "event time %lld, current time %lld, call time %lld. " - "Using current time instead.", - device->path.string(), event->when, time, now); - event->when = time; - } else { - ALOGV("Event time is ok but failed the fast path and required " - "an extra call to systemTime: " - "event time %lld, current time %lld, call time %lld.", - event->when, time, now); - } - } -#else - event->when = now; -#endif - event->deviceId = deviceId; - event->type = iev.type; - event->code = iev.code; - event->value = iev.value; - event += 1; - capacity -= 1; - } - if (capacity == 0) { - // The result buffer is full. Reset the pending event index - // so we will try to read the device again on the next iteration. - mPendingEventIndex -= 1; - break; - } - } - } else if (eventItem.events & EPOLLHUP) { - ALOGI("Removing device %s due to epoll hang-up event.", - device->identifier.name.string()); - deviceChanged = true; - closeDeviceLocked(device); - } else { - ALOGW("Received unexpected epoll event 0x%08x for device %s.", - eventItem.events, device->identifier.name.string()); - } - } - - // readNotify() will modify the list of devices so this must be done after - // processing all other events to ensure that we read all remaining events - // before closing the devices. - if (mPendingINotify && mPendingEventIndex >= mPendingEventCount) { - mPendingINotify = false; - readNotifyLocked(); - deviceChanged = true; - } - - // Report added or removed devices immediately. - if (deviceChanged) { - continue; - } - - // Return now if we have collected any events or if we were explicitly awoken. - if (event != buffer || awoken) { - break; - } - - // Poll for events. Mind the wake lock dance! - // We hold a wake lock at all times except during epoll_wait(). This works due to some - // subtle choreography. When a device driver has pending (unread) events, it acquires - // a kernel wake lock. However, once the last pending event has been read, the device - // driver will release the kernel wake lock. To prevent the system from going to sleep - // when this happens, the EventHub holds onto its own user wake lock while the client - // is processing events. Thus the system can only sleep if there are no events - // pending or currently being processed. - // - // The timeout is advisory only. If the device is asleep, it will not wake just to - // service the timeout. - mPendingEventIndex = 0; - - mLock.unlock(); // release lock before poll, must be before release_wake_lock - release_wake_lock(WAKE_LOCK_ID); - - int pollResult = epoll_wait(mEpollFd, mPendingEventItems, EPOLL_MAX_EVENTS, timeoutMillis); - - acquire_wake_lock(PARTIAL_WAKE_LOCK, WAKE_LOCK_ID); - mLock.lock(); // reacquire lock after poll, must be after acquire_wake_lock - - if (pollResult == 0) { - // Timed out. - mPendingEventCount = 0; - break; - } - - if (pollResult < 0) { - // An error occurred. - mPendingEventCount = 0; - - // Sleep after errors to avoid locking up the system. - // Hopefully the error is transient. - if (errno != EINTR) { - ALOGW("poll failed (errno=%d)\n", errno); - usleep(100000); - } - } else { - // Some events occurred. - mPendingEventCount = size_t(pollResult); - } - } - - // All done, return the number of events we read. - return event - buffer; -} - -void EventHub::wake() { - ALOGV("wake() called"); - - ssize_t nWrite; - do { - nWrite = write(mWakeWritePipeFd, "W", 1); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite != 1 && errno != EAGAIN) { - ALOGW("Could not write wake signal, errno=%d", errno); - } -} - -void EventHub::scanDevicesLocked() { - status_t res = scanDirLocked(DEVICE_PATH); - if(res < 0) { - ALOGE("scan dir failed for %s\n", DEVICE_PATH); - } - if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) { - createVirtualKeyboardLocked(); - } -} - -// ---------------------------------------------------------------------------- - -static bool containsNonZeroByte(const uint8_t* array, uint32_t startIndex, uint32_t endIndex) { - const uint8_t* end = array + endIndex; - array += startIndex; - while (array != end) { - if (*(array++) != 0) { - return true; - } - } - return false; -} - -static const int32_t GAMEPAD_KEYCODES[] = { - AKEYCODE_BUTTON_A, AKEYCODE_BUTTON_B, AKEYCODE_BUTTON_C, - AKEYCODE_BUTTON_X, AKEYCODE_BUTTON_Y, AKEYCODE_BUTTON_Z, - AKEYCODE_BUTTON_L1, AKEYCODE_BUTTON_R1, - AKEYCODE_BUTTON_L2, AKEYCODE_BUTTON_R2, - AKEYCODE_BUTTON_THUMBL, AKEYCODE_BUTTON_THUMBR, - AKEYCODE_BUTTON_START, AKEYCODE_BUTTON_SELECT, AKEYCODE_BUTTON_MODE, - AKEYCODE_BUTTON_1, AKEYCODE_BUTTON_2, AKEYCODE_BUTTON_3, AKEYCODE_BUTTON_4, - AKEYCODE_BUTTON_5, AKEYCODE_BUTTON_6, AKEYCODE_BUTTON_7, AKEYCODE_BUTTON_8, - AKEYCODE_BUTTON_9, AKEYCODE_BUTTON_10, AKEYCODE_BUTTON_11, AKEYCODE_BUTTON_12, - AKEYCODE_BUTTON_13, AKEYCODE_BUTTON_14, AKEYCODE_BUTTON_15, AKEYCODE_BUTTON_16, -}; - -status_t EventHub::openDeviceLocked(const char *devicePath) { - char buffer[80]; - - ALOGV("Opening device: %s", devicePath); - - int fd = open(devicePath, O_RDWR | O_CLOEXEC); - if(fd < 0) { - ALOGE("could not open %s, %s\n", devicePath, strerror(errno)); - return -1; - } - - InputDeviceIdentifier identifier; - - // Get device name. - if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get device name for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.name.setTo(buffer); - } - - // Check to see if the device is on our excluded list - for (size_t i = 0; i < mExcludedDevices.size(); i++) { - const String8& item = mExcludedDevices.itemAt(i); - if (identifier.name == item) { - ALOGI("ignoring event id %s driver %s\n", devicePath, item.string()); - close(fd); - return -1; - } - } - - // Get device driver version. - int driverVersion; - if(ioctl(fd, EVIOCGVERSION, &driverVersion)) { - ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - - // Get device identifier. - struct input_id inputId; - if(ioctl(fd, EVIOCGID, &inputId)) { - ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno)); - close(fd); - return -1; - } - identifier.bus = inputId.bustype; - identifier.product = inputId.product; - identifier.vendor = inputId.vendor; - identifier.version = inputId.version; - - // Get device physical location. - if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.location.setTo(buffer); - } - - // Get device unique id. - if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) { - //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno)); - } else { - buffer[sizeof(buffer) - 1] = '\0'; - identifier.uniqueId.setTo(buffer); - } - - // Fill in the descriptor. - setDescriptor(identifier); - - // Make file descriptor non-blocking for use with poll(). - if (fcntl(fd, F_SETFL, O_NONBLOCK)) { - ALOGE("Error %d making device file descriptor non-blocking.", errno); - close(fd); - return -1; - } - - // Allocate device. (The device object takes ownership of the fd at this point.) - int32_t deviceId = mNextDeviceId++; - Device* device = new Device(fd, deviceId, String8(devicePath), identifier); - - ALOGV("add device %d: %s\n", deviceId, devicePath); - ALOGV(" bus: %04x\n" - " vendor %04x\n" - " product %04x\n" - " version %04x\n", - identifier.bus, identifier.vendor, identifier.product, identifier.version); - ALOGV(" name: \"%s\"\n", identifier.name.string()); - ALOGV(" location: \"%s\"\n", identifier.location.string()); - ALOGV(" unique id: \"%s\"\n", identifier.uniqueId.string()); - ALOGV(" descriptor: \"%s\"\n", identifier.descriptor.string()); - ALOGV(" driver: v%d.%d.%d\n", - driverVersion >> 16, (driverVersion >> 8) & 0xff, driverVersion & 0xff); - - // Load the configuration file for the device. - loadConfigurationLocked(device); - - // Figure out the kinds of events the device reports. - ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask); - ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask); - ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask); - ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask); - ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask); - ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask); - ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask); - - // See if this is a keyboard. Ignore everything in the button range except for - // joystick and gamepad buttons which are handled like keyboards for the most part. - bool haveKeyboardKeys = containsNonZeroByte(device->keyBitmask, 0, sizeof_bit_array(BTN_MISC)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(KEY_OK), - sizeof_bit_array(KEY_MAX + 1)); - bool haveGamepadButtons = containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_MISC), - sizeof_bit_array(BTN_MOUSE)) - || containsNonZeroByte(device->keyBitmask, sizeof_bit_array(BTN_JOYSTICK), - sizeof_bit_array(BTN_DIGI)); - if (haveKeyboardKeys || haveGamepadButtons) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - - // See if this is a cursor device such as a trackball or mouse. - if (test_bit(BTN_MOUSE, device->keyBitmask) - && test_bit(REL_X, device->relBitmask) - && test_bit(REL_Y, device->relBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_CURSOR; - } - - // See if this is a touch pad. - // Is this a new modern multi-touch driver? - if (test_bit(ABS_MT_POSITION_X, device->absBitmask) - && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) { - // Some joysticks such as the PS3 controller report axes that conflict - // with the ABS_MT range. Try to confirm that the device really is - // a touch screen. - if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT; - } - // Is this an old style single-touch driver? - } else if (test_bit(BTN_TOUCH, device->keyBitmask) - && test_bit(ABS_X, device->absBitmask) - && test_bit(ABS_Y, device->absBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_TOUCH; - } - - // See if this device is a joystick. - // Assumes that joysticks always have gamepad buttons in order to distinguish them - // from other devices such as accelerometers that also have absolute axes. - if (haveGamepadButtons) { - uint32_t assumedClasses = device->classes | INPUT_DEVICE_CLASS_JOYSTICK; - for (int i = 0; i <= ABS_MAX; i++) { - if (test_bit(i, device->absBitmask) - && (getAbsAxisUsage(i, assumedClasses) & INPUT_DEVICE_CLASS_JOYSTICK)) { - device->classes = assumedClasses; - break; - } - } - } - - // Check whether this device has switches. - for (int i = 0; i <= SW_MAX; i++) { - if (test_bit(i, device->swBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_SWITCH; - break; - } - } - - // Check whether this device supports the vibrator. - if (test_bit(FF_RUMBLE, device->ffBitmask)) { - device->classes |= INPUT_DEVICE_CLASS_VIBRATOR; - } - - // Configure virtual keys. - if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) { - // Load the virtual keys for the touch screen, if any. - // We do this now so that we can make sure to load the keymap if necessary. - status_t status = loadVirtualKeyMapLocked(device); - if (!status) { - device->classes |= INPUT_DEVICE_CLASS_KEYBOARD; - } - } - - // Load the key map. - // We need to do this for joysticks too because the key layout may specify axes. - status_t keyMapStatus = NAME_NOT_FOUND; - if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) { - // Load the keymap for the device. - keyMapStatus = loadKeyMapLocked(device); - } - - // Configure the keyboard, gamepad or virtual keyboard. - if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { - // Register the keyboard as a built-in keyboard if it is eligible. - if (!keyMapStatus - && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD - && isEligibleBuiltInKeyboard(device->identifier, - device->configuration, &device->keyMap)) { - mBuiltInKeyboardId = device->id; - } - - // 'Q' key support = cheap test of whether this is an alpha-capable kbd - if (hasKeycodeLocked(device, AKEYCODE_Q)) { - device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY; - } - - // See if this device has a DPAD. - if (hasKeycodeLocked(device, AKEYCODE_DPAD_UP) && - hasKeycodeLocked(device, AKEYCODE_DPAD_DOWN) && - hasKeycodeLocked(device, AKEYCODE_DPAD_LEFT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_RIGHT) && - hasKeycodeLocked(device, AKEYCODE_DPAD_CENTER)) { - device->classes |= INPUT_DEVICE_CLASS_DPAD; - } - - // See if this device has a gamepad. - for (size_t i = 0; i < sizeof(GAMEPAD_KEYCODES)/sizeof(GAMEPAD_KEYCODES[0]); i++) { - if (hasKeycodeLocked(device, GAMEPAD_KEYCODES[i])) { - device->classes |= INPUT_DEVICE_CLASS_GAMEPAD; - break; - } - } - - // Disable kernel key repeat since we handle it ourselves - unsigned int repeatRate[] = {0,0}; - if (ioctl(fd, EVIOCSREP, repeatRate)) { - ALOGW("Unable to disable kernel key repeat for %s: %s", devicePath, strerror(errno)); - } - } - - // If the device isn't recognized as something we handle, don't monitor it. - if (device->classes == 0) { - ALOGV("Dropping device: id=%d, path='%s', name='%s'", - deviceId, devicePath, device->identifier.name.string()); - delete device; - return -1; - } - - // Determine whether the device is external or internal. - if (isExternalDeviceLocked(device)) { - device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; - } - - // Register with epoll. - struct epoll_event eventItem; - memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = EPOLLIN; - eventItem.data.u32 = deviceId; - if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { - ALOGE("Could not add device fd to epoll instance. errno=%d", errno); - delete device; - return -1; - } - - // Enable wake-lock behavior on kernels that support it. - // TODO: Only need this for devices that can really wake the system. - bool usingSuspendBlockIoctl = !ioctl(fd, EVIOCSSUSPENDBLOCK, 1); - - // Tell the kernel that we want to use the monotonic clock for reporting timestamps - // associated with input events. This is important because the input system - // uses the timestamps extensively and assumes they were recorded using the monotonic - // clock. - // - // In older kernel, before Linux 3.4, there was no way to tell the kernel which - // clock to use to input event timestamps. The standard kernel behavior was to - // record a real time timestamp, which isn't what we want. Android kernels therefore - // contained a patch to the evdev_event() function in drivers/input/evdev.c to - // replace the call to do_gettimeofday() with ktime_get_ts() to cause the monotonic - // clock to be used instead of the real time clock. - // - // As of Linux 3.4, there is a new EVIOCSCLOCKID ioctl to set the desired clock. - // Therefore, we no longer require the Android-specific kernel patch described above - // as long as we make sure to set select the monotonic clock. We do that here. - int clockId = CLOCK_MONOTONIC; - bool usingClockIoctl = !ioctl(fd, EVIOCSCLOCKID, &clockId); - - ALOGI("New device: id=%d, fd=%d, path='%s', name='%s', classes=0x%x, " - "configuration='%s', keyLayout='%s', keyCharacterMap='%s', builtinKeyboard=%s, " - "usingSuspendBlockIoctl=%s, usingClockIoctl=%s", - deviceId, fd, devicePath, device->identifier.name.string(), - device->classes, - device->configurationFile.string(), - device->keyMap.keyLayoutFile.string(), - device->keyMap.keyCharacterMapFile.string(), - toString(mBuiltInKeyboardId == deviceId), - toString(usingSuspendBlockIoctl), toString(usingClockIoctl)); - - addDeviceLocked(device); - return 0; -} - -void EventHub::createVirtualKeyboardLocked() { - InputDeviceIdentifier identifier; - identifier.name = "Virtual"; - identifier.uniqueId = ""; - setDescriptor(identifier); - - Device* device = new Device(-1, VIRTUAL_KEYBOARD_ID, String8(""), identifier); - device->classes = INPUT_DEVICE_CLASS_KEYBOARD - | INPUT_DEVICE_CLASS_ALPHAKEY - | INPUT_DEVICE_CLASS_DPAD - | INPUT_DEVICE_CLASS_VIRTUAL; - loadKeyMapLocked(device); - addDeviceLocked(device); -} - -void EventHub::addDeviceLocked(Device* device) { - mDevices.add(device->id, device); - device->next = mOpeningDevices; - mOpeningDevices = device; -} - -void EventHub::loadConfigurationLocked(Device* device) { - device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier( - device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION); - if (device->configurationFile.isEmpty()) { - ALOGD("No input device configuration file found for device '%s'.", - device->identifier.name.string()); - } else { - status_t status = PropertyMap::load(device->configurationFile, - &device->configuration); - if (status) { - ALOGE("Error loading input device configuration file for device '%s'. " - "Using default configuration.", - device->identifier.name.string()); - } - } -} - -status_t EventHub::loadVirtualKeyMapLocked(Device* device) { - // The virtual key map is supplied by the kernel as a system board property file. - String8 path; - path.append("/sys/board_properties/virtualkeys."); - path.append(device->identifier.name); - if (access(path.string(), R_OK)) { - return NAME_NOT_FOUND; - } - return VirtualKeyMap::load(path, &device->virtualKeyMap); -} - -status_t EventHub::loadKeyMapLocked(Device* device) { - return device->keyMap.load(device->identifier, device->configuration); -} - -bool EventHub::isExternalDeviceLocked(Device* device) { - if (device->configuration) { - bool value; - if (device->configuration->tryGetProperty(String8("device.internal"), value)) { - return !value; - } - } - return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; -} - -bool EventHub::hasKeycodeLocked(Device* device, int keycode) const { - if (!device->keyMap.haveKeyLayout() || !device->keyBitmask) { - return false; - } - - Vector scanCodes; - device->keyMap.keyLayoutMap->findScanCodesForKey(keycode, &scanCodes); - const size_t N = scanCodes.size(); - for (size_t i=0; i= 0 && sc <= KEY_MAX && test_bit(sc, device->keyBitmask)) { - return true; - } - } - - return false; -} - -status_t EventHub::closeDeviceByPathLocked(const char *devicePath) { - Device* device = getDeviceByPathLocked(devicePath); - if (device) { - closeDeviceLocked(device); - return 0; - } - ALOGV("Remove device: %s not found, device may already have been removed.", devicePath); - return -1; -} - -void EventHub::closeAllDevicesLocked() { - while (mDevices.size() > 0) { - closeDeviceLocked(mDevices.valueAt(mDevices.size() - 1)); - } -} - -void EventHub::closeDeviceLocked(Device* device) { - ALOGI("Removed device: path=%s name=%s id=%d fd=%d classes=0x%x\n", - device->path.string(), device->identifier.name.string(), device->id, - device->fd, device->classes); - - if (device->id == mBuiltInKeyboardId) { - ALOGW("built-in keyboard device %s (id=%d) is closing! the apps will not like this", - device->path.string(), mBuiltInKeyboardId); - mBuiltInKeyboardId = NO_BUILT_IN_KEYBOARD; - } - - if (!device->isVirtual()) { - if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) { - ALOGW("Could not remove device fd from epoll instance. errno=%d", errno); - } - } - - mDevices.removeItem(device->id); - device->close(); - - // Unlink for opening devices list if it is present. - Device* pred = NULL; - bool found = false; - for (Device* entry = mOpeningDevices; entry != NULL; ) { - if (entry == device) { - found = true; - break; - } - pred = entry; - entry = entry->next; - } - if (found) { - // Unlink the device from the opening devices list then delete it. - // We don't need to tell the client that the device was closed because - // it does not even know it was opened in the first place. - ALOGI("Device %s was immediately closed after opening.", device->path.string()); - if (pred) { - pred->next = device->next; - } else { - mOpeningDevices = device->next; - } - delete device; - } else { - // Link into closing devices list. - // The device will be deleted later after we have informed the client. - device->next = mClosingDevices; - mClosingDevices = device; - } -} - -status_t EventHub::readNotifyLocked() { - int res; - char devname[PATH_MAX]; - char *filename; - char event_buf[512]; - int event_size; - int event_pos = 0; - struct inotify_event *event; - - ALOGV("EventHub::readNotify nfd: %d\n", mINotifyFd); - res = read(mINotifyFd, event_buf, sizeof(event_buf)); - if(res < (int)sizeof(*event)) { - if(errno == EINTR) - return 0; - ALOGW("could not get event, %s\n", strerror(errno)); - return -1; - } - //printf("got %d bytes of event information\n", res); - - strcpy(devname, DEVICE_PATH); - filename = devname + strlen(devname); - *filename++ = '/'; - - while(res >= (int)sizeof(*event)) { - event = (struct inotify_event *)(event_buf + event_pos); - //printf("%d: %08x \"%s\"\n", event->wd, event->mask, event->len ? event->name : ""); - if(event->len) { - strcpy(filename, event->name); - if(event->mask & IN_CREATE) { - openDeviceLocked(devname); - } else { - ALOGI("Removing device '%s' due to inotify event\n", devname); - closeDeviceByPathLocked(devname); - } - } - event_size = sizeof(*event) + event->len; - res -= event_size; - event_pos += event_size; - } - return 0; -} - -status_t EventHub::scanDirLocked(const char *dirname) -{ - char devname[PATH_MAX]; - char *filename; - DIR *dir; - struct dirent *de; - dir = opendir(dirname); - if(dir == NULL) - return -1; - strcpy(devname, dirname); - filename = devname + strlen(devname); - *filename++ = '/'; - while((de = readdir(dir))) { - if(de->d_name[0] == '.' && - (de->d_name[1] == '\0' || - (de->d_name[1] == '.' && de->d_name[2] == '\0'))) - continue; - strcpy(filename, de->d_name); - openDeviceLocked(devname); - } - closedir(dir); - return 0; -} - -void EventHub::requestReopenDevices() { - ALOGV("requestReopenDevices() called"); - - AutoMutex _l(mLock); - mNeedToReopenDevices = true; -} - -void EventHub::dump(String8& dump) { - dump.append("Event Hub State:\n"); - - { // acquire lock - AutoMutex _l(mLock); - - dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId); - - dump.append(INDENT "Devices:\n"); - - for (size_t i = 0; i < mDevices.size(); i++) { - const Device* device = mDevices.valueAt(i); - if (mBuiltInKeyboardId == device->id) { - dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n", - device->id, device->identifier.name.string()); - } else { - dump.appendFormat(INDENT2 "%d: %s\n", device->id, - device->identifier.name.string()); - } - dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes); - dump.appendFormat(INDENT3 "Path: %s\n", device->path.string()); - dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string()); - dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string()); - dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string()); - dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, " - "product=0x%04x, version=0x%04x\n", - device->identifier.bus, device->identifier.vendor, - device->identifier.product, device->identifier.version); - dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n", - device->keyMap.keyLayoutFile.string()); - dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n", - device->keyMap.keyCharacterMapFile.string()); - dump.appendFormat(INDENT3 "ConfigurationFile: %s\n", - device->configurationFile.string()); - dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n", - toString(device->overlayKeyMap != NULL)); - } - } // release lock -} - -void EventHub::monitor() { - // Acquire and release the lock to ensure that the event hub has not deadlocked. - mLock.lock(); - mLock.unlock(); -} - - -}; // namespace android diff --git a/widget/gonk/libui/EventHub.h b/widget/gonk/libui/EventHub.h deleted file mode 100644 index e4e658b21..000000000 --- a/widget/gonk/libui/EventHub.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -// -#ifndef _RUNTIME_EVENT_HUB_H -#define _RUNTIME_EVENT_HUB_H - -#include "Input.h" -#include "InputDevice.h" -#include "Keyboard.h" -#include "KeyLayoutMap.h" -#include "KeyCharacterMap.h" -#include "VirtualKeyMap.h" -#include -#include -#include "cutils_log.h" -#include -#include -#include -#include -#include -#include - -#include "linux_input.h" -#include - -/* Convenience constants. */ - -#define BTN_FIRST 0x100 // first button code -#define BTN_LAST 0x15f // last button code - -/* - * These constants are used privately in Android to pass raw timestamps - * through evdev from uinput device drivers because there is currently no - * other way to transfer this information. The evdev driver automatically - * timestamps all input events with the time they were posted and clobbers - * whatever information was passed in. - * - * For the purposes of this hack, the timestamp is specified in the - * CLOCK_MONOTONIC timebase and is split into two EV_MSC events specifying - * seconds and microseconds. - */ -#define MSC_ANDROID_TIME_SEC 0x6 -#define MSC_ANDROID_TIME_USEC 0x7 - -namespace android { - -enum { - // Device id of a special "virtual" keyboard that is always present. - VIRTUAL_KEYBOARD_ID = -1, - // Device id of the "built-in" keyboard if there is one. - BUILT_IN_KEYBOARD_ID = 0, -}; - -/* - * A raw event as retrieved from the EventHub. - */ -struct RawEvent { - nsecs_t when; - int32_t deviceId; - int32_t type; - int32_t code; - int32_t value; -}; - -/* Describes an absolute axis. */ -struct RawAbsoluteAxisInfo { - bool valid; // true if the information is valid, false otherwise - - int32_t minValue; // minimum value - int32_t maxValue; // maximum value - int32_t flat; // center flat position, eg. flat == 8 means center is between -8 and 8 - int32_t fuzz; // error tolerance, eg. fuzz == 4 means value is +/- 4 due to noise - int32_t resolution; // resolution in units per mm or radians per mm - - inline void clear() { - valid = false; - minValue = 0; - maxValue = 0; - flat = 0; - fuzz = 0; - resolution = 0; - } -}; - -/* - * Input device classes. - */ -enum { - /* The input device is a keyboard or has buttons. */ - INPUT_DEVICE_CLASS_KEYBOARD = 0x00000001, - - /* The input device is an alpha-numeric keyboard (not just a dial pad). */ - INPUT_DEVICE_CLASS_ALPHAKEY = 0x00000002, - - /* The input device is a touchscreen or a touchpad (either single-touch or multi-touch). */ - INPUT_DEVICE_CLASS_TOUCH = 0x00000004, - - /* The input device is a cursor device such as a trackball or mouse. */ - INPUT_DEVICE_CLASS_CURSOR = 0x00000008, - - /* The input device is a multi-touch touchscreen. */ - INPUT_DEVICE_CLASS_TOUCH_MT = 0x00000010, - - /* The input device is a directional pad (implies keyboard, has DPAD keys). */ - INPUT_DEVICE_CLASS_DPAD = 0x00000020, - - /* The input device is a gamepad (implies keyboard, has BUTTON keys). */ - INPUT_DEVICE_CLASS_GAMEPAD = 0x00000040, - - /* The input device has switches. */ - INPUT_DEVICE_CLASS_SWITCH = 0x00000080, - - /* The input device is a joystick (implies gamepad, has joystick absolute axes). */ - INPUT_DEVICE_CLASS_JOYSTICK = 0x00000100, - - /* The input device has a vibrator (supports FF_RUMBLE). */ - INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, - - /* The input device is virtual (not a real device, not part of UI configuration). */ - INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, - - /* The input device is external (not built-in). */ - INPUT_DEVICE_CLASS_EXTERNAL = 0x80000000, -}; - -/* - * Gets the class that owns an axis, in cases where multiple classes might claim - * the same axis for different purposes. - */ -extern uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses); - -/* - * Grand Central Station for events. - * - * The event hub aggregates input events received across all known input - * devices on the system, including devices that may be emulated by the simulator - * environment. In addition, the event hub generates fake input events to indicate - * when devices are added or removed. - * - * The event hub provides a stream of input events (via the getEvent function). - * It also supports querying the current actual state of input devices such as identifying - * which keys are currently down. Finally, the event hub keeps track of the capabilities of - * individual input devices, such as their class and the set of key codes that they support. - */ -class EventHubInterface : public virtual RefBase { -protected: - EventHubInterface() { } - virtual ~EventHubInterface() { } - -public: - // Synthetic raw event type codes produced when devices are added or removed. - enum { - // Sent when a device is added. - DEVICE_ADDED = 0x10000000, - // Sent when a device is removed. - DEVICE_REMOVED = 0x20000000, - // Sent when all added/removed devices from the most recent scan have been reported. - // This event is always sent at least once. - FINISHED_DEVICE_SCAN = 0x30000000, - - FIRST_SYNTHETIC_EVENT = DEVICE_ADDED, - }; - - virtual uint32_t getDeviceClasses(int32_t deviceId) const = 0; - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const = 0; - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const = 0; - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const = 0; - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const = 0; - - virtual bool hasInputProperty(int32_t deviceId, int property) const = 0; - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const = 0; - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const = 0; - - // Sets devices that are excluded from opening. - // This can be used to ignore input devices for sensors. - virtual void setExcludedDevices(const Vector& devices) = 0; - - /* - * Wait for events to become available and returns them. - * After returning, the EventHub holds onto a wake lock until the next call to getEvent. - * This ensures that the device will not go to sleep while the event is being processed. - * If the device needs to remain awake longer than that, then the caller is responsible - * for taking care of it (say, by poking the power manager user activity timer). - * - * The timeout is advisory only. If the device is asleep, it will not wake just to - * service the timeout. - * - * Returns the number of events obtained, or 0 if the timeout expired. - */ - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) = 0; - - /* - * Query current input state. - */ - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const = 0; - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const = 0; - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const = 0; - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, - int32_t* outValue) const = 0; - - /* - * Examine key input devices for specific framework keycode support - */ - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes, - uint8_t* outFlags) const = 0; - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const = 0; - virtual bool hasLed(int32_t deviceId, int32_t led) const = 0; - virtual void setLedState(int32_t deviceId, int32_t led, bool on) = 0; - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector& outVirtualKeys) const = 0; - - virtual sp getKeyCharacterMap(int32_t deviceId) const = 0; - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map) = 0; - - /* Control the vibrator. */ - virtual void vibrate(int32_t deviceId, nsecs_t duration) = 0; - virtual void cancelVibrate(int32_t deviceId) = 0; - - /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */ - virtual void requestReopenDevices() = 0; - - /* Wakes up getEvents() if it is blocked on a read. */ - virtual void wake() = 0; - - /* Dump EventHub state to a string. */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; -}; - -class EventHub : public EventHubInterface -{ -public: - EventHub(); - - virtual uint32_t getDeviceClasses(int32_t deviceId) const; - - virtual InputDeviceIdentifier getDeviceIdentifier(int32_t deviceId) const; - - virtual void getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const; - - virtual status_t getAbsoluteAxisInfo(int32_t deviceId, int axis, - RawAbsoluteAxisInfo* outAxisInfo) const; - - virtual bool hasRelativeAxis(int32_t deviceId, int axis) const; - - virtual bool hasInputProperty(int32_t deviceId, int property) const; - - virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, - int32_t* outKeycode, uint32_t* outFlags) const; - - virtual status_t mapAxis(int32_t deviceId, int32_t scanCode, - AxisInfo* outAxisInfo) const; - - virtual void setExcludedDevices(const Vector& devices); - - virtual int32_t getScanCodeState(int32_t deviceId, int32_t scanCode) const; - virtual int32_t getKeyCodeState(int32_t deviceId, int32_t keyCode) const; - virtual int32_t getSwitchState(int32_t deviceId, int32_t sw) const; - virtual status_t getAbsoluteAxisValue(int32_t deviceId, int32_t axis, int32_t* outValue) const; - - virtual bool markSupportedKeyCodes(int32_t deviceId, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) const; - - virtual size_t getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize); - - virtual bool hasScanCode(int32_t deviceId, int32_t scanCode) const; - virtual bool hasLed(int32_t deviceId, int32_t led) const; - virtual void setLedState(int32_t deviceId, int32_t led, bool on); - - virtual void getVirtualKeyDefinitions(int32_t deviceId, - Vector& outVirtualKeys) const; - - virtual sp getKeyCharacterMap(int32_t deviceId) const; - virtual bool setKeyboardLayoutOverlay(int32_t deviceId, const sp& map); - - virtual void vibrate(int32_t deviceId, nsecs_t duration); - virtual void cancelVibrate(int32_t deviceId); - - virtual void requestReopenDevices(); - - virtual void wake(); - - virtual void dump(String8& dump); - virtual void monitor(); - -protected: - virtual ~EventHub(); - -private: - struct Device { - Device* next; - - int fd; // may be -1 if device is virtual - const int32_t id; - const String8 path; - const InputDeviceIdentifier identifier; - - uint32_t classes; - - uint8_t keyBitmask[(KEY_MAX + 1) / 8]; - uint8_t absBitmask[(ABS_MAX + 1) / 8]; - uint8_t relBitmask[(REL_MAX + 1) / 8]; - uint8_t swBitmask[(SW_MAX + 1) / 8]; - uint8_t ledBitmask[(LED_MAX + 1) / 8]; - uint8_t ffBitmask[(FF_MAX + 1) / 8]; - uint8_t propBitmask[(INPUT_PROP_MAX + 1) / 8]; - - String8 configurationFile; - PropertyMap* configuration; - VirtualKeyMap* virtualKeyMap; - KeyMap keyMap; - - sp overlayKeyMap; - sp combinedKeyMap; - - bool ffEffectPlaying; - int16_t ffEffectId; // initially -1 - - int32_t timestampOverrideSec; - int32_t timestampOverrideUsec; - - Device(int fd, int32_t id, const String8& path, const InputDeviceIdentifier& identifier); - ~Device(); - - void close(); - - inline bool isVirtual() const { return fd < 0; } - - const sp& getKeyCharacterMap() const { - if (combinedKeyMap != NULL) { - return combinedKeyMap; - } - return keyMap.keyCharacterMap; - } - }; - - status_t openDeviceLocked(const char *devicePath); - void createVirtualKeyboardLocked(); - void addDeviceLocked(Device* device); - - status_t closeDeviceByPathLocked(const char *devicePath); - void closeDeviceLocked(Device* device); - void closeAllDevicesLocked(); - - status_t scanDirLocked(const char *dirname); - void scanDevicesLocked(); - status_t readNotifyLocked(); - - Device* getDeviceLocked(int32_t deviceId) const; - Device* getDeviceByPathLocked(const char* devicePath) const; - - bool hasKeycodeLocked(Device* device, int keycode) const; - - void loadConfigurationLocked(Device* device); - status_t loadVirtualKeyMapLocked(Device* device); - status_t loadKeyMapLocked(Device* device); - - bool isExternalDeviceLocked(Device* device); - - // Protect all internal state. - mutable Mutex mLock; - - // The actual id of the built-in keyboard, or NO_BUILT_IN_KEYBOARD if none. - // EventHub remaps the built-in keyboard to id 0 externally as required by the API. - enum { - // Must not conflict with any other assigned device ids, including - // the virtual keyboard id (-1). - NO_BUILT_IN_KEYBOARD = -2, - }; - int32_t mBuiltInKeyboardId; - - int32_t mNextDeviceId; - - KeyedVector mDevices; - - Device *mOpeningDevices; - Device *mClosingDevices; - - bool mNeedToSendFinishedDeviceScan; - bool mNeedToReopenDevices; - bool mNeedToScanDevices; - Vector mExcludedDevices; - - int mEpollFd; - int mINotifyFd; - int mWakeReadPipeFd; - int mWakeWritePipeFd; - - // Ids used for epoll notifications not associated with devices. - static const uint32_t EPOLL_ID_INOTIFY = 0x80000001; - static const uint32_t EPOLL_ID_WAKE = 0x80000002; - - // Epoll FD list size hint. - static const int EPOLL_SIZE_HINT = 8; - - // Maximum number of signalled FDs to handle at a time. - static const int EPOLL_MAX_EVENTS = 16; - - // The array of pending epoll events and the index of the next event to be handled. - struct epoll_event mPendingEventItems[EPOLL_MAX_EVENTS]; - size_t mPendingEventCount; - size_t mPendingEventIndex; - bool mPendingINotify; -}; - -}; // namespace android - -#endif // _RUNTIME_EVENT_HUB_H diff --git a/widget/gonk/libui/Input.cpp b/widget/gonk/libui/Input.cpp deleted file mode 100644 index 2208191e6..000000000 --- a/widget/gonk/libui/Input.cpp +++ /dev/null @@ -1,635 +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. - */ - -#define LOG_TAG "Input" -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -#include -#include - -#include "Input.h" - -#ifdef HAVE_ANDROID_OS -#include - -#include "SkPoint.h" -#include "SkMatrix.h" -#include "SkScalar.h" -#endif - -namespace android { - -// --- InputEvent --- - -void InputEvent::initialize(int32_t deviceId, int32_t source) { - mDeviceId = deviceId; - mSource = source; -} - -void InputEvent::initialize(const InputEvent& from) { - mDeviceId = from.mDeviceId; - mSource = from.mSource; -} - -// --- KeyEvent --- - -bool KeyEvent::hasDefaultAction(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_HOME: - case AKEYCODE_BACK: - case AKEYCODE_CALL: - case AKEYCODE_ENDCALL: - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_VOLUME_MUTE: - case AKEYCODE_POWER: - case AKEYCODE_CAMERA: - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MENU: - case AKEYCODE_NOTIFICATION: - case AKEYCODE_FOCUS: - case AKEYCODE_SEARCH: - case AKEYCODE_MEDIA_PLAY: - case AKEYCODE_MEDIA_PAUSE: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_RECORD: - case AKEYCODE_MEDIA_FAST_FORWARD: - case AKEYCODE_MUTE: - case AKEYCODE_BRIGHTNESS_DOWN: - case AKEYCODE_BRIGHTNESS_UP: - return true; - } - - return false; -} - -bool KeyEvent::hasDefaultAction() const { - return hasDefaultAction(getKeyCode()); -} - -bool KeyEvent::isSystemKey(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_MENU: - case AKEYCODE_SOFT_RIGHT: - case AKEYCODE_HOME: - case AKEYCODE_BACK: - case AKEYCODE_CALL: - case AKEYCODE_ENDCALL: - case AKEYCODE_VOLUME_UP: - case AKEYCODE_VOLUME_DOWN: - case AKEYCODE_VOLUME_MUTE: - case AKEYCODE_MUTE: - case AKEYCODE_POWER: - case AKEYCODE_HEADSETHOOK: - case AKEYCODE_MEDIA_PLAY: - case AKEYCODE_MEDIA_PAUSE: - case AKEYCODE_MEDIA_PLAY_PAUSE: - case AKEYCODE_MEDIA_STOP: - case AKEYCODE_MEDIA_NEXT: - case AKEYCODE_MEDIA_PREVIOUS: - case AKEYCODE_MEDIA_REWIND: - case AKEYCODE_MEDIA_RECORD: - case AKEYCODE_MEDIA_FAST_FORWARD: - case AKEYCODE_CAMERA: - case AKEYCODE_FOCUS: - case AKEYCODE_SEARCH: - case AKEYCODE_BRIGHTNESS_DOWN: - case AKEYCODE_BRIGHTNESS_UP: - return true; - } - - return false; -} - -bool KeyEvent::isSystemKey() const { - return isSystemKey(getKeyCode()); -} - -void KeyEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime) { - InputEvent::initialize(deviceId, source); - mAction = action; - mFlags = flags; - mKeyCode = keyCode; - mScanCode = scanCode; - mMetaState = metaState; - mRepeatCount = repeatCount; - mDownTime = downTime; - mEventTime = eventTime; -} - -void KeyEvent::initialize(const KeyEvent& from) { - InputEvent::initialize(from); - mAction = from.mAction; - mFlags = from.mFlags; - mKeyCode = from.mKeyCode; - mScanCode = from.mScanCode; - mMetaState = from.mMetaState; - mRepeatCount = from.mRepeatCount; - mDownTime = from.mDownTime; - mEventTime = from.mEventTime; -} - - -// --- PointerCoords --- - -float PointerCoords::getAxisValue(int32_t axis) const { - if (axis < 0 || axis > 63) { - return 0; - } - - uint64_t axisBit = 1LL << axis; - if (!(bits & axisBit)) { - return 0; - } - uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); - return values[index]; -} - -status_t PointerCoords::setAxisValue(int32_t axis, float value) { - if (axis < 0 || axis > 63) { - return NAME_NOT_FOUND; - } - - uint64_t axisBit = 1LL << axis; - uint32_t index = __builtin_popcountll(bits & (axisBit - 1LL)); - if (!(bits & axisBit)) { - if (value == 0) { - return OK; // axes with value 0 do not need to be stored - } - uint32_t count = __builtin_popcountll(bits); - if (count >= MAX_AXES) { - tooManyAxes(axis); - return NO_MEMORY; - } - bits |= axisBit; - for (uint32_t i = count; i > index; i--) { - values[i] = values[i - 1]; - } - } - values[index] = value; - return OK; -} - -static inline void scaleAxisValue(PointerCoords& c, int axis, float scaleFactor) { - float value = c.getAxisValue(axis); - if (value != 0) { - c.setAxisValue(axis, value * scaleFactor); - } -} - -void PointerCoords::scale(float scaleFactor) { - // No need to scale pressure or size since they are normalized. - // No need to scale orientation since it is meaningless to do so. - scaleAxisValue(*this, AMOTION_EVENT_AXIS_X, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_Y, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MAJOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOUCH_MINOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MAJOR, scaleFactor); - scaleAxisValue(*this, AMOTION_EVENT_AXIS_TOOL_MINOR, scaleFactor); -} - -#ifdef HAVE_ANDROID_OS -status_t PointerCoords::readFromParcel(Parcel* parcel) { - bits = parcel->readInt64(); - - uint32_t count = __builtin_popcountll(bits); - if (count > MAX_AXES) { - return BAD_VALUE; - } - - for (uint32_t i = 0; i < count; i++) { - values[i] = parcel->readFloat(); - } - return OK; -} - -status_t PointerCoords::writeToParcel(Parcel* parcel) const { - parcel->writeInt64(bits); - - uint32_t count = __builtin_popcountll(bits); - for (uint32_t i = 0; i < count; i++) { - parcel->writeFloat(values[i]); - } - return OK; -} -#endif - -void PointerCoords::tooManyAxes(int axis) { - ALOGW("Could not set value for axis %d because the PointerCoords structure is full and " - "cannot contain more than %d axis values.", axis, int(MAX_AXES)); -} - -bool PointerCoords::operator==(const PointerCoords& other) const { - if (bits != other.bits) { - return false; - } - uint32_t count = __builtin_popcountll(bits); - for (uint32_t i = 0; i < count; i++) { - if (values[i] != other.values[i]) { - return false; - } - } - return true; -} - -void PointerCoords::copyFrom(const PointerCoords& other) { - bits = other.bits; - uint32_t count = __builtin_popcountll(bits); - for (uint32_t i = 0; i < count; i++) { - values[i] = other.values[i]; - } -} - - -// --- PointerProperties --- - -bool PointerProperties::operator==(const PointerProperties& other) const { - return id == other.id - && toolType == other.toolType; -} - -void PointerProperties::copyFrom(const PointerProperties& other) { - id = other.id; - toolType = other.toolType; -} - - -// --- MotionEvent --- - -void MotionEvent::initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { - InputEvent::initialize(deviceId, source); - mAction = action; - mFlags = flags; - mEdgeFlags = edgeFlags; - mMetaState = metaState; - mButtonState = buttonState; - mXOffset = xOffset; - mYOffset = yOffset; - mXPrecision = xPrecision; - mYPrecision = yPrecision; - mDownTime = downTime; - mPointerProperties.clear(); - mPointerProperties.appendArray(pointerProperties, pointerCount); - mSampleEventTimes.clear(); - mSamplePointerCoords.clear(); - addSample(eventTime, pointerCoords); -} - -void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) { - InputEvent::initialize(other->mDeviceId, other->mSource); - mAction = other->mAction; - mFlags = other->mFlags; - mEdgeFlags = other->mEdgeFlags; - mMetaState = other->mMetaState; - mButtonState = other->mButtonState; - mXOffset = other->mXOffset; - mYOffset = other->mYOffset; - mXPrecision = other->mXPrecision; - mYPrecision = other->mYPrecision; - mDownTime = other->mDownTime; - mPointerProperties = other->mPointerProperties; - - if (keepHistory) { - mSampleEventTimes = other->mSampleEventTimes; - mSamplePointerCoords = other->mSamplePointerCoords; - } else { - mSampleEventTimes.clear(); - mSampleEventTimes.push(other->getEventTime()); - mSamplePointerCoords.clear(); - size_t pointerCount = other->getPointerCount(); - size_t historySize = other->getHistorySize(); - mSamplePointerCoords.appendArray(other->mSamplePointerCoords.array() - + (historySize * pointerCount), pointerCount); - } -} - -void MotionEvent::addSample( - int64_t eventTime, - const PointerCoords* pointerCoords) { - mSampleEventTimes.push(eventTime); - mSamplePointerCoords.appendArray(pointerCoords, getPointerCount()); -} - -const PointerCoords* MotionEvent::getRawPointerCoords(size_t pointerIndex) const { - return &mSamplePointerCoords[getHistorySize() * getPointerCount() + pointerIndex]; -} - -float MotionEvent::getRawAxisValue(int32_t axis, size_t pointerIndex) const { - return getRawPointerCoords(pointerIndex)->getAxisValue(axis); -} - -float MotionEvent::getAxisValue(int32_t axis, size_t pointerIndex) const { - float value = getRawPointerCoords(pointerIndex)->getAxisValue(axis); - switch (axis) { - case AMOTION_EVENT_AXIS_X: - return value + mXOffset; - case AMOTION_EVENT_AXIS_Y: - return value + mYOffset; - } - return value; -} - -const PointerCoords* MotionEvent::getHistoricalRawPointerCoords( - size_t pointerIndex, size_t historicalIndex) const { - return &mSamplePointerCoords[historicalIndex * getPointerCount() + pointerIndex]; -} - -float MotionEvent::getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { - return getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); -} - -float MotionEvent::getHistoricalAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const { - float value = getHistoricalRawPointerCoords(pointerIndex, historicalIndex)->getAxisValue(axis); - switch (axis) { - case AMOTION_EVENT_AXIS_X: - return value + mXOffset; - case AMOTION_EVENT_AXIS_Y: - return value + mYOffset; - } - return value; -} - -ssize_t MotionEvent::findPointerIndex(int32_t pointerId) const { - size_t pointerCount = mPointerProperties.size(); - for (size_t i = 0; i < pointerCount; i++) { - if (mPointerProperties.itemAt(i).id == pointerId) { - return i; - } - } - return -1; -} - -void MotionEvent::offsetLocation(float xOffset, float yOffset) { - mXOffset += xOffset; - mYOffset += yOffset; -} - -void MotionEvent::scale(float scaleFactor) { - mXOffset *= scaleFactor; - mYOffset *= scaleFactor; - mXPrecision *= scaleFactor; - mYPrecision *= scaleFactor; - - size_t numSamples = mSamplePointerCoords.size(); - for (size_t i = 0; i < numSamples; i++) { - mSamplePointerCoords.editItemAt(i).scale(scaleFactor); - } -} - -#ifdef HAVE_ANDROID_OS -static inline float transformAngle(const SkMatrix* matrix, float angleRadians) { - // Construct and transform a vector oriented at the specified clockwise angle from vertical. - // Coordinate system: down is increasing Y, right is increasing X. - SkPoint vector; - vector.fX = SkFloatToScalar(sinf(angleRadians)); - vector.fY = SkFloatToScalar(-cosf(angleRadians)); - matrix->mapVectors(& vector, 1); - - // Derive the transformed vector's clockwise angle from vertical. - float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY)); - if (result < - M_PI_2) { - result += M_PI; - } else if (result > M_PI_2) { - result -= M_PI; - } - return result; -} - -void MotionEvent::transform(const SkMatrix* matrix) { - float oldXOffset = mXOffset; - float oldYOffset = mYOffset; - - // The tricky part of this implementation is to preserve the value of - // rawX and rawY. So we apply the transformation to the first point - // then derive an appropriate new X/Y offset that will preserve rawX and rawY. - SkPoint point; - float rawX = getRawX(0); - float rawY = getRawY(0); - matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset), - & point); - float newX = SkScalarToFloat(point.fX); - float newY = SkScalarToFloat(point.fY); - float newXOffset = newX - rawX; - float newYOffset = newY - rawY; - - mXOffset = newXOffset; - mYOffset = newYOffset; - - // Apply the transformation to all samples. - size_t numSamples = mSamplePointerCoords.size(); - for (size_t i = 0; i < numSamples; i++) { - PointerCoords& c = mSamplePointerCoords.editItemAt(i); - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset; - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset; - matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point); - c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset); - c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset); - - float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation)); - } -} - -status_t MotionEvent::readFromParcel(Parcel* parcel) { - size_t pointerCount = parcel->readInt32(); - size_t sampleCount = parcel->readInt32(); - if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) { - return BAD_VALUE; - } - - mDeviceId = parcel->readInt32(); - mSource = parcel->readInt32(); - mAction = parcel->readInt32(); - mFlags = parcel->readInt32(); - mEdgeFlags = parcel->readInt32(); - mMetaState = parcel->readInt32(); - mButtonState = parcel->readInt32(); - mXOffset = parcel->readFloat(); - mYOffset = parcel->readFloat(); - mXPrecision = parcel->readFloat(); - mYPrecision = parcel->readFloat(); - mDownTime = parcel->readInt64(); - - mPointerProperties.clear(); - mPointerProperties.setCapacity(pointerCount); - mSampleEventTimes.clear(); - mSampleEventTimes.setCapacity(sampleCount); - mSamplePointerCoords.clear(); - mSamplePointerCoords.setCapacity(sampleCount * pointerCount); - - for (size_t i = 0; i < pointerCount; i++) { - mPointerProperties.push(); - PointerProperties& properties = mPointerProperties.editTop(); - properties.id = parcel->readInt32(); - properties.toolType = parcel->readInt32(); - } - - while (sampleCount-- > 0) { - mSampleEventTimes.push(parcel->readInt64()); - for (size_t i = 0; i < pointerCount; i++) { - mSamplePointerCoords.push(); - status_t status = mSamplePointerCoords.editTop().readFromParcel(parcel); - if (status) { - return status; - } - } - } - return OK; -} - -status_t MotionEvent::writeToParcel(Parcel* parcel) const { - size_t pointerCount = mPointerProperties.size(); - size_t sampleCount = mSampleEventTimes.size(); - - parcel->writeInt32(pointerCount); - parcel->writeInt32(sampleCount); - - parcel->writeInt32(mDeviceId); - parcel->writeInt32(mSource); - parcel->writeInt32(mAction); - parcel->writeInt32(mFlags); - parcel->writeInt32(mEdgeFlags); - parcel->writeInt32(mMetaState); - parcel->writeInt32(mButtonState); - parcel->writeFloat(mXOffset); - parcel->writeFloat(mYOffset); - parcel->writeFloat(mXPrecision); - parcel->writeFloat(mYPrecision); - parcel->writeInt64(mDownTime); - - for (size_t i = 0; i < pointerCount; i++) { - const PointerProperties& properties = mPointerProperties.itemAt(i); - parcel->writeInt32(properties.id); - parcel->writeInt32(properties.toolType); - } - - const PointerCoords* pc = mSamplePointerCoords.array(); - for (size_t h = 0; h < sampleCount; h++) { - parcel->writeInt64(mSampleEventTimes.itemAt(h)); - for (size_t i = 0; i < pointerCount; i++) { - status_t status = (pc++)->writeToParcel(parcel); - if (status) { - return status; - } - } - } - return OK; -} -#endif - -bool MotionEvent::isTouchEvent(int32_t source, int32_t action) { - if (source & AINPUT_SOURCE_CLASS_POINTER) { - // Specifically excludes HOVER_MOVE and SCROLL. - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_OUTSIDE: - return true; - } - } - return false; -} - - -// --- PooledInputEventFactory --- - -PooledInputEventFactory::PooledInputEventFactory(size_t maxPoolSize) : - mMaxPoolSize(maxPoolSize) { -} - -PooledInputEventFactory::~PooledInputEventFactory() { - for (size_t i = 0; i < mKeyEventPool.size(); i++) { - delete mKeyEventPool.itemAt(i); - } - for (size_t i = 0; i < mMotionEventPool.size(); i++) { - delete mMotionEventPool.itemAt(i); - } -} - -KeyEvent* PooledInputEventFactory::createKeyEvent() { - if (!mKeyEventPool.isEmpty()) { - KeyEvent* event = mKeyEventPool.top(); - mKeyEventPool.pop(); - return event; - } - return new KeyEvent(); -} - -MotionEvent* PooledInputEventFactory::createMotionEvent() { - if (!mMotionEventPool.isEmpty()) { - MotionEvent* event = mMotionEventPool.top(); - mMotionEventPool.pop(); - return event; - } - return new MotionEvent(); -} - -void PooledInputEventFactory::recycle(InputEvent* event) { - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: - if (mKeyEventPool.size() < mMaxPoolSize) { - mKeyEventPool.push(static_cast(event)); - return; - } - break; - case AINPUT_EVENT_TYPE_MOTION: - if (mMotionEventPool.size() < mMaxPoolSize) { - mMotionEventPool.push(static_cast(event)); - return; - } - break; - } - delete event; -} - -} // namespace android diff --git a/widget/gonk/libui/Input.h b/widget/gonk/libui/Input.h deleted file mode 100644 index 3d958bfab..000000000 --- a/widget/gonk/libui/Input.h +++ /dev/null @@ -1,622 +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. - */ - -#ifndef _ANDROIDFW_INPUT_H -#define _ANDROIDFW_INPUT_H - -/** - * Native input event structures. - */ - -#include "android_input.h" -#include -#include -#include -#include -#include - -#ifdef HAVE_ANDROID_OS -class SkMatrix; -#endif - -/* - * Additional private constants not defined in ndk/ui/input.h. - */ -enum { - /* Signifies that the key is being predispatched */ - AKEY_EVENT_FLAG_PREDISPATCH = 0x20000000, - - /* Private control to determine when an app is tracking a key sequence. */ - AKEY_EVENT_FLAG_START_TRACKING = 0x40000000, - - /* Key event is inconsistent with previously sent key events. */ - AKEY_EVENT_FLAG_TAINTED = 0x80000000, -}; - -enum { - /* Motion event is inconsistent with previously sent motion events. */ - AMOTION_EVENT_FLAG_TAINTED = 0x80000000, -}; - -enum { - /* Used when a motion event is not associated with any display. - * Typically used for non-pointer events. */ - ADISPLAY_ID_NONE = -1, - - /* The default display id. */ - ADISPLAY_ID_DEFAULT = 0, -}; - -enum { - /* - * Indicates that an input device has switches. - * This input source flag is hidden from the API because switches are only used by the system - * and applications have no way to interact with them. - */ - AINPUT_SOURCE_SWITCH = 0x80000000, -}; - -/* - * SystemUiVisibility constants from View. - */ -enum { - ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0, - ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001, -}; - -/* - * Maximum number of pointers supported per motion event. - * Smallest number of pointers is 1. - * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers - * will occasionally emit 11. There is not much harm making this constant bigger.) - */ -#define MAX_POINTERS 16 - -/* - * Maximum pointer id value supported in a motion event. - * Smallest pointer id is 0. - * (This is limited by our use of BitSet32 to track pointer assignments.) - */ -#define MAX_POINTER_ID 31 - -/* - * Declare a concrete type for the NDK's input event forward declaration. - */ -struct AInputEvent { - virtual ~AInputEvent() { } -}; - -/* - * Declare a concrete type for the NDK's input device forward declaration. - */ -struct AInputDevice { - virtual ~AInputDevice() { } -}; - - -namespace android { - -#ifdef HAVE_ANDROID_OS -class Parcel; -#endif - -/* - * Flags that flow alongside events in the input dispatch system to help with certain - * policy decisions such as waking from device sleep. - * - * These flags are also defined in frameworks/base/core/java/android/view/WindowManagerPolicy.java. - */ -enum { - /* These flags originate in RawEvents and are generally set in the key map. - * NOTE: If you edit these flags, also edit labels in KeycodeLabels.h. */ - - POLICY_FLAG_WAKE = 0x00000001, - POLICY_FLAG_WAKE_DROPPED = 0x00000002, - POLICY_FLAG_SHIFT = 0x00000004, - POLICY_FLAG_CAPS_LOCK = 0x00000008, - POLICY_FLAG_ALT = 0x00000010, - POLICY_FLAG_ALT_GR = 0x00000020, - POLICY_FLAG_MENU = 0x00000040, - POLICY_FLAG_LAUNCHER = 0x00000080, - POLICY_FLAG_VIRTUAL = 0x00000100, - POLICY_FLAG_FUNCTION = 0x00000200, - - POLICY_FLAG_RAW_MASK = 0x0000ffff, - - /* These flags are set by the input dispatcher. */ - - // Indicates that the input event was injected. - POLICY_FLAG_INJECTED = 0x01000000, - - // Indicates that the input event is from a trusted source such as a directly attached - // input device or an application with system-wide event injection permission. - POLICY_FLAG_TRUSTED = 0x02000000, - - // Indicates that the input event has passed through an input filter. - POLICY_FLAG_FILTERED = 0x04000000, - - // Disables automatic key repeating behavior. - POLICY_FLAG_DISABLE_KEY_REPEAT = 0x08000000, - - /* These flags are set by the input reader policy as it intercepts each event. */ - - // Indicates that the screen was off when the event was received and the event - // should wake the device. - POLICY_FLAG_WOKE_HERE = 0x10000000, - - // Indicates that the screen was dim when the event was received and the event - // should brighten the device. - POLICY_FLAG_BRIGHT_HERE = 0x20000000, - - // Indicates that the event should be dispatched to applications. - // The input event should still be sent to the InputDispatcher so that it can see all - // input events received include those that it will not deliver. - POLICY_FLAG_PASS_TO_USER = 0x40000000, -}; - -/* - * Pointer coordinate data. - */ -struct PointerCoords { - enum { MAX_AXES = 14 }; // 14 so that sizeof(PointerCoords) == 64 - - // Bitfield of axes that are present in this structure. - uint64_t bits; - - // Values of axes that are stored in this structure packed in order by axis id - // for each axis that is present in the structure according to 'bits'. - float values[MAX_AXES]; - - inline void clear() { - bits = 0; - } - - float getAxisValue(int32_t axis) const; - status_t setAxisValue(int32_t axis, float value); - - void scale(float scale); - - inline float getX() const { - return getAxisValue(AMOTION_EVENT_AXIS_X); - } - - inline float getY() const { - return getAxisValue(AMOTION_EVENT_AXIS_Y); - } - -#ifdef HAVE_ANDROID_OS - status_t readFromParcel(Parcel* parcel); - status_t writeToParcel(Parcel* parcel) const; -#endif - - bool operator==(const PointerCoords& other) const; - inline bool operator!=(const PointerCoords& other) const { - return !(*this == other); - } - - void copyFrom(const PointerCoords& other); - -private: - void tooManyAxes(int axis); -}; - -/* - * Pointer property data. - */ -struct PointerProperties { - // The id of the pointer. - int32_t id; - - // The pointer tool type. - int32_t toolType; - - inline void clear() { - id = -1; - toolType = 0; - } - - bool operator==(const PointerProperties& other) const; - inline bool operator!=(const PointerProperties& other) const { - return !(*this == other); - } - - void copyFrom(const PointerProperties& other); -}; - -/* - * Input events. - */ -class InputEvent : public AInputEvent { -public: - virtual ~InputEvent() { } - - virtual int32_t getType() const = 0; - - inline int32_t getDeviceId() const { return mDeviceId; } - - inline int32_t getSource() const { return mSource; } - - inline void setSource(int32_t source) { mSource = source; } - -protected: - void initialize(int32_t deviceId, int32_t source); - void initialize(const InputEvent& from); - - int32_t mDeviceId; - int32_t mSource; -}; - -/* - * Key events. - */ -class KeyEvent : public InputEvent { -public: - virtual ~KeyEvent() { } - - virtual int32_t getType() const { return AINPUT_EVENT_TYPE_KEY; } - - inline int32_t getAction() const { return mAction; } - - inline int32_t getFlags() const { return mFlags; } - - inline void setFlags(int32_t flags) { mFlags = flags; } - - inline int32_t getKeyCode() const { return mKeyCode; } - - inline int32_t getScanCode() const { return mScanCode; } - - inline int32_t getMetaState() const { return mMetaState; } - - inline int32_t getRepeatCount() const { return mRepeatCount; } - - inline nsecs_t getDownTime() const { return mDownTime; } - - inline nsecs_t getEventTime() const { return mEventTime; } - - // Return true if this event may have a default action implementation. - static bool hasDefaultAction(int32_t keyCode); - bool hasDefaultAction() const; - - // Return true if this event represents a system key. - static bool isSystemKey(int32_t keyCode); - bool isSystemKey() const; - - void initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime); - void initialize(const KeyEvent& from); - -protected: - int32_t mAction; - int32_t mFlags; - int32_t mKeyCode; - int32_t mScanCode; - int32_t mMetaState; - int32_t mRepeatCount; - nsecs_t mDownTime; - nsecs_t mEventTime; -}; - -/* - * Motion events. - */ -class MotionEvent : public InputEvent { -public: - virtual ~MotionEvent() { } - - virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; } - - inline int32_t getAction() const { return mAction; } - - inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; } - - inline int32_t getActionIndex() const { - return (mAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - inline void setAction(int32_t action) { mAction = action; } - - inline int32_t getFlags() const { return mFlags; } - - inline void setFlags(int32_t flags) { mFlags = flags; } - - inline int32_t getEdgeFlags() const { return mEdgeFlags; } - - inline void setEdgeFlags(int32_t edgeFlags) { mEdgeFlags = edgeFlags; } - - inline int32_t getMetaState() const { return mMetaState; } - - inline void setMetaState(int32_t metaState) { mMetaState = metaState; } - - inline int32_t getButtonState() const { return mButtonState; } - - inline float getXOffset() const { return mXOffset; } - - inline float getYOffset() const { return mYOffset; } - - inline float getXPrecision() const { return mXPrecision; } - - inline float getYPrecision() const { return mYPrecision; } - - inline nsecs_t getDownTime() const { return mDownTime; } - - inline void setDownTime(nsecs_t downTime) { mDownTime = downTime; } - - inline size_t getPointerCount() const { return mPointerProperties.size(); } - - inline const PointerProperties* getPointerProperties(size_t pointerIndex) const { - return &mPointerProperties[pointerIndex]; - } - - inline int32_t getPointerId(size_t pointerIndex) const { - return mPointerProperties[pointerIndex].id; - } - - inline int32_t getToolType(size_t pointerIndex) const { - return mPointerProperties[pointerIndex].toolType; - } - - inline nsecs_t getEventTime() const { return mSampleEventTimes[getHistorySize()]; } - - const PointerCoords* getRawPointerCoords(size_t pointerIndex) const; - - float getRawAxisValue(int32_t axis, size_t pointerIndex) const; - - inline float getRawX(size_t pointerIndex) const { - return getRawAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); - } - - inline float getRawY(size_t pointerIndex) const { - return getRawAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); - } - - float getAxisValue(int32_t axis, size_t pointerIndex) const; - - inline float getX(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex); - } - - inline float getY(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex); - } - - inline float getPressure(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pointerIndex); - } - - inline float getSize(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_SIZE, pointerIndex); - } - - inline float getTouchMajor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex); - } - - inline float getTouchMinor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex); - } - - inline float getToolMajor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex); - } - - inline float getToolMinor(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex); - } - - inline float getOrientation(size_t pointerIndex) const { - return getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex); - } - - inline size_t getHistorySize() const { return mSampleEventTimes.size() - 1; } - - inline nsecs_t getHistoricalEventTime(size_t historicalIndex) const { - return mSampleEventTimes[historicalIndex]; - } - - const PointerCoords* getHistoricalRawPointerCoords( - size_t pointerIndex, size_t historicalIndex) const; - - float getHistoricalRawAxisValue(int32_t axis, size_t pointerIndex, - size_t historicalIndex) const; - - inline float getHistoricalRawX(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalRawAxisValue( - AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); - } - - inline float getHistoricalRawY(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalRawAxisValue( - AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); - } - - float getHistoricalAxisValue(int32_t axis, size_t pointerIndex, size_t historicalIndex) const; - - inline float getHistoricalX(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_X, pointerIndex, historicalIndex); - } - - inline float getHistoricalY(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_Y, pointerIndex, historicalIndex); - } - - inline float getHistoricalPressure(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, pointerIndex, historicalIndex); - } - - inline float getHistoricalSize(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_SIZE, pointerIndex, historicalIndex); - } - - inline float getHistoricalTouchMajor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOUCH_MAJOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalTouchMinor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOUCH_MINOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalToolMajor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOOL_MAJOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalToolMinor(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_TOOL_MINOR, pointerIndex, historicalIndex); - } - - inline float getHistoricalOrientation(size_t pointerIndex, size_t historicalIndex) const { - return getHistoricalAxisValue( - AMOTION_EVENT_AXIS_ORIENTATION, pointerIndex, historicalIndex); - } - - ssize_t findPointerIndex(int32_t pointerId) const; - - void initialize( - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); - - void copyFrom(const MotionEvent* other, bool keepHistory); - - void addSample( - nsecs_t eventTime, - const PointerCoords* pointerCoords); - - void offsetLocation(float xOffset, float yOffset); - - void scale(float scaleFactor); - -#ifdef HAVE_ANDROID_OS - void transform(const SkMatrix* matrix); - - status_t readFromParcel(Parcel* parcel); - status_t writeToParcel(Parcel* parcel) const; -#endif - - static bool isTouchEvent(int32_t source, int32_t action); - inline bool isTouchEvent() const { - return isTouchEvent(mSource, mAction); - } - - // Low-level accessors. - inline const PointerProperties* getPointerProperties() const { - return mPointerProperties.array(); - } - inline const nsecs_t* getSampleEventTimes() const { return mSampleEventTimes.array(); } - inline const PointerCoords* getSamplePointerCoords() const { - return mSamplePointerCoords.array(); - } - -protected: - int32_t mAction; - int32_t mFlags; - int32_t mEdgeFlags; - int32_t mMetaState; - int32_t mButtonState; - float mXOffset; - float mYOffset; - float mXPrecision; - float mYPrecision; - nsecs_t mDownTime; - Vector mPointerProperties; - Vector mSampleEventTimes; - Vector mSamplePointerCoords; -}; - -/* - * Input event factory. - */ -class InputEventFactoryInterface { -protected: - virtual ~InputEventFactoryInterface() { } - -public: - InputEventFactoryInterface() { } - - virtual KeyEvent* createKeyEvent() = 0; - virtual MotionEvent* createMotionEvent() = 0; -}; - -/* - * A simple input event factory implementation that uses a single preallocated instance - * of each type of input event that are reused for each request. - */ -class PreallocatedInputEventFactory : public InputEventFactoryInterface { -public: - PreallocatedInputEventFactory() { } - virtual ~PreallocatedInputEventFactory() { } - - virtual KeyEvent* createKeyEvent() { return & mKeyEvent; } - virtual MotionEvent* createMotionEvent() { return & mMotionEvent; } - -private: - KeyEvent mKeyEvent; - MotionEvent mMotionEvent; -}; - -/* - * An input event factory implementation that maintains a pool of input events. - */ -class PooledInputEventFactory : public InputEventFactoryInterface { -public: - PooledInputEventFactory(size_t maxPoolSize = 20); - virtual ~PooledInputEventFactory(); - - virtual KeyEvent* createKeyEvent(); - virtual MotionEvent* createMotionEvent(); - - void recycle(InputEvent* event); - -private: - const size_t mMaxPoolSize; - - Vector mKeyEventPool; - Vector mMotionEventPool; -}; - -} // namespace android - -#endif // _ANDROIDFW_INPUT_H diff --git a/widget/gonk/libui/InputApplication.cpp b/widget/gonk/libui/InputApplication.cpp deleted file mode 100644 index ce432356b..000000000 --- a/widget/gonk/libui/InputApplication.cpp +++ /dev/null @@ -1,42 +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. - */ - -#define LOG_TAG "InputApplication" - -#include "InputApplication.h" - -#include "cutils_log.h" - -namespace android { - -// --- InputApplicationHandle --- - -InputApplicationHandle::InputApplicationHandle() : - mInfo(NULL) { -} - -InputApplicationHandle::~InputApplicationHandle() { - delete mInfo; -} - -void InputApplicationHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = NULL; - } -} - -} // namespace android diff --git a/widget/gonk/libui/InputApplication.h b/widget/gonk/libui/InputApplication.h deleted file mode 100644 index ba789559c..000000000 --- a/widget/gonk/libui/InputApplication.h +++ /dev/null @@ -1,83 +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. - */ - -#ifndef _UI_INPUT_APPLICATION_H -#define _UI_INPUT_APPLICATION_H - -#include "Input.h" - -#include -#include -#include - -namespace android { - -/* - * Describes the properties of an application that can receive input. - */ -struct InputApplicationInfo { - String8 name; - nsecs_t dispatchingTimeout; -}; - - -/* - * Handle for an application that can receive input. - * - * Used by the native input dispatcher as a handle for the window manager objects - * that describe an application. - */ -class InputApplicationHandle : public RefBase { -public: - inline const InputApplicationInfo* getInfo() const { - return mInfo; - } - - inline String8 getName() const { - return mInfo ? mInfo->name : String8(""); - } - - inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - - /** - * Releases the storage used by the associated information when it is - * no longer needed. - */ - void releaseInfo(); - -protected: - InputApplicationHandle(); - virtual ~InputApplicationHandle(); - - InputApplicationInfo* mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_APPLICATION_H diff --git a/widget/gonk/libui/InputDevice.cpp b/widget/gonk/libui/InputDevice.cpp deleted file mode 100644 index 01a437dd4..000000000 --- a/widget/gonk/libui/InputDevice.cpp +++ /dev/null @@ -1,184 +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. - */ - -#define LOG_TAG "InputDevice" - -#include -#include -#include - -#include "InputDevice.h" - -namespace android { - -static const char* CONFIGURATION_FILE_DIR[] = { - "idc/", - "keylayout/", - "keychars/", -}; - -static const char* CONFIGURATION_FILE_EXTENSION[] = { - ".idc", - ".kl", - ".kcm", -}; - -static bool isValidNameChar(char ch) { - return isascii(ch) && (isdigit(ch) || isalpha(ch) || ch == '-' || ch == '_'); -} - -static void appendInputDeviceConfigurationFileRelativePath(String8& path, - const String8& name, InputDeviceConfigurationFileType type) { - path.append(CONFIGURATION_FILE_DIR[type]); - for (size_t i = 0; i < name.length(); i++) { - char ch = name[i]; - if (!isValidNameChar(ch)) { - ch = '_'; - } - path.append(&ch, 1); - } - path.append(CONFIGURATION_FILE_EXTENSION[type]); -} - -String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( - const InputDeviceIdentifier& deviceIdentifier, - InputDeviceConfigurationFileType type) { - if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) { - if (deviceIdentifier.version != 0) { - // Try vendor product version. - String8 versionPath(getInputDeviceConfigurationFilePathByName( - String8::format("Vendor_%04x_Product_%04x_Version_%04x", - deviceIdentifier.vendor, deviceIdentifier.product, - deviceIdentifier.version), - type)); - if (!versionPath.isEmpty()) { - return versionPath; - } - } - - // Try vendor product. - String8 productPath(getInputDeviceConfigurationFilePathByName( - String8::format("Vendor_%04x_Product_%04x", - deviceIdentifier.vendor, deviceIdentifier.product), - type)); - if (!productPath.isEmpty()) { - return productPath; - } - } - - // Try device name. - return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type); -} - -String8 getInputDeviceConfigurationFilePathByName( - const String8& name, InputDeviceConfigurationFileType type) { - // Search system repository. - String8 path; - path.setTo(getenv("ANDROID_ROOT")); - path.append("/usr/"); - appendInputDeviceConfigurationFileRelativePath(path, name, type); -#if DEBUG_PROBE - ALOGD("Probing for system provided input device configuration file: path='%s'", path.string()); -#endif - if (!access(path.string(), R_OK)) { -#if DEBUG_PROBE - ALOGD("Found"); -#endif - return path; - } - - // Search user repository. - // TODO Should only look here if not in safe mode. - path.setTo(getenv("ANDROID_DATA")); - path.append("/system/devices/"); - appendInputDeviceConfigurationFileRelativePath(path, name, type); -#if DEBUG_PROBE - ALOGD("Probing for system user input device configuration file: path='%s'", path.string()); -#endif - if (!access(path.string(), R_OK)) { -#if DEBUG_PROBE - ALOGD("Found"); -#endif - return path; - } - - // Not found. -#if DEBUG_PROBE - ALOGD("Probe failed to find input device configuration file: name='%s', type=%d", - name.string(), type); -#endif - return String8(); -} - - -// --- InputDeviceInfo --- - -InputDeviceInfo::InputDeviceInfo() { - initialize(-1, -1, InputDeviceIdentifier(), String8(), false); -} - -InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : - mId(other.mId), mGeneration(other.mGeneration), mIdentifier(other.mIdentifier), - mAlias(other.mAlias), mIsExternal(other.mIsExternal), mSources(other.mSources), - mKeyboardType(other.mKeyboardType), - mKeyCharacterMap(other.mKeyCharacterMap), - mHasVibrator(other.mHasVibrator), - mMotionRanges(other.mMotionRanges) { -} - -InputDeviceInfo::~InputDeviceInfo() { -} - -void InputDeviceInfo::initialize(int32_t id, int32_t generation, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { - mId = id; - mGeneration = generation; - mIdentifier = identifier; - mAlias = alias; - mIsExternal = isExternal; - mSources = 0; - mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; - mHasVibrator = false; - mMotionRanges.clear(); -} - -const InputDeviceInfo::MotionRange* InputDeviceInfo::getMotionRange( - int32_t axis, uint32_t source) const { - size_t numRanges = mMotionRanges.size(); - for (size_t i = 0; i < numRanges; i++) { - const MotionRange& range = mMotionRanges.itemAt(i); - if (range.axis == axis && range.source == source) { - return ⦥ - } - } - return NULL; -} - -void InputDeviceInfo::addSource(uint32_t source) { - mSources |= source; -} - -void InputDeviceInfo::addMotionRange(int32_t axis, uint32_t source, float min, float max, - float flat, float fuzz, float resolution) { - MotionRange range = { axis, source, min, max, flat, fuzz, resolution }; - mMotionRanges.add(range); -} - -void InputDeviceInfo::addMotionRange(const MotionRange& range) { - mMotionRanges.add(range); -} - -} // namespace android diff --git a/widget/gonk/libui/InputDevice.h b/widget/gonk/libui/InputDevice.h deleted file mode 100644 index 0ab5863c9..000000000 --- a/widget/gonk/libui/InputDevice.h +++ /dev/null @@ -1,156 +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. - */ - -#ifndef _ANDROIDFW_INPUT_DEVICE_H -#define _ANDROIDFW_INPUT_DEVICE_H - -#include "Input.h" -#include "KeyCharacterMap.h" - -namespace android { - -/* - * Identifies a device. - */ -struct InputDeviceIdentifier { - inline InputDeviceIdentifier() : - bus(0), vendor(0), product(0), version(0) { - } - - // Information provided by the kernel. - String8 name; - String8 location; - String8 uniqueId; - uint16_t bus; - uint16_t vendor; - uint16_t product; - uint16_t version; - - // A composite input device descriptor string that uniquely identifies the device - // even across reboots or reconnections. The value of this field is used by - // upper layers of the input system to associate settings with individual devices. - // It is hashed from whatever kernel provided information is available. - // Ideally, the way this value is computed should not change between Android releases - // because that would invalidate persistent settings that rely on it. - String8 descriptor; -}; - -/* - * Describes the characteristics and capabilities of an input device. - */ -class InputDeviceInfo { -public: - InputDeviceInfo(); - InputDeviceInfo(const InputDeviceInfo& other); - ~InputDeviceInfo(); - - struct MotionRange { - int32_t axis; - uint32_t source; - float min; - float max; - float flat; - float fuzz; - float resolution; - }; - - void initialize(int32_t id, int32_t generation, const InputDeviceIdentifier& identifier, - const String8& alias, bool isExternal); - - inline int32_t getId() const { return mId; } - inline int32_t getGeneration() const { return mGeneration; } - inline const InputDeviceIdentifier& getIdentifier() const { return mIdentifier; } - inline const String8& getAlias() const { return mAlias; } - inline const String8& getDisplayName() const { - return mAlias.isEmpty() ? mIdentifier.name : mAlias; - } - inline bool isExternal() const { return mIsExternal; } - inline uint32_t getSources() const { return mSources; } - - const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; - - void addSource(uint32_t source); - void addMotionRange(int32_t axis, uint32_t source, - float min, float max, float flat, float fuzz, float resolution); - void addMotionRange(const MotionRange& range); - - inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; } - inline int32_t getKeyboardType() const { return mKeyboardType; } - - inline void setKeyCharacterMap(const sp& value) { - mKeyCharacterMap = value; - } - - inline sp getKeyCharacterMap() const { - return mKeyCharacterMap; - } - - inline void setVibrator(bool hasVibrator) { mHasVibrator = hasVibrator; } - inline bool hasVibrator() const { return mHasVibrator; } - - inline const Vector& getMotionRanges() const { - return mMotionRanges; - } - -private: - int32_t mId; - int32_t mGeneration; - InputDeviceIdentifier mIdentifier; - String8 mAlias; - bool mIsExternal; - uint32_t mSources; - int32_t mKeyboardType; - sp mKeyCharacterMap; - bool mHasVibrator; - - Vector mMotionRanges; -}; - -/* Types of input device configuration files. */ -enum InputDeviceConfigurationFileType { - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION = 0, /* .idc file */ - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT = 1, /* .kl file */ - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP = 2, /* .kcm file */ -}; - -/* - * Gets the path of an input device configuration file, if one is available. - * Considers both system provided and user installed configuration files. - * - * The device identifier is used to construct several default configuration file - * names to try based on the device name, vendor, product, and version. - * - * Returns an empty string if not found. - */ -extern String8 getInputDeviceConfigurationFilePathByDeviceIdentifier( - const InputDeviceIdentifier& deviceIdentifier, - InputDeviceConfigurationFileType type); - -/* - * Gets the path of an input device configuration file, if one is available. - * Considers both system provided and user installed configuration files. - * - * The name is case-sensitive and is used to construct the filename to resolve. - * All characters except 'a'-'z', 'A'-'Z', '0'-'9', '-', and '_' are replaced by underscores. - * - * Returns an empty string if not found. - */ -extern String8 getInputDeviceConfigurationFilePathByName( - const String8& name, InputDeviceConfigurationFileType type); - -} // namespace android - -#endif // _ANDROIDFW_INPUT_DEVICE_H diff --git a/widget/gonk/libui/InputDispatcher.cpp b/widget/gonk/libui/InputDispatcher.cpp deleted file mode 100644 index 7adaa1998..000000000 --- a/widget/gonk/libui/InputDispatcher.cpp +++ /dev/null @@ -1,4430 +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. - */ - -#define LOG_TAG "InputDispatcher" -#define ATRACE_TAG ATRACE_TAG_INPUT - -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -// Log detailed debug messages about each inbound event notification to the dispatcher. -#define DEBUG_INBOUND_EVENT_DETAILS 0 - -// Log detailed debug messages about each outbound event processed by the dispatcher. -#define DEBUG_OUTBOUND_EVENT_DETAILS 0 - -// Log debug messages about the dispatch cycle. -#define DEBUG_DISPATCH_CYCLE 0 - -// Log debug messages about registrations. -#define DEBUG_REGISTRATION 0 - -// Log debug messages about input event injection. -#define DEBUG_INJECTION 0 - -// Log debug messages about input focus tracking. -#define DEBUG_FOCUS 0 - -// Log debug messages about the app switch latency optimization. -#define DEBUG_APP_SWITCH 0 - -// Log debug messages about hover events. -#define DEBUG_HOVER 0 - -#include "InputDispatcher.h" - -#include "Trace.h" -#include "PowerManager.h" - -#include -#include -#include -#include -#include - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " - -namespace android { - -// Default input dispatching timeout if there is no focused application or paused window -// from which to determine an appropriate dispatching timeout. -const nsecs_t DEFAULT_INPUT_DISPATCHING_TIMEOUT = 5000 * 1000000LL; // 5 sec - -// Amount of time to allow for all pending events to be processed when an app switch -// key is on the way. This is used to preempt input dispatch and drop input events -// when an application takes too long to respond and the user has pressed an app switch key. -const nsecs_t APP_SWITCH_TIMEOUT = 500 * 1000000LL; // 0.5sec - -// Amount of time to allow for an event to be dispatched (measured since its eventTime) -// before considering it stale and dropping it. -const nsecs_t STALE_EVENT_TIMEOUT = 10000 * 1000000LL; // 10sec - -// Amount of time to allow touch events to be streamed out to a connection before requiring -// that the first event be finished. This value extends the ANR timeout by the specified -// amount. For example, if streaming is allowed to get ahead by one second relative to the -// queue of waiting unfinished events, then ANRs will similarly be delayed by one second. -const nsecs_t STREAM_AHEAD_EVENT_TIMEOUT = 500 * 1000000LL; // 0.5sec - -// Log a warning when an event takes longer than this to process, even if an ANR does not occur. -const nsecs_t SLOW_EVENT_PROCESSING_WARNING_TIMEOUT = 2000 * 1000000LL; // 2sec - - -static inline nsecs_t now() { - return systemTime(SYSTEM_TIME_MONOTONIC); -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static inline int32_t getMotionEventActionPointerIndex(int32_t action) { - return (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; -} - -static bool isValidKeyAction(int32_t action) { - switch (action) { - case AKEY_EVENT_ACTION_DOWN: - case AKEY_EVENT_ACTION_UP: - return true; - default: - return false; - } -} - -static bool validateKeyEvent(int32_t action) { - if (! isValidKeyAction(action)) { - ALOGE("Key event has invalid action code 0x%x", action); - return false; - } - return true; -} - -static bool isValidMotionAction(int32_t action, size_t pointerCount) { - switch (action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_SCROLL: - return true; - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_POINTER_UP: { - int32_t index = getMotionEventActionPointerIndex(action); - return index >= 0 && size_t(index) < pointerCount; - } - default: - return false; - } -} - -static bool validateMotionEvent(int32_t action, size_t pointerCount, - const PointerProperties* pointerProperties) { - if (! isValidMotionAction(action, pointerCount)) { - ALOGE("Motion event has invalid action code 0x%x", action); - return false; - } - if (pointerCount < 1 || pointerCount > MAX_POINTERS) { - ALOGE("Motion event has invalid pointer count %d; value must be between 1 and %d.", - pointerCount, MAX_POINTERS); - return false; - } - BitSet32 pointerIdBits; - for (size_t i = 0; i < pointerCount; i++) { - int32_t id = pointerProperties[i].id; - if (id < 0 || id > MAX_POINTER_ID) { - ALOGE("Motion event has invalid pointer id %d; value must be between 0 and %d", - id, MAX_POINTER_ID); - return false; - } - if (pointerIdBits.hasBit(id)) { - ALOGE("Motion event has duplicate pointer id %d", id); - return false; - } - pointerIdBits.markBit(id); - } - return true; -} - -static bool isMainDisplay(int32_t displayId) { - return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE; -} - -static void dumpRegion(String8& dump, const SkRegion& region) { - if (region.isEmpty()) { - dump.append(""); - return; - } - - bool first = true; - for (SkRegion::Iterator it(region); !it.done(); it.next()) { - if (first) { - first = false; - } else { - dump.append("|"); - } - const SkIRect& rect = it.rect(); - dump.appendFormat("[%d,%d][%d,%d]", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom); - } -} - - -// --- InputDispatcher --- - -InputDispatcher::InputDispatcher(const sp& policy) : - mPolicy(policy), - mPendingEvent(NULL), mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX), - mNextUnblockedEvent(NULL), - mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false), - mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) { - mLooper = new Looper(false); - - mKeyRepeatState.lastKeyEntry = NULL; - - policy->getDispatcherConfiguration(&mConfig); -} - -InputDispatcher::~InputDispatcher() { - { // acquire lock - AutoMutex _l(mLock); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - } - - while (mConnectionsByFd.size() != 0) { - unregisterInputChannel(mConnectionsByFd.valueAt(0)->inputChannel); - } -} - -void InputDispatcher::dispatchOnce() { - nsecs_t nextWakeupTime = LONG_LONG_MAX; - { // acquire lock - AutoMutex _l(mLock); - mDispatcherIsAliveCondition.broadcast(); - - // Run a dispatch loop if there are no pending commands. - // The dispatch loop might enqueue commands to run afterwards. - if (!haveCommandsLocked()) { - dispatchOnceInnerLocked(&nextWakeupTime); - } - - // Run all pending commands if there are any. - // If any commands were run then force the next poll to wake up immediately. - if (runCommandsLockedInterruptible()) { - nextWakeupTime = LONG_LONG_MIN; - } - } // release lock - - // Wait for callback or timeout or wake. (make sure we round up, not down) - nsecs_t currentTime = now(); - int timeoutMillis = toMillisecondTimeoutDelay(currentTime, nextWakeupTime); - mLooper->pollOnce(timeoutMillis); -} - -void InputDispatcher::dispatchOnceInnerLocked(nsecs_t* nextWakeupTime) { - nsecs_t currentTime = now(); - - // Reset the key repeat timer whenever we disallow key events, even if the next event - // is not a key. This is to ensure that we abort a key repeat if the device is just coming - // out of sleep. - if (!mPolicy->isKeyRepeatEnabled()) { - resetKeyRepeatLocked(); - } - - // If dispatching is frozen, do not process timeouts or try to deliver any new events. - if (mDispatchFrozen) { -#if DEBUG_FOCUS - ALOGD("Dispatch frozen. Waiting some more."); -#endif - return; - } - - // Optimize latency of app switches. - // Essentially we start a short timeout when an app switch key (HOME / ENDCALL) has - // been pressed. When it expires, we preempt dispatch and drop all other pending events. - bool isAppSwitchDue = mAppSwitchDueTime <= currentTime; - if (mAppSwitchDueTime < *nextWakeupTime) { - *nextWakeupTime = mAppSwitchDueTime; - } - - // Ready to start a new event. - // If we don't already have a pending event, go grab one. - if (! mPendingEvent) { - if (mInboundQueue.isEmpty()) { - if (isAppSwitchDue) { - // The inbound queue is empty so the app switch key we were waiting - // for will never arrive. Stop waiting for it. - resetPendingAppSwitchLocked(false); - isAppSwitchDue = false; - } - - // Synthesize a key repeat if appropriate. - if (mKeyRepeatState.lastKeyEntry) { - if (currentTime >= mKeyRepeatState.nextRepeatTime) { - mPendingEvent = synthesizeKeyRepeatLocked(currentTime); - } else { - if (mKeyRepeatState.nextRepeatTime < *nextWakeupTime) { - *nextWakeupTime = mKeyRepeatState.nextRepeatTime; - } - } - } - - // Nothing to do if there is no pending event. - if (!mPendingEvent) { - return; - } - } else { - // Inbound queue has at least one entry. - mPendingEvent = mInboundQueue.dequeueAtHead(); - traceInboundQueueLengthLocked(); - } - - // Poke user activity for this event. - if (mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER) { - pokeUserActivityLocked(mPendingEvent); - } - - // Get ready to dispatch the event. - resetANRTimeoutsLocked(); - } - - // Now we have an event to dispatch. - // All events are eventually dequeued and processed this way, even if we intend to drop them. - ALOG_ASSERT(mPendingEvent != NULL); - bool done = false; - DropReason dropReason = DROP_REASON_NOT_DROPPED; - if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) { - dropReason = DROP_REASON_POLICY; - } else if (!mDispatchEnabled) { - dropReason = DROP_REASON_DISABLED; - } - - if (mNextUnblockedEvent == mPendingEvent) { - mNextUnblockedEvent = NULL; - } - - switch (mPendingEvent->type) { - case EventEntry::TYPE_CONFIGURATION_CHANGED: { - ConfigurationChangedEntry* typedEntry = - static_cast(mPendingEvent); - done = dispatchConfigurationChangedLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // configuration changes are never dropped - break; - } - - case EventEntry::TYPE_DEVICE_RESET: { - DeviceResetEntry* typedEntry = - static_cast(mPendingEvent); - done = dispatchDeviceResetLocked(currentTime, typedEntry); - dropReason = DROP_REASON_NOT_DROPPED; // device resets are never dropped - break; - } - - case EventEntry::TYPE_KEY: { - KeyEntry* typedEntry = static_cast(mPendingEvent); - if (isAppSwitchDue) { - if (isAppSwitchKeyEventLocked(typedEntry)) { - resetPendingAppSwitchLocked(true); - isAppSwitchDue = false; - } else if (dropReason == DROP_REASON_NOT_DROPPED) { - dropReason = DROP_REASON_APP_SWITCH; - } - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEventLocked(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchKeyLocked(currentTime, typedEntry, &dropReason, nextWakeupTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* typedEntry = static_cast(mPendingEvent); - if (dropReason == DROP_REASON_NOT_DROPPED && isAppSwitchDue) { - dropReason = DROP_REASON_APP_SWITCH; - } - if (dropReason == DROP_REASON_NOT_DROPPED - && isStaleEventLocked(currentTime, typedEntry)) { - dropReason = DROP_REASON_STALE; - } - if (dropReason == DROP_REASON_NOT_DROPPED && mNextUnblockedEvent) { - dropReason = DROP_REASON_BLOCKED; - } - done = dispatchMotionLocked(currentTime, typedEntry, - &dropReason, nextWakeupTime); - break; - } - - default: - ALOG_ASSERT(false); - break; - } - - if (done) { - if (dropReason != DROP_REASON_NOT_DROPPED) { - dropInboundEventLocked(mPendingEvent, dropReason); - } - - releasePendingEventLocked(); - *nextWakeupTime = LONG_LONG_MIN; // force next poll to wake up immediately - } -} - -bool InputDispatcher::enqueueInboundEventLocked(EventEntry* entry) { - bool needWake = mInboundQueue.isEmpty(); - mInboundQueue.enqueueAtTail(entry); - traceInboundQueueLengthLocked(); - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - // Optimize app switch latency. - // If the application takes too long to catch up then we drop all events preceding - // the app switch key. - KeyEntry* keyEntry = static_cast(entry); - if (isAppSwitchKeyEventLocked(keyEntry)) { - if (keyEntry->action == AKEY_EVENT_ACTION_DOWN) { - mAppSwitchSawKeyDown = true; - } else if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - if (mAppSwitchSawKeyDown) { -#if DEBUG_APP_SWITCH - ALOGD("App switch is pending!"); -#endif - mAppSwitchDueTime = keyEntry->eventTime + APP_SWITCH_TIMEOUT; - mAppSwitchSawKeyDown = false; - needWake = true; - } - } - } - break; - } - - case EventEntry::TYPE_MOTION: { - // Optimize case where the current application is unresponsive and the user - // decides to touch a window in a different application. - // If the application takes too long to catch up then we drop all events preceding - // the touch into the other window. - MotionEntry* motionEntry = static_cast(entry); - if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN - && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY - && mInputTargetWaitApplicationHandle != NULL) { - int32_t displayId = motionEntry->displayId; - int32_t x = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(motionEntry->pointerCoords[0]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y); - if (touchedWindowHandle != NULL - && touchedWindowHandle->inputApplicationHandle - != mInputTargetWaitApplicationHandle) { - // User touched a different application than the one we are waiting on. - // Flag the event, and start pruning the input queue. - mNextUnblockedEvent = motionEntry; - needWake = true; - } - } - break; - } - } - - return needWake; -} - -sp InputDispatcher::findTouchedWindowAtLocked(int32_t displayId, - int32_t x, int32_t y) { - // Traverse windows from front to back to find touched window. - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId == displayId) { - int32_t flags = windowInfo->layoutParamsFlags; - - if (windowInfo->visible) { - if (!(flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - bool isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - // Found window. - return windowHandle; - } - } - } - - if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) { - // Error window is on top but not visible, so touch is dropped. - return NULL; - } - } - } - return NULL; -} - -void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) { - const char* reason; - switch (dropReason) { - case DROP_REASON_POLICY: -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("Dropped event because policy consumed it."); -#endif - reason = "inbound event was dropped because the policy consumed it"; - break; - case DROP_REASON_DISABLED: - ALOGI("Dropped event because input dispatch is disabled."); - reason = "inbound event was dropped because input dispatch is disabled"; - break; - case DROP_REASON_APP_SWITCH: - ALOGI("Dropped event because of pending overdue app switch."); - reason = "inbound event was dropped because of pending overdue app switch"; - break; - case DROP_REASON_BLOCKED: - ALOGI("Dropped event because the current application is not responding and the user " - "has started interacting with a different application."); - reason = "inbound event was dropped because the current application is not responding " - "and the user has started interacting with a different application"; - break; - case DROP_REASON_STALE: - ALOGI("Dropped event because it is stale."); - reason = "inbound event was dropped because it is stale"; - break; - default: - ALOG_ASSERT(false); - return; - } - - switch (entry->type) { - case EventEntry::TYPE_KEY: { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - break; - } - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast(entry); - if (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } else { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - break; - } - } -} - -bool InputDispatcher::isAppSwitchKeyCode(int32_t keyCode) { - return keyCode == AKEYCODE_HOME - || keyCode == AKEYCODE_ENDCALL - || keyCode == AKEYCODE_APP_SWITCH; -} - -bool InputDispatcher::isAppSwitchKeyEventLocked(KeyEntry* keyEntry) { - return ! (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) - && isAppSwitchKeyCode(keyEntry->keyCode) - && (keyEntry->policyFlags & POLICY_FLAG_TRUSTED) - && (keyEntry->policyFlags & POLICY_FLAG_PASS_TO_USER); -} - -bool InputDispatcher::isAppSwitchPendingLocked() { - return mAppSwitchDueTime != LONG_LONG_MAX; -} - -void InputDispatcher::resetPendingAppSwitchLocked(bool handled) { - mAppSwitchDueTime = LONG_LONG_MAX; - -#if DEBUG_APP_SWITCH - if (handled) { - ALOGD("App switch has arrived."); - } else { - ALOGD("App switch was abandoned."); - } -#endif -} - -bool InputDispatcher::isStaleEventLocked(nsecs_t currentTime, EventEntry* entry) { - return currentTime - entry->eventTime >= STALE_EVENT_TIMEOUT; -} - -bool InputDispatcher::haveCommandsLocked() const { - return !mCommandQueue.isEmpty(); -} - -bool InputDispatcher::runCommandsLockedInterruptible() { - if (mCommandQueue.isEmpty()) { - return false; - } - - do { - CommandEntry* commandEntry = mCommandQueue.dequeueAtHead(); - - Command command = commandEntry->command; - (this->*command)(commandEntry); // commands are implicitly 'LockedInterruptible' - - commandEntry->connection.clear(); - delete commandEntry; - } while (! mCommandQueue.isEmpty()); - return true; -} - -InputDispatcher::CommandEntry* InputDispatcher::postCommandLocked(Command command) { - CommandEntry* commandEntry = new CommandEntry(command); - mCommandQueue.enqueueAtTail(commandEntry); - return commandEntry; -} - -void InputDispatcher::drainInboundQueueLocked() { - while (! mInboundQueue.isEmpty()) { - EventEntry* entry = mInboundQueue.dequeueAtHead(); - releaseInboundEventLocked(entry); - } - traceInboundQueueLengthLocked(); -} - -void InputDispatcher::releasePendingEventLocked() { - if (mPendingEvent) { - resetANRTimeoutsLocked(); - releaseInboundEventLocked(mPendingEvent); - mPendingEvent = NULL; - } -} - -void InputDispatcher::releaseInboundEventLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState && injectionState->injectionResult == INPUT_EVENT_INJECTION_PENDING) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("Injected inbound event was dropped."); -#endif - setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED); - } - if (entry == mNextUnblockedEvent) { - mNextUnblockedEvent = NULL; - } - entry->release(); -} - -void InputDispatcher::resetKeyRepeatLocked() { - if (mKeyRepeatState.lastKeyEntry) { - mKeyRepeatState.lastKeyEntry->release(); - mKeyRepeatState.lastKeyEntry = NULL; - } -} - -InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(nsecs_t currentTime) { - KeyEntry* entry = mKeyRepeatState.lastKeyEntry; - - // Reuse the repeated key entry if it is otherwise unreferenced. - uint32_t policyFlags = (entry->policyFlags & POLICY_FLAG_RAW_MASK) - | POLICY_FLAG_PASS_TO_USER | POLICY_FLAG_TRUSTED; - if (entry->refCount == 1) { - entry->recycle(); - entry->eventTime = currentTime; - entry->policyFlags = policyFlags; - entry->repeatCount += 1; - } else { - KeyEntry* newEntry = new KeyEntry(currentTime, - entry->deviceId, entry->source, policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, - entry->metaState, entry->repeatCount + 1, entry->downTime); - - mKeyRepeatState.lastKeyEntry = newEntry; - entry->release(); - - entry = newEntry; - } - entry->syntheticRepeat = true; - - // Increment reference count since we keep a reference to the event in - // mKeyRepeatState.lastKeyEntry in addition to the one we return. - entry->refCount += 1; - - mKeyRepeatState.nextRepeatTime = currentTime + mConfig.keyRepeatDelay; - return entry; -} - -bool InputDispatcher::dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchConfigurationChanged - eventTime=%lld", entry->eventTime); -#endif - - // Reset key repeating in case a keyboard device was added or removed or something. - resetKeyRepeatLocked(); - - // Enqueue a command to run outside the lock to tell the policy that the configuration changed. - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyConfigurationChangedInterruptible); - commandEntry->eventTime = entry->eventTime; - return true; -} - -bool InputDispatcher::dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("dispatchDeviceReset - eventTime=%lld, deviceId=%d", entry->eventTime, entry->deviceId); -#endif - - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "device was reset"); - options.deviceId = entry->deviceId; - synthesizeCancelationEventsForAllConnectionsLocked(options); - return true; -} - -bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - if (entry->repeatCount == 0 - && entry->action == AKEY_EVENT_ACTION_DOWN - && (entry->policyFlags & POLICY_FLAG_TRUSTED) - && (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) { - if (mKeyRepeatState.lastKeyEntry - && mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) { - // We have seen two identical key downs in a row which indicates that the device - // driver is automatically generating key repeats itself. We take note of the - // repeat here, but we disable our own next key repeat timer since it is clear that - // we will not need to synthesize key repeats ourselves. - entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1; - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves - } else { - // Not a repeat. Save key down state in case we do see a repeat later. - resetKeyRepeatLocked(); - mKeyRepeatState.nextRepeatTime = entry->eventTime + mConfig.keyRepeatTimeout; - } - mKeyRepeatState.lastKeyEntry = entry; - entry->refCount += 1; - } else if (! entry->syntheticRepeat) { - resetKeyRepeatLocked(); - } - - if (entry->repeatCount == 1) { - entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS; - } else { - entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS; - } - - entry->dispatchInProgress = true; - - logOutboundKeyDetailsLocked("dispatchKey - ", entry); - } - - // Handle case where the policy asked us to try again later last time. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER) { - if (currentTime < entry->interceptKeyWakeupTime) { - if (entry->interceptKeyWakeupTime < *nextWakeupTime) { - *nextWakeupTime = entry->interceptKeyWakeupTime; - } - return false; // wait until next wakeup - } - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - entry->interceptKeyWakeupTime = 0; - } - - // Give the policy a chance to intercept the key. - if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN) { - if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible); - if (mFocusedWindowHandle != NULL) { - commandEntry->inputWindowHandle = mFocusedWindowHandle; - } - commandEntry->keyEntry = entry; - entry->refCount += 1; - return false; // wait for the command to run - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } - } else if (entry->interceptKeyResult == KeyEntry::INTERCEPT_KEY_RESULT_SKIP) { - if (*dropReason == DROP_REASON_NOT_DROPPED) { - *dropReason = DROP_REASON_POLICY; - } - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - // Identify targets. - Vector inputTargets; - int32_t injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - addMonitoringTargetsLocked(inputTargets); - - // Dispatch the key. - dispatchEventLocked(currentTime, entry, inputTargets); - return true; -} - -void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, " - "repeatCount=%d, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState, - entry->repeatCount, entry->downTime); -#endif -} - -bool InputDispatcher::dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, DropReason* dropReason, nsecs_t* nextWakeupTime) { - // Preprocessing. - if (! entry->dispatchInProgress) { - entry->dispatchInProgress = true; - - logOutboundMotionDetailsLocked("dispatchMotion - ", entry); - } - - // Clean up if dropping the event. - if (*dropReason != DROP_REASON_NOT_DROPPED) { - setInjectionResultLocked(entry, *dropReason == DROP_REASON_POLICY - ? INPUT_EVENT_INJECTION_SUCCEEDED : INPUT_EVENT_INJECTION_FAILED); - return true; - } - - bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER; - - // Identify targets. - Vector inputTargets; - - bool conflictingPointerActions = false; - int32_t injectionResult; - if (isPointerEvent) { - // Pointer event. (eg. touchscreen) - injectionResult = findTouchedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime, &conflictingPointerActions); - } else { - // Non touch event. (eg. trackball) - injectionResult = findFocusedWindowTargetsLocked(currentTime, - entry, inputTargets, nextWakeupTime); - } - if (injectionResult == INPUT_EVENT_INJECTION_PENDING) { - return false; - } - - setInjectionResultLocked(entry, injectionResult); - if (injectionResult != INPUT_EVENT_INJECTION_SUCCEEDED) { - return true; - } - - // TODO: support sending secondary display events to input monitors - if (isMainDisplay(entry->displayId)) { - addMonitoringTargetsLocked(inputTargets); - } - - // Dispatch the motion. - if (conflictingPointerActions) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "conflicting pointer actions"); - synthesizeCancelationEventsForAllConnectionsLocked(options); - } - dispatchEventLocked(currentTime, entry, inputTargets); - return true; -} - - -void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("%seventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, " - "metaState=0x%x, buttonState=0x%x, " - "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%lld", - prefix, - entry->eventTime, entry->deviceId, entry->source, entry->policyFlags, - entry->action, entry->flags, - entry->metaState, entry->buttonState, - entry->edgeFlags, entry->xPrecision, entry->yPrecision, - entry->downTime); - - for (uint32_t i = 0; i < entry->pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, entry->pointerProperties[i].id, - entry->pointerProperties[i].toolType, - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - entry->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } -#endif -} - -void InputDispatcher::dispatchEventLocked(nsecs_t currentTime, - EventEntry* eventEntry, const Vector& inputTargets) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("dispatchEventToCurrentInputTargets"); -#endif - - ALOG_ASSERT(eventEntry->dispatchInProgress); // should already have been set to true - - pokeUserActivityLocked(eventEntry); - - for (size_t i = 0; i < inputTargets.size(); i++) { - const InputTarget& inputTarget = inputTargets.itemAt(i); - - ssize_t connectionIndex = getConnectionIndexLocked(inputTarget.inputChannel); - if (connectionIndex >= 0) { - sp connection = mConnectionsByFd.valueAt(connectionIndex); - prepareDispatchCycleLocked(currentTime, connection, eventEntry, &inputTarget); - } else { -#if DEBUG_FOCUS - ALOGD("Dropping event delivery to target with channel '%s' because it " - "is no longer registered with the input dispatcher.", - inputTarget.inputChannel->getName().string()); -#endif - } - } -} - -int32_t InputDispatcher::handleTargetsNotReadyLocked(nsecs_t currentTime, - const EventEntry* entry, - const sp& applicationHandle, - const sp& windowHandle, - nsecs_t* nextWakeupTime, const char* reason) { - if (applicationHandle == NULL && windowHandle == NULL) { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) { -#if DEBUG_FOCUS - ALOGD("Waiting for system to become ready for input. Reason: %s", reason); -#endif - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = LONG_LONG_MAX; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); - } - } else { - if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { -#if DEBUG_FOCUS - ALOGD("Waiting for application to become ready for input: %s. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), - reason); -#endif - nsecs_t timeout; - if (windowHandle != NULL) { - timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else if (applicationHandle != NULL) { - timeout = applicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT); - } else { - timeout = DEFAULT_INPUT_DISPATCHING_TIMEOUT; - } - - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY; - mInputTargetWaitStartTime = currentTime; - mInputTargetWaitTimeoutTime = currentTime + timeout; - mInputTargetWaitTimeoutExpired = false; - mInputTargetWaitApplicationHandle.clear(); - - if (windowHandle != NULL) { - mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle; - } - if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) { - mInputTargetWaitApplicationHandle = applicationHandle; - } - } - } - - if (mInputTargetWaitTimeoutExpired) { - return INPUT_EVENT_INJECTION_TIMED_OUT; - } - - if (currentTime >= mInputTargetWaitTimeoutTime) { - onANRLocked(currentTime, applicationHandle, windowHandle, - entry->eventTime, mInputTargetWaitStartTime, reason); - - // Force poll loop to wake up immediately on next iteration once we get the - // ANR response back from the policy. - *nextWakeupTime = LONG_LONG_MIN; - return INPUT_EVENT_INJECTION_PENDING; - } else { - // Force poll loop to wake up when timeout is due. - if (mInputTargetWaitTimeoutTime < *nextWakeupTime) { - *nextWakeupTime = mInputTargetWaitTimeoutTime; - } - return INPUT_EVENT_INJECTION_PENDING; - } -} - -void InputDispatcher::resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp& inputChannel) { - if (newTimeout > 0) { - // Extend the timeout. - mInputTargetWaitTimeoutTime = now() + newTimeout; - } else { - // Give up. - mInputTargetWaitTimeoutExpired = true; - - // Input state will not be realistic. Mark it out of sync. - if (inputChannel.get()) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex >= 0) { - sp connection = mConnectionsByFd.valueAt(connectionIndex); - sp windowHandle = connection->inputWindowHandle; - - if (windowHandle != NULL) { - mTouchState.removeWindow(windowHandle); - } - - if (connection->status == Connection::STATUS_NORMAL) { - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, - "application not responding"); - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - } - } - } -} - -nsecs_t InputDispatcher::getTimeSpentWaitingForApplicationLocked( - nsecs_t currentTime) { - if (mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) { - return currentTime - mInputTargetWaitStartTime; - } - return 0; -} - -void InputDispatcher::resetANRTimeoutsLocked() { -#if DEBUG_FOCUS - ALOGD("Resetting ANR timeouts."); -#endif - - // Reset input target wait timeout. - mInputTargetWaitCause = INPUT_TARGET_WAIT_CAUSE_NONE; - mInputTargetWaitApplicationHandle.clear(); -} - -int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime, - const EventEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime) { - int32_t injectionResult; - - // If there is no currently focused window and no focused application - // then drop the event. - if (mFocusedWindowHandle == NULL) { - if (mFocusedApplicationHandle != NULL) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, NULL, nextWakeupTime, - "Waiting because no window has focus but there is a " - "focused application that may eventually add a window " - "when it finishes starting up."); - goto Unresponsive; - } - - ALOGI("Dropping event because there is no focused window or focused application."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check permissions. - if (! checkInjectionPermission(mFocusedWindowHandle, entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - goto Failed; - } - - // If the currently focused window is paused then keep waiting. - if (mFocusedWindowHandle->getInfo()->paused) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, - "Waiting because the focused window is paused."); - goto Unresponsive; - } - - // If the currently focused window is still working on previous events then keep waiting. - if (!isWindowReadyForMoreInputLocked(currentTime, mFocusedWindowHandle, entry)) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, - "Waiting because the focused window has not finished " - "processing the input events that were previously delivered to it."); - goto Unresponsive; - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - addWindowTargetLocked(mFocusedWindowHandle, - InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS, BitSet32(0), - inputTargets); - - // Done. -Failed: -Unresponsive: - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - ALOGD("findFocusedWindow finished: injectionResult=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -int32_t InputDispatcher::findTouchedWindowTargetsLocked(nsecs_t currentTime, - const MotionEntry* entry, Vector& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions) { - enum InjectionPermission { - INJECTION_PERMISSION_UNKNOWN, - INJECTION_PERMISSION_GRANTED, - INJECTION_PERMISSION_DENIED - }; - - // For security reasons, we defer updating the touch state until we are sure that - // event injection will be allowed. - // - // FIXME In the original code, screenWasOff could never be set to true. - // The reason is that the POLICY_FLAG_WOKE_HERE - // and POLICY_FLAG_BRIGHT_HERE flags were set only when preprocessing raw - // EV_KEY, EV_REL and EV_ABS events. As it happens, the touch event was - // actually enqueued using the policyFlags that appeared in the final EV_SYN - // events upon which no preprocessing took place. So policyFlags was always 0. - // In the new native input dispatcher we're a bit more careful about event - // preprocessing so the touches we receive can actually have non-zero policyFlags. - // Unfortunately we obtain undesirable behavior. - // - // Here's what happens: - // - // When the device dims in anticipation of going to sleep, touches - // in windows which have FLAG_TOUCHABLE_WHEN_WAKING cause - // the device to brighten and reset the user activity timer. - // Touches on other windows (such as the launcher window) - // are dropped. Then after a moment, the device goes to sleep. Oops. - // - // Also notice how screenWasOff was being initialized using POLICY_FLAG_BRIGHT_HERE - // instead of POLICY_FLAG_WOKE_HERE... - // - bool screenWasOff = false; // original policy: policyFlags & POLICY_FLAG_BRIGHT_HERE; - - int32_t displayId = entry->displayId; - int32_t action = entry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - - // Update the touch state as needed based on the properties of the touch event. - int32_t injectionResult = INPUT_EVENT_INJECTION_PENDING; - InjectionPermission injectionPermission = INJECTION_PERMISSION_UNKNOWN; - sp newHoverWindowHandle; - - bool isSplit = mTouchState.split; - bool switchedDevice = mTouchState.deviceId >= 0 && mTouchState.displayId >= 0 - && (mTouchState.deviceId != entry->deviceId - || mTouchState.source != entry->source - || mTouchState.displayId != displayId); - bool isHoverAction = (maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - || maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_EXIT); - bool newGesture = (maskedAction == AMOTION_EVENT_ACTION_DOWN - || maskedAction == AMOTION_EVENT_ACTION_SCROLL - || isHoverAction); - bool wrongDevice = false; - if (newGesture) { - bool down = maskedAction == AMOTION_EVENT_ACTION_DOWN; - if (switchedDevice && mTouchState.down && !down) { -#if DEBUG_FOCUS - ALOGD("Dropping event because a pointer for a different device is already down."); -#endif - mTempTouchState.copyFrom(mTouchState); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - switchedDevice = false; - wrongDevice = true; - goto Failed; - } - mTempTouchState.reset(); - mTempTouchState.down = down; - mTempTouchState.deviceId = entry->deviceId; - mTempTouchState.source = entry->source; - mTempTouchState.displayId = displayId; - isSplit = false; - } else { - mTempTouchState.copyFrom(mTouchState); - } - - if (newGesture || (isSplit && maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN)) { - /* Case 1: New splittable pointer going down, or need target for hover or scroll. */ - - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - int32_t x = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[pointerIndex]. - getAxisValue(AMOTION_EVENT_AXIS_Y)); - sp newTouchedWindowHandle; - sp topErrorWindowHandle; - bool isTouchModal = false; - - // Traverse windows from front to back to find touched window and outside targets. - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - if (windowInfo->displayId != displayId) { - continue; // wrong display - } - - int32_t flags = windowInfo->layoutParamsFlags; - if (flags & InputWindowInfo::FLAG_SYSTEM_ERROR) { - if (topErrorWindowHandle == NULL) { - topErrorWindowHandle = windowHandle; - } - } - - if (windowInfo->visible) { - if (! (flags & InputWindowInfo::FLAG_NOT_TOUCHABLE)) { - isTouchModal = (flags & (InputWindowInfo::FLAG_NOT_FOCUSABLE - | InputWindowInfo::FLAG_NOT_TOUCH_MODAL)) == 0; - if (isTouchModal || windowInfo->touchableRegionContainsPoint(x, y)) { - if (! screenWasOff - || (flags & InputWindowInfo::FLAG_TOUCHABLE_WHEN_WAKING)) { - newTouchedWindowHandle = windowHandle; - } - break; // found touched window, exit window loop - } - } - - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && (flags & InputWindowInfo::FLAG_WATCH_OUTSIDE_TOUCH)) { - int32_t outsideTargetFlags = InputTarget::FLAG_DISPATCH_AS_OUTSIDE; - if (isWindowObscuredAtPointLocked(windowHandle, x, y)) { - outsideTargetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - mTempTouchState.addOrUpdateWindow( - windowHandle, outsideTargetFlags, BitSet32(0)); - } - } - } - - // If there is an error window but it is not taking focus (typically because - // it is invisible) then wait for it. Any other focused window may in - // fact be in ANR state. - if (topErrorWindowHandle != NULL && newTouchedWindowHandle != topErrorWindowHandle) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, NULL, nextWakeupTime, - "Waiting because a system error window is about to be displayed."); - injectionPermission = INJECTION_PERMISSION_UNKNOWN; - goto Unresponsive; - } - - // Figure out whether splitting will be allowed for this window. - if (newTouchedWindowHandle != NULL - && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - // New window supports splitting. - isSplit = true; - } else if (isSplit) { - // New window does not support splitting but we have already split events. - // Ignore the new window. - newTouchedWindowHandle = NULL; - } - - // Handle the case where we did not find a window. - if (newTouchedWindowHandle == NULL) { - // Try to assign the pointer to the first foreground window we find, if there is one. - newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle(); - if (newTouchedWindowHandle == NULL) { - // There is no touched window. If this is an initial down event - // then wait for a window to appear that will handle the touch. This is - // to ensure that we report an ANR in the case where an application has started - // but not yet put up a window and the user is starting to get impatient. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN - && mFocusedApplicationHandle != NULL) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - mFocusedApplicationHandle, NULL, nextWakeupTime, - "Waiting because there is no touchable window that can " - "handle the event but there is focused application that may " - "eventually add a new window when it finishes starting up."); - goto Unresponsive; - } - - ALOGI("Dropping event because there is no touched window."); - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - } - - // Set target flags. - int32_t targetFlags = InputTarget::FLAG_FOREGROUND | InputTarget::FLAG_DISPATCH_AS_IS; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - // Update hover state. - if (isHoverAction) { - newHoverWindowHandle = newTouchedWindowHandle; - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - newHoverWindowHandle = mLastHoverWindowHandle; - } - - // Update the temporary touch state. - BitSet32 pointerIds; - if (isSplit) { - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - pointerIds.markBit(pointerId); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); - } else { - /* Case 2: Pointer move, up, cancel or non-splittable pointer down. */ - - // If the pointer is not currently down, then ignore the event. - if (! mTempTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Dropping event because the pointer is not down or we previously " - "dropped the pointer down event."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Check whether touches should slip outside of the current foreground window. - if (maskedAction == AMOTION_EVENT_ACTION_MOVE - && entry->pointerCount == 1 - && mTempTouchState.isSlippery()) { - int32_t x = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_X)); - int32_t y = int32_t(entry->pointerCoords[0].getAxisValue(AMOTION_EVENT_AXIS_Y)); - - sp oldTouchedWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - sp newTouchedWindowHandle = - findTouchedWindowAtLocked(displayId, x, y); - if (oldTouchedWindowHandle != newTouchedWindowHandle - && newTouchedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Touch is slipping out of window %s into window %s.", - oldTouchedWindowHandle->getName().string(), - newTouchedWindowHandle->getName().string()); -#endif - // Make a slippery exit from the old window. - mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT, BitSet32(0)); - - // Make a slippery entrance into the new window. - if (newTouchedWindowHandle->getInfo()->supportsSplitTouch()) { - isSplit = true; - } - - int32_t targetFlags = InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER; - if (isSplit) { - targetFlags |= InputTarget::FLAG_SPLIT; - } - if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) { - targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED; - } - - BitSet32 pointerIds; - if (isSplit) { - pointerIds.markBit(entry->pointerProperties[0].id); - } - mTempTouchState.addOrUpdateWindow(newTouchedWindowHandle, targetFlags, pointerIds); - } - } - } - - if (newHoverWindowHandle != mLastHoverWindowHandle) { - // Let the previous window know that the hover sequence is over. - if (mLastHoverWindowHandle != NULL) { -#if DEBUG_HOVER - ALOGD("Sending hover exit event to window %s.", - mLastHoverWindowHandle->getName().string()); -#endif - mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0)); - } - - // Let the new window know that the hover sequence is starting. - if (newHoverWindowHandle != NULL) { -#if DEBUG_HOVER - ALOGD("Sending hover enter event to window %s.", - newHoverWindowHandle->getName().string()); -#endif - mTempTouchState.addOrUpdateWindow(newHoverWindowHandle, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0)); - } - } - - // Check permission to inject into all touched foreground windows and ensure there - // is at least one touched foreground window. - { - bool haveForegroundWindow = false; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - haveForegroundWindow = true; - if (! checkInjectionPermission(touchedWindow.windowHandle, - entry->injectionState)) { - injectionResult = INPUT_EVENT_INJECTION_PERMISSION_DENIED; - injectionPermission = INJECTION_PERMISSION_DENIED; - goto Failed; - } - } - } - if (! haveForegroundWindow) { -#if DEBUG_FOCUS - ALOGD("Dropping event because there is no touched foreground window to receive it."); -#endif - injectionResult = INPUT_EVENT_INJECTION_FAILED; - goto Failed; - } - - // Permission granted to injection into all touched foreground windows. - injectionPermission = INJECTION_PERMISSION_GRANTED; - } - - // Check whether windows listening for outside touches are owned by the same UID. If it is - // set the policy flag that we will not reveal coordinate information to this window. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - const int32_t foregroundWindowUid = foregroundWindowHandle->getInfo()->ownerUid; - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - sp inputWindowHandle = touchedWindow.windowHandle; - if (inputWindowHandle->getInfo()->ownerUid != foregroundWindowUid) { - mTempTouchState.addOrUpdateWindow(inputWindowHandle, - InputTarget::FLAG_ZERO_COORDS, BitSet32(0)); - } - } - } - } - - // Ensure all touched foreground windows are ready for new input. - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows[i]; - if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) { - // If the touched window is paused then keep waiting. - if (touchedWindow.windowHandle->getInfo()->paused) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, - "Waiting because the touched window is paused."); - goto Unresponsive; - } - - // If the touched window is still working on previous events then keep waiting. - if (!isWindowReadyForMoreInputLocked(currentTime, touchedWindow.windowHandle, entry)) { - injectionResult = handleTargetsNotReadyLocked(currentTime, entry, - NULL, touchedWindow.windowHandle, nextWakeupTime, - "Waiting because the touched window has not finished " - "processing the input events that were previously delivered to it."); - goto Unresponsive; - } - } - } - - // If this is the first pointer going down and the touched window has a wallpaper - // then also add the touched wallpaper windows so they are locked in for the duration - // of the touch gesture. - // We do not collect wallpapers during HOVER_MOVE or SCROLL because the wallpaper - // engine only supports touch events. We would need to add a mechanism similar - // to View.onGenericMotionEvent to enable wallpapers to handle these events. - if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - sp foregroundWindowHandle = - mTempTouchState.getFirstForegroundWindowHandle(); - if (foregroundWindowHandle->getInfo()->hasWallpaper) { - for (size_t i = 0; i < mWindowHandles.size(); i++) { - sp windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* info = windowHandle->getInfo(); - if (info->displayId == displayId - && windowHandle->getInfo()->layoutParamsType - == InputWindowInfo::TYPE_WALLPAPER) { - mTempTouchState.addOrUpdateWindow(windowHandle, - InputTarget::FLAG_WINDOW_IS_OBSCURED - | InputTarget::FLAG_DISPATCH_AS_IS, - BitSet32(0)); - } - } - } - } - - // Success! Output targets. - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - - for (size_t i = 0; i < mTempTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTempTouchState.windows.itemAt(i); - addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags, - touchedWindow.pointerIds, inputTargets); - } - - // Drop the outside or hover touch windows since we will not care about them - // in the next iteration. - mTempTouchState.filterNonAsIsTouchWindows(); - -Failed: - // Check injection permission once and for all. - if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) { - if (checkInjectionPermission(NULL, entry->injectionState)) { - injectionPermission = INJECTION_PERMISSION_GRANTED; - } else { - injectionPermission = INJECTION_PERMISSION_DENIED; - } - } - - // Update final pieces of touch state if the injector had permission. - if (injectionPermission == INJECTION_PERMISSION_GRANTED) { - if (!wrongDevice) { - if (switchedDevice) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Switched to a different device."); -#endif - *outConflictingPointerActions = true; - } - - if (isHoverAction) { - // Started hovering, therefore no longer down. - if (mTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Hover received while pointer was down."); -#endif - *outConflictingPointerActions = true; - } - mTouchState.reset(); - if (maskedAction == AMOTION_EVENT_ACTION_HOVER_ENTER - || maskedAction == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mTouchState.deviceId = entry->deviceId; - mTouchState.source = entry->source; - mTouchState.displayId = displayId; - } - } else if (maskedAction == AMOTION_EVENT_ACTION_UP - || maskedAction == AMOTION_EVENT_ACTION_CANCEL) { - // All pointers up or canceled. - mTouchState.reset(); - } else if (maskedAction == AMOTION_EVENT_ACTION_DOWN) { - // First pointer went down. - if (mTouchState.down) { -#if DEBUG_FOCUS - ALOGD("Conflicting pointer actions: Down received while already down."); -#endif - *outConflictingPointerActions = true; - } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - // One pointer went up. - if (isSplit) { - int32_t pointerIndex = getMotionEventActionPointerIndex(action); - uint32_t pointerId = entry->pointerProperties[pointerIndex].id; - - for (size_t i = 0; i < mTempTouchState.windows.size(); ) { - TouchedWindow& touchedWindow = mTempTouchState.windows.editItemAt(i); - if (touchedWindow.targetFlags & InputTarget::FLAG_SPLIT) { - touchedWindow.pointerIds.clearBit(pointerId); - if (touchedWindow.pointerIds.isEmpty()) { - mTempTouchState.windows.removeAt(i); - continue; - } - } - i += 1; - } - } - mTouchState.copyFrom(mTempTouchState); - } else if (maskedAction == AMOTION_EVENT_ACTION_SCROLL) { - // Discard temporary touch state since it was only valid for this action. - } else { - // Save changes to touch state as-is for all other actions. - mTouchState.copyFrom(mTempTouchState); - } - - // Update hover state. - mLastHoverWindowHandle = newHoverWindowHandle; - } - } else { -#if DEBUG_FOCUS - ALOGD("Not updating touch focus because injection was denied."); -#endif - } - -Unresponsive: - // Reset temporary touch state to ensure we release unnecessary references to input channels. - mTempTouchState.reset(); - - nsecs_t timeSpentWaitingForApplication = getTimeSpentWaitingForApplicationLocked(currentTime); - updateDispatchStatisticsLocked(currentTime, entry, - injectionResult, timeSpentWaitingForApplication); -#if DEBUG_FOCUS - ALOGD("findTouchedWindow finished: injectionResult=%d, injectionPermission=%d, " - "timeSpentWaitingForApplication=%0.1fms", - injectionResult, injectionPermission, timeSpentWaitingForApplication / 1000000.0); -#endif - return injectionResult; -} - -void InputDispatcher::addWindowTargetLocked(const sp& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, Vector& inputTargets) { - inputTargets.push(); - - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - InputTarget& target = inputTargets.editTop(); - target.inputChannel = windowInfo->inputChannel; - target.flags = targetFlags; - target.xOffset = - windowInfo->frameLeft; - target.yOffset = - windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; - target.pointerIds = pointerIds; -} - -void InputDispatcher::addMonitoringTargetsLocked(Vector& inputTargets) { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - inputTargets.push(); - - InputTarget& target = inputTargets.editTop(); - target.inputChannel = mMonitoringChannels[i]; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - target.xOffset = 0; - target.yOffset = 0; - target.pointerIds.clear(); - target.scaleFactor = 1.0f; - } -} - -bool InputDispatcher::checkInjectionPermission(const sp& windowHandle, - const InjectionState* injectionState) { - if (injectionState - && (windowHandle == NULL - || windowHandle->getInfo()->ownerUid != injectionState->injectorUid) - && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) { - if (windowHandle != NULL) { - ALOGW("Permission denied: injecting event from pid %d uid %d to window %s " - "owned by uid %d", - injectionState->injectorPid, injectionState->injectorUid, - windowHandle->getName().string(), - windowHandle->getInfo()->ownerUid); - } else { - ALOGW("Permission denied: injecting event from pid %d uid %d", - injectionState->injectorPid, injectionState->injectorUid); - } - return false; - } - return true; -} - -bool InputDispatcher::isWindowObscuredAtPointLocked( - const sp& windowHandle, int32_t x, int32_t y) const { - int32_t displayId = windowHandle->getInfo()->displayId; - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - sp otherHandle = mWindowHandles.itemAt(i); - if (otherHandle == windowHandle) { - break; - } - - const InputWindowInfo* otherInfo = otherHandle->getInfo(); - if (otherInfo->displayId == displayId - && otherInfo->visible && !otherInfo->isTrustedOverlay() - && otherInfo->frameContainsPoint(x, y)) { - return true; - } - } - return false; -} - -bool InputDispatcher::isWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp& windowHandle, const EventEntry* eventEntry) { - ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel()); - if (connectionIndex >= 0) { - sp connection = mConnectionsByFd.valueAt(connectionIndex); - if (connection->inputPublisherBlocked) { - return false; - } - if (eventEntry->type == EventEntry::TYPE_KEY) { - // If the event is a key event, then we must wait for all previous events to - // complete before delivering it because previous events may have the - // side-effect of transferring focus to a different window and we want to - // ensure that the following keys are sent to the new window. - // - // Suppose the user touches a button in a window then immediately presses "A". - // If the button causes a pop-up window to appear then we want to ensure that - // the "A" key is delivered to the new pop-up window. This is because users - // often anticipate pending UI changes when typing on a keyboard. - // To obtain this behavior, we must serialize key events with respect to all - // prior input events. - return connection->outboundQueue.isEmpty() - && connection->waitQueue.isEmpty(); - } - // Touch events can always be sent to a window immediately because the user intended - // to touch whatever was visible at the time. Even if focus changes or a new - // window appears moments later, the touch event was meant to be delivered to - // whatever window happened to be on screen at the time. - // - // Generic motion events, such as trackball or joystick events are a little trickier. - // Like key events, generic motion events are delivered to the focused window. - // Unlike key events, generic motion events don't tend to transfer focus to other - // windows and it is not important for them to be serialized. So we prefer to deliver - // generic motion events as soon as possible to improve efficiency and reduce lag - // through batching. - // - // The one case where we pause input event delivery is when the wait queue is piling - // up with lots of events because the application is not responding. - // This condition ensures that ANRs are detected reliably. - if (!connection->waitQueue.isEmpty() - && currentTime >= connection->waitQueue.head->eventEntry->eventTime - + STREAM_AHEAD_EVENT_TIMEOUT) { - return false; - } - } - return true; -} - -String8 InputDispatcher::getApplicationWindowLabelLocked( - const sp& applicationHandle, - const sp& windowHandle) { - if (applicationHandle != NULL) { - if (windowHandle != NULL) { - String8 label(applicationHandle->getName()); - label.append(" - "); - label.append(windowHandle->getName()); - return label; - } else { - return applicationHandle->getName(); - } - } else if (windowHandle != NULL) { - return windowHandle->getName(); - } else { - return String8(""); - } -} - -void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) { - if (mFocusedWindowHandle != NULL) { - const InputWindowInfo* info = mFocusedWindowHandle->getInfo(); - if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string()); -#endif - return; - } - } - - int32_t eventType = USER_ACTIVITY_EVENT_OTHER; - switch (eventEntry->type) { - case EventEntry::TYPE_MOTION: { - const MotionEntry* motionEntry = static_cast(eventEntry); - if (motionEntry->action == AMOTION_EVENT_ACTION_CANCEL) { - return; - } - - if (MotionEvent::isTouchEvent(motionEntry->source, motionEntry->action)) { - eventType = USER_ACTIVITY_EVENT_TOUCH; - } - break; - } - case EventEntry::TYPE_KEY: { - const KeyEntry* keyEntry = static_cast(eventEntry); - if (keyEntry->flags & AKEY_EVENT_FLAG_CANCELED) { - return; - } - eventType = USER_ACTIVITY_EVENT_BUTTON; - break; - } - } - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doPokeUserActivityLockedInterruptible); - commandEntry->eventTime = eventEntry->eventTime; - commandEntry->userActivityEventType = eventType; -} - -void InputDispatcher::prepareDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ prepareDispatchCycle - flags=0x%08x, " - "xOffset=%f, yOffset=%f, scaleFactor=%f, " - "pointerIds=0x%x", - connection->getInputChannelName(), inputTarget->flags, - inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor, inputTarget->pointerIds.value); -#endif - - // Skip this event if the connection status is not normal. - // We don't want to enqueue additional outbound events if the connection is broken. - if (connection->status != Connection::STATUS_NORMAL) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Dropping event because the channel status is %s", - connection->getInputChannelName(), connection->getStatusLabel()); -#endif - return; - } - - // Split a motion event if needed. - if (inputTarget->flags & InputTarget::FLAG_SPLIT) { - ALOG_ASSERT(eventEntry->type == EventEntry::TYPE_MOTION); - - MotionEntry* originalMotionEntry = static_cast(eventEntry); - if (inputTarget->pointerIds.count() != originalMotionEntry->pointerCount) { - MotionEntry* splitMotionEntry = splitMotionEvent( - originalMotionEntry, inputTarget->pointerIds); - if (!splitMotionEntry) { - return; // split event was dropped - } -#if DEBUG_FOCUS - ALOGD("channel '%s' ~ Split motion event.", - connection->getInputChannelName()); - logOutboundMotionDetailsLocked(" ", splitMotionEntry); -#endif - enqueueDispatchEntriesLocked(currentTime, connection, - splitMotionEntry, inputTarget); - splitMotionEntry->release(); - return; - } - } - - // Not splitting. Enqueue dispatch entries for the event as is. - enqueueDispatchEntriesLocked(currentTime, connection, eventEntry, inputTarget); -} - -void InputDispatcher::enqueueDispatchEntriesLocked(nsecs_t currentTime, - const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget) { - bool wasEmpty = connection->outboundQueue.isEmpty(); - - // Enqueue dispatch entries for the requested modes. - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_OUTSIDE); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_IS); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT); - enqueueDispatchEntryLocked(connection, eventEntry, inputTarget, - InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER); - - // If the outbound queue was previously empty, start the dispatch cycle going. - if (wasEmpty && !connection->outboundQueue.isEmpty()) { - startDispatchCycleLocked(currentTime, connection); - } -} - -void InputDispatcher::enqueueDispatchEntryLocked( - const sp& connection, EventEntry* eventEntry, const InputTarget* inputTarget, - int32_t dispatchMode) { - int32_t inputTargetFlags = inputTarget->flags; - if (!(inputTargetFlags & dispatchMode)) { - return; - } - inputTargetFlags = (inputTargetFlags & ~InputTarget::FLAG_DISPATCH_MASK) | dispatchMode; - - // This is a new event. - // Enqueue a new dispatch entry onto the outbound queue for this connection. - DispatchEntry* dispatchEntry = new DispatchEntry(eventEntry, // increments ref - inputTargetFlags, inputTarget->xOffset, inputTarget->yOffset, - inputTarget->scaleFactor); - - // Apply target flags and update the connection's input state. - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast(eventEntry); - dispatchEntry->resolvedAction = keyEntry->action; - dispatchEntry->resolvedFlags = keyEntry->flags; - - if (!connection->inputState.trackKey(keyEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent key event", - connection->getInputChannelName()); -#endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast(eventEntry); - if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_OUTSIDE) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_OUTSIDE; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_EXIT; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_CANCEL; - } else if (dispatchMode & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER) { - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_DOWN; - } else { - dispatchEntry->resolvedAction = motionEntry->action; - } - if (dispatchEntry->resolvedAction == AMOTION_EVENT_ACTION_HOVER_MOVE - && !connection->inputState.isHovering( - motionEntry->deviceId, motionEntry->source, motionEntry->displayId)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: filling in missing hover enter event", - connection->getInputChannelName()); -#endif - dispatchEntry->resolvedAction = AMOTION_EVENT_ACTION_HOVER_ENTER; - } - - dispatchEntry->resolvedFlags = motionEntry->flags; - if (dispatchEntry->targetFlags & InputTarget::FLAG_WINDOW_IS_OBSCURED) { - dispatchEntry->resolvedFlags |= AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED; - } - - if (!connection->inputState.trackMotion(motionEntry, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags)) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ enqueueDispatchEntryLocked: skipping inconsistent motion event", - connection->getInputChannelName()); -#endif - delete dispatchEntry; - return; // skip the inconsistent event - } - break; - } - } - - // Remember that we are waiting for this dispatch to complete. - if (dispatchEntry->hasForegroundTarget()) { - incrementPendingForegroundDispatchesLocked(eventEntry); - } - - // Enqueue the dispatch entry. - connection->outboundQueue.enqueueAtTail(dispatchEntry); - traceOutboundQueueLengthLocked(connection); -} - -void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime, - const sp& connection) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ startDispatchCycle", - connection->getInputChannelName()); -#endif - - while (connection->status == Connection::STATUS_NORMAL - && !connection->outboundQueue.isEmpty()) { - DispatchEntry* dispatchEntry = connection->outboundQueue.head; - dispatchEntry->deliveryTime = currentTime; - - // Publish the event. - status_t status; - EventEntry* eventEntry = dispatchEntry->eventEntry; - switch (eventEntry->type) { - case EventEntry::TYPE_KEY: { - KeyEntry* keyEntry = static_cast(eventEntry); - - // Publish the key event. - status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq, - keyEntry->deviceId, keyEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - keyEntry->keyCode, keyEntry->scanCode, - keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime, - keyEntry->eventTime); - break; - } - - case EventEntry::TYPE_MOTION: { - MotionEntry* motionEntry = static_cast(eventEntry); - - PointerCoords scaledCoords[MAX_POINTERS]; - const PointerCoords* usingCoords = motionEntry->pointerCoords; - - // Set the X and Y offset depending on the input source. - float xOffset, yOffset, scaleFactor; - if ((motionEntry->source & AINPUT_SOURCE_CLASS_POINTER) - && !(dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS)) { - scaleFactor = dispatchEntry->scaleFactor; - xOffset = dispatchEntry->xOffset * scaleFactor; - yOffset = dispatchEntry->yOffset * scaleFactor; - if (scaleFactor != 1.0f) { - for (size_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i] = motionEntry->pointerCoords[i]; - scaledCoords[i].scale(scaleFactor); - } - usingCoords = scaledCoords; - } - } else { - xOffset = 0.0f; - yOffset = 0.0f; - scaleFactor = 1.0f; - - // We don't want the dispatch target to know. - if (dispatchEntry->targetFlags & InputTarget::FLAG_ZERO_COORDS) { - for (size_t i = 0; i < motionEntry->pointerCount; i++) { - scaledCoords[i].clear(); - } - usingCoords = scaledCoords; - } - } - - // Publish the motion event. - status = connection->inputPublisher.publishMotionEvent(dispatchEntry->seq, - motionEntry->deviceId, motionEntry->source, - dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags, - motionEntry->edgeFlags, motionEntry->metaState, motionEntry->buttonState, - xOffset, yOffset, - motionEntry->xPrecision, motionEntry->yPrecision, - motionEntry->downTime, motionEntry->eventTime, - motionEntry->pointerCount, motionEntry->pointerProperties, - usingCoords); - break; - } - - default: - ALOG_ASSERT(false); - return; - } - - // Check the result. - if (status) { - if (status == WOULD_BLOCK) { - if (connection->waitQueue.isEmpty()) { - ALOGE("channel '%s' ~ Could not publish event because the pipe is full. " - "This is unexpected because the wait queue is empty, so the pipe " - "should be empty and we shouldn't have any problems writing an " - "event to it, status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - } else { - // Pipe is full and we are waiting for the app to finish process some events - // before sending more events to it. -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ Could not publish event because the pipe is full, " - "waiting for the application to catch up", - connection->getInputChannelName()); -#endif - connection->inputPublisherBlocked = true; - } - } else { - ALOGE("channel '%s' ~ Could not publish event due to an unexpected error, " - "status=%d", connection->getInputChannelName(), status); - abortBrokenDispatchCycleLocked(currentTime, connection, true /*notify*/); - } - return; - } - - // Re-enqueue the event on the wait queue. - connection->outboundQueue.dequeue(dispatchEntry); - traceOutboundQueueLengthLocked(connection); - connection->waitQueue.enqueueAtTail(dispatchEntry); - traceWaitQueueLengthLocked(connection); - } -} - -void InputDispatcher::finishDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, uint32_t seq, bool handled) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ finishDispatchCycle - seq=%u, handled=%s", - connection->getInputChannelName(), seq, toString(handled)); -#endif - - connection->inputPublisherBlocked = false; - - if (connection->status == Connection::STATUS_BROKEN - || connection->status == Connection::STATUS_ZOMBIE) { - return; - } - - // Notify other system components and prepare to start the next dispatch cycle. - onDispatchCycleFinishedLocked(currentTime, connection, seq, handled); -} - -void InputDispatcher::abortBrokenDispatchCycleLocked(nsecs_t currentTime, - const sp& connection, bool notify) { -#if DEBUG_DISPATCH_CYCLE - ALOGD("channel '%s' ~ abortBrokenDispatchCycle - notify=%s", - connection->getInputChannelName(), toString(notify)); -#endif - - // Clear the dispatch queues. - drainDispatchQueueLocked(&connection->outboundQueue); - traceOutboundQueueLengthLocked(connection); - drainDispatchQueueLocked(&connection->waitQueue); - traceWaitQueueLengthLocked(connection); - - // The connection appears to be unrecoverably broken. - // Ignore already broken or zombie connections. - if (connection->status == Connection::STATUS_NORMAL) { - connection->status = Connection::STATUS_BROKEN; - - if (notify) { - // Notify other system components. - onDispatchCycleBrokenLocked(currentTime, connection); - } - } -} - -void InputDispatcher::drainDispatchQueueLocked(Queue* queue) { - while (!queue->isEmpty()) { - DispatchEntry* dispatchEntry = queue->dequeueAtHead(); - releaseDispatchEntryLocked(dispatchEntry); - } -} - -void InputDispatcher::releaseDispatchEntryLocked(DispatchEntry* dispatchEntry) { - if (dispatchEntry->hasForegroundTarget()) { - decrementPendingForegroundDispatchesLocked(dispatchEntry->eventEntry); - } - delete dispatchEntry; -} - -int InputDispatcher::handleReceiveCallback(int fd, int events, void* data) { - InputDispatcher* d = static_cast(data); - - { // acquire lock - AutoMutex _l(d->mLock); - - ssize_t connectionIndex = d->mConnectionsByFd.indexOfKey(fd); - if (connectionIndex < 0) { - ALOGE("Received spurious receive callback for unknown input channel. " - "fd=%d, events=0x%x", fd, events); - return 0; // remove the callback - } - - bool notify; - sp connection = d->mConnectionsByFd.valueAt(connectionIndex); - if (!(events & (ALOOPER_EVENT_ERROR | ALOOPER_EVENT_HANGUP))) { - if (!(events & ALOOPER_EVENT_INPUT)) { - ALOGW("channel '%s' ~ Received spurious callback for unhandled poll event. " - "events=0x%x", connection->getInputChannelName(), events); - return 1; - } - - nsecs_t currentTime = now(); - bool gotOne = false; - status_t status; - for (;;) { - uint32_t seq; - bool handled; - status = connection->inputPublisher.receiveFinishedSignal(&seq, &handled); - if (status) { - break; - } - d->finishDispatchCycleLocked(currentTime, connection, seq, handled); - gotOne = true; - } - if (gotOne) { - d->runCommandsLockedInterruptible(); - if (status == WOULD_BLOCK) { - return 1; - } - } - - notify = status != DEAD_OBJECT || !connection->monitor; - if (notify) { - ALOGE("channel '%s' ~ Failed to receive finished signal. status=%d", - connection->getInputChannelName(), status); - } - } else { - // Monitor channels are never explicitly unregistered. - // We do it automatically when the remote endpoint is closed so don't warn - // about them. - notify = !connection->monitor; - if (notify) { - ALOGW("channel '%s' ~ Consumer closed input channel or an error occurred. " - "events=0x%x", connection->getInputChannelName(), events); - } - } - - // Unregister the channel. - d->unregisterInputChannelLocked(connection->inputChannel, notify); - return 0; // remove the callback - } // release lock -} - -void InputDispatcher::synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options) { - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(i), options); - } -} - -void InputDispatcher::synthesizeCancelationEventsForInputChannelLocked( - const sp& channel, const CancelationOptions& options) { - ssize_t index = getConnectionIndexLocked(channel); - if (index >= 0) { - synthesizeCancelationEventsForConnectionLocked( - mConnectionsByFd.valueAt(index), options); - } -} - -void InputDispatcher::synthesizeCancelationEventsForConnectionLocked( - const sp& connection, const CancelationOptions& options) { - if (connection->status == Connection::STATUS_BROKEN) { - return; - } - - nsecs_t currentTime = now(); - - Vector cancelationEvents; - connection->inputState.synthesizeCancelationEvents(currentTime, - cancelationEvents, options); - - if (!cancelationEvents.isEmpty()) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("channel '%s' ~ Synthesized %d cancelation events to bring channel back in sync " - "with reality: %s, mode=%d.", - connection->getInputChannelName(), cancelationEvents.size(), - options.reason, options.mode); -#endif - for (size_t i = 0; i < cancelationEvents.size(); i++) { - EventEntry* cancelationEventEntry = cancelationEvents.itemAt(i); - switch (cancelationEventEntry->type) { - case EventEntry::TYPE_KEY: - logOutboundKeyDetailsLocked("cancel - ", - static_cast(cancelationEventEntry)); - break; - case EventEntry::TYPE_MOTION: - logOutboundMotionDetailsLocked("cancel - ", - static_cast(cancelationEventEntry)); - break; - } - - InputTarget target; - sp windowHandle = getWindowHandleLocked(connection->inputChannel); - if (windowHandle != NULL) { - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - target.xOffset = -windowInfo->frameLeft; - target.yOffset = -windowInfo->frameTop; - target.scaleFactor = windowInfo->scaleFactor; - } else { - target.xOffset = 0; - target.yOffset = 0; - target.scaleFactor = 1.0f; - } - target.inputChannel = connection->inputChannel; - target.flags = InputTarget::FLAG_DISPATCH_AS_IS; - - enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref - &target, InputTarget::FLAG_DISPATCH_AS_IS); - - cancelationEventEntry->release(); - } - - startDispatchCycleLocked(currentTime, connection); - } -} - -InputDispatcher::MotionEntry* -InputDispatcher::splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds) { - ALOG_ASSERT(pointerIds.value != 0); - - PointerProperties splitPointerProperties[MAX_POINTERS]; - PointerCoords splitPointerCoords[MAX_POINTERS]; - - uint32_t originalPointerCount = originalMotionEntry->pointerCount; - uint32_t splitPointerCount = 0; - - for (uint32_t originalPointerIndex = 0; originalPointerIndex < originalPointerCount; - originalPointerIndex++) { - const PointerProperties& pointerProperties = - originalMotionEntry->pointerProperties[originalPointerIndex]; - uint32_t pointerId = uint32_t(pointerProperties.id); - if (pointerIds.hasBit(pointerId)) { - splitPointerProperties[splitPointerCount].copyFrom(pointerProperties); - splitPointerCoords[splitPointerCount].copyFrom( - originalMotionEntry->pointerCoords[originalPointerIndex]); - splitPointerCount += 1; - } - } - - if (splitPointerCount != pointerIds.count()) { - // This is bad. We are missing some of the pointers that we expected to deliver. - // Most likely this indicates that we received an ACTION_MOVE events that has - // different pointer ids than we expected based on the previous ACTION_DOWN - // or ACTION_POINTER_DOWN events that caused us to decide to split the pointers - // in this way. - ALOGW("Dropping split motion event because the pointer count is %d but " - "we expected there to be %d pointers. This probably means we received " - "a broken sequence of pointer ids from the input device.", - splitPointerCount, pointerIds.count()); - return NULL; - } - - int32_t action = originalMotionEntry->action; - int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK; - if (maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - || maskedAction == AMOTION_EVENT_ACTION_POINTER_UP) { - int32_t originalPointerIndex = getMotionEventActionPointerIndex(action); - const PointerProperties& pointerProperties = - originalMotionEntry->pointerProperties[originalPointerIndex]; - uint32_t pointerId = uint32_t(pointerProperties.id); - if (pointerIds.hasBit(pointerId)) { - if (pointerIds.count() == 1) { - // The first/last pointer went down/up. - action = maskedAction == AMOTION_EVENT_ACTION_POINTER_DOWN - ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else { - // A secondary pointer went down/up. - uint32_t splitPointerIndex = 0; - while (pointerId != uint32_t(splitPointerProperties[splitPointerIndex].id)) { - splitPointerIndex += 1; - } - action = maskedAction | (splitPointerIndex - << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT); - } - } else { - // An unrelated pointer changed. - action = AMOTION_EVENT_ACTION_MOVE; - } - } - - MotionEntry* splitMotionEntry = new MotionEntry( - originalMotionEntry->eventTime, - originalMotionEntry->deviceId, - originalMotionEntry->source, - originalMotionEntry->policyFlags, - action, - originalMotionEntry->flags, - originalMotionEntry->metaState, - originalMotionEntry->buttonState, - originalMotionEntry->edgeFlags, - originalMotionEntry->xPrecision, - originalMotionEntry->yPrecision, - originalMotionEntry->downTime, - originalMotionEntry->displayId, - splitPointerCount, splitPointerProperties, splitPointerCoords); - - if (originalMotionEntry->injectionState) { - splitMotionEntry->injectionState = originalMotionEntry->injectionState; - splitMotionEntry->injectionState->refCount += 1; - } - - return splitMotionEntry; -} - -void InputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyConfigurationChanged - eventTime=%lld", args->eventTime); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - ConfigurationChangedEntry* newEntry = new ConfigurationChangedEntry(args->eventTime); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -void InputDispatcher::notifyKey(const NotifyKeyArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyKey - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, " - "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%lld", - args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->keyCode, args->scanCode, - args->metaState, args->downTime); -#endif - if (!validateKeyEvent(args->action)) { - return; - } - - uint32_t policyFlags = args->policyFlags; - int32_t flags = args->flags; - int32_t metaState = args->metaState; - if ((policyFlags & POLICY_FLAG_VIRTUAL) || (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY)) { - policyFlags |= POLICY_FLAG_VIRTUAL; - flags |= AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY; - } - if (policyFlags & POLICY_FLAG_ALT) { - metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON; - } - if (policyFlags & POLICY_FLAG_ALT_GR) { - metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON; - } - if (policyFlags & POLICY_FLAG_SHIFT) { - metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON; - } - if (policyFlags & POLICY_FLAG_CAPS_LOCK) { - metaState |= AMETA_CAPS_LOCK_ON; - } - if (policyFlags & POLICY_FLAG_FUNCTION) { - metaState |= AMETA_FUNCTION_ON; - } - - policyFlags |= POLICY_FLAG_TRUSTED; - - KeyEvent event; - event.initialize(args->deviceId, args->source, args->action, - flags, args->keyCode, args->scanCode, metaState, 0, - args->downTime, args->eventTime); - - mPolicy->interceptKeyBeforeQueueing(&event, /*byref*/ policyFlags); - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - bool needWake; - { // acquire lock - mLock.lock(); - - if (shouldSendKeyToInputFilterLocked(args)) { - mLock.unlock(); - - policyFlags |= POLICY_FLAG_FILTERED; - if (!mPolicy->filterInputEvent(&event, policyFlags)) { - return; // event was consumed by the filter - } - - mLock.lock(); - } - - int32_t repeatCount = 0; - KeyEntry* newEntry = new KeyEntry(args->eventTime, - args->deviceId, args->source, policyFlags, - args->action, flags, args->keyCode, args->scanCode, - metaState, repeatCount, args->downTime); - - needWake = enqueueInboundEventLocked(newEntry); - mLock.unlock(); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -bool InputDispatcher::shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args) { - return mInputFilterEnabled; -} - -void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyMotion - eventTime=%lld, deviceId=%d, source=0x%x, policyFlags=0x%x, " - "action=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x, edgeFlags=0x%x, " - "xPrecision=%f, yPrecision=%f, downTime=%lld", - args->eventTime, args->deviceId, args->source, args->policyFlags, - args->action, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime); - for (uint32_t i = 0; i < args->pointerCount; i++) { - ALOGD(" Pointer %d: id=%d, toolType=%d, " - "x=%f, y=%f, pressure=%f, size=%f, " - "touchMajor=%f, touchMinor=%f, toolMajor=%f, toolMinor=%f, " - "orientation=%f", - i, args->pointerProperties[i].id, - args->pointerProperties[i].toolType, - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - args->pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION)); - } -#endif - if (!validateMotionEvent(args->action, args->pointerCount, args->pointerProperties)) { - return; - } - - uint32_t policyFlags = args->policyFlags; - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->interceptMotionBeforeQueueing(args->eventTime, /*byref*/ policyFlags); - - bool needWake; - { // acquire lock - mLock.lock(); - - if (shouldSendMotionToInputFilterLocked(args)) { - mLock.unlock(); - - MotionEvent event; - event.initialize(args->deviceId, args->source, args->action, args->flags, - args->edgeFlags, args->metaState, args->buttonState, 0, 0, - args->xPrecision, args->yPrecision, - args->downTime, args->eventTime, - args->pointerCount, args->pointerProperties, args->pointerCoords); - - policyFlags |= POLICY_FLAG_FILTERED; - if (!mPolicy->filterInputEvent(&event, policyFlags)) { - return; // event was consumed by the filter - } - - mLock.lock(); - } - - // Just enqueue a new motion event. - MotionEntry* newEntry = new MotionEntry(args->eventTime, - args->deviceId, args->source, policyFlags, - args->action, args->flags, args->metaState, args->buttonState, - args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime, - args->displayId, - args->pointerCount, args->pointerProperties, args->pointerCoords); - - needWake = enqueueInboundEventLocked(newEntry); - mLock.unlock(); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -bool InputDispatcher::shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args) { - // TODO: support sending secondary display events to input filter - return mInputFilterEnabled && isMainDisplay(args->displayId); -} - -void InputDispatcher::notifySwitch(const NotifySwitchArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifySwitch - eventTime=%lld, policyFlags=0x%x, switchValues=0x%08x, switchMask=0x%08x", - args->eventTime, args->policyFlags, - args->switchValues, args->switchMask); -#endif - - uint32_t policyFlags = args->policyFlags; - policyFlags |= POLICY_FLAG_TRUSTED; - mPolicy->notifySwitch(args->eventTime, - args->switchValues, args->switchMask, policyFlags); -} - -void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("notifyDeviceReset - eventTime=%lld, deviceId=%d", - args->eventTime, args->deviceId); -#endif - - bool needWake; - { // acquire lock - AutoMutex _l(mLock); - - DeviceResetEntry* newEntry = new DeviceResetEntry(args->eventTime, args->deviceId); - needWake = enqueueInboundEventLocked(newEntry); - } // release lock - - if (needWake) { - mLooper->wake(); - } -} - -int32_t InputDispatcher::injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) { -#if DEBUG_INBOUND_EVENT_DETAILS - ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, " - "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x", - event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags); -#endif - - nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis); - - policyFlags |= POLICY_FLAG_INJECTED; - if (hasInjectionPermission(injectorPid, injectorUid)) { - policyFlags |= POLICY_FLAG_TRUSTED; - } - - EventEntry* firstInjectedEntry; - EventEntry* lastInjectedEntry; - switch (event->getType()) { - case AINPUT_EVENT_TYPE_KEY: { - const KeyEvent* keyEvent = static_cast(event); - int32_t action = keyEvent->getAction(); - if (! validateKeyEvent(action)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - int32_t flags = keyEvent->getFlags(); - if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) { - policyFlags |= POLICY_FLAG_VIRTUAL; - } - - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags); - } - - if (policyFlags & POLICY_FLAG_WOKE_HERE) { - flags |= AKEY_EVENT_FLAG_WOKE_HERE; - } - - mLock.lock(); - firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(), - keyEvent->getDeviceId(), keyEvent->getSource(), - policyFlags, action, flags, - keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(), - keyEvent->getRepeatCount(), keyEvent->getDownTime()); - lastInjectedEntry = firstInjectedEntry; - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - const MotionEvent* motionEvent = static_cast(event); - int32_t displayId = ADISPLAY_ID_DEFAULT; - int32_t action = motionEvent->getAction(); - size_t pointerCount = motionEvent->getPointerCount(); - const PointerProperties* pointerProperties = motionEvent->getPointerProperties(); - if (! validateMotionEvent(action, pointerCount, pointerProperties)) { - return INPUT_EVENT_INJECTION_FAILED; - } - - if (!(policyFlags & POLICY_FLAG_FILTERED)) { - nsecs_t eventTime = motionEvent->getEventTime(); - mPolicy->interceptMotionBeforeQueueing(eventTime, /*byref*/ policyFlags); - } - - mLock.lock(); - const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes(); - const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords(); - firstInjectedEntry = new MotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); - lastInjectedEntry = firstInjectedEntry; - for (size_t i = motionEvent->getHistorySize(); i > 0; i--) { - sampleEventTimes += 1; - samplePointerCoords += pointerCount; - MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes, - motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags, - action, motionEvent->getFlags(), - motionEvent->getMetaState(), motionEvent->getButtonState(), - motionEvent->getEdgeFlags(), - motionEvent->getXPrecision(), motionEvent->getYPrecision(), - motionEvent->getDownTime(), displayId, - uint32_t(pointerCount), pointerProperties, samplePointerCoords); - lastInjectedEntry->next = nextInjectedEntry; - lastInjectedEntry = nextInjectedEntry; - } - break; - } - - default: - ALOGW("Cannot inject event of type %d", event->getType()); - return INPUT_EVENT_INJECTION_FAILED; - } - - InjectionState* injectionState = new InjectionState(injectorPid, injectorUid); - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionState->injectionIsAsync = true; - } - - injectionState->refCount += 1; - lastInjectedEntry->injectionState = injectionState; - - bool needWake = false; - for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) { - EventEntry* nextEntry = entry->next; - needWake |= enqueueInboundEventLocked(entry); - entry = nextEntry; - } - - mLock.unlock(); - - if (needWake) { - mLooper->wake(); - } - - int32_t injectionResult; - { // acquire lock - AutoMutex _l(mLock); - - if (syncMode == INPUT_EVENT_INJECTION_SYNC_NONE) { - injectionResult = INPUT_EVENT_INJECTION_SUCCEEDED; - } else { - for (;;) { - injectionResult = injectionState->injectionResult; - if (injectionResult != INPUT_EVENT_INJECTION_PENDING) { - break; - } - - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for injection result " - "to become available."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionResultAvailableCondition.waitRelative(mLock, remainingTimeout); - } - - if (injectionResult == INPUT_EVENT_INJECTION_SUCCEEDED - && syncMode == INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED) { - while (injectionState->pendingForegroundDispatches != 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Waiting for %d pending foreground dispatches.", - injectionState->pendingForegroundDispatches); -#endif - nsecs_t remainingTimeout = endTime - now(); - if (remainingTimeout <= 0) { -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Timed out waiting for pending foreground " - "dispatches to finish."); -#endif - injectionResult = INPUT_EVENT_INJECTION_TIMED_OUT; - break; - } - - mInjectionSyncFinishedCondition.waitRelative(mLock, remainingTimeout); - } - } - } - - injectionState->release(); - } // release lock - -#if DEBUG_INJECTION - ALOGD("injectInputEvent - Finished with result %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectorPid, injectorUid); -#endif - - return injectionResult; -} - -bool InputDispatcher::hasInjectionPermission(int32_t injectorPid, int32_t injectorUid) { - return injectorUid == 0 - || mPolicy->checkInjectEventsPermissionNonReentrant(injectorPid, injectorUid); -} - -void InputDispatcher::setInjectionResultLocked(EventEntry* entry, int32_t injectionResult) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { -#if DEBUG_INJECTION - ALOGD("Setting input event injection result to %d. " - "injectorPid=%d, injectorUid=%d", - injectionResult, injectionState->injectorPid, injectionState->injectorUid); -#endif - - if (injectionState->injectionIsAsync - && !(entry->policyFlags & POLICY_FLAG_FILTERED)) { - // Log the outcome since the injector did not wait for the injection result. - switch (injectionResult) { - case INPUT_EVENT_INJECTION_SUCCEEDED: - ALOGV("Asynchronous input event injection succeeded."); - break; - case INPUT_EVENT_INJECTION_FAILED: - ALOGW("Asynchronous input event injection failed."); - break; - case INPUT_EVENT_INJECTION_PERMISSION_DENIED: - ALOGW("Asynchronous input event injection permission denied."); - break; - case INPUT_EVENT_INJECTION_TIMED_OUT: - ALOGW("Asynchronous input event injection timed out."); - break; - } - } - - injectionState->injectionResult = injectionResult; - mInjectionResultAvailableCondition.broadcast(); - } -} - -void InputDispatcher::incrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches += 1; - } -} - -void InputDispatcher::decrementPendingForegroundDispatchesLocked(EventEntry* entry) { - InjectionState* injectionState = entry->injectionState; - if (injectionState) { - injectionState->pendingForegroundDispatches -= 1; - - if (injectionState->pendingForegroundDispatches == 0) { - mInjectionSyncFinishedCondition.broadcast(); - } - } -} - -sp InputDispatcher::getWindowHandleLocked( - const sp& inputChannel) const { - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - const sp& windowHandle = mWindowHandles.itemAt(i); - if (windowHandle->getInputChannel() == inputChannel) { - return windowHandle; - } - } - return NULL; -} - -bool InputDispatcher::hasWindowHandleLocked( - const sp& windowHandle) const { - size_t numWindows = mWindowHandles.size(); - for (size_t i = 0; i < numWindows; i++) { - if (mWindowHandles.itemAt(i) == windowHandle) { - return true; - } - } - return false; -} - -void InputDispatcher::setInputWindows(const Vector >& inputWindowHandles) { -#if DEBUG_FOCUS - ALOGD("setInputWindows"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - Vector > oldWindowHandles = mWindowHandles; - mWindowHandles = inputWindowHandles; - - sp newFocusedWindowHandle; - bool foundHoveredWindow = false; - for (size_t i = 0; i < mWindowHandles.size(); i++) { - const sp& windowHandle = mWindowHandles.itemAt(i); - if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) { - mWindowHandles.removeAt(i--); - continue; - } - if (windowHandle->getInfo()->hasFocus) { - newFocusedWindowHandle = windowHandle; - } - if (windowHandle == mLastHoverWindowHandle) { - foundHoveredWindow = true; - } - } - - if (!foundHoveredWindow) { - mLastHoverWindowHandle = NULL; - } - - if (mFocusedWindowHandle != newFocusedWindowHandle) { - if (mFocusedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Focus left window: %s", - mFocusedWindowHandle->getName().string()); -#endif - sp focusedInputChannel = mFocusedWindowHandle->getInputChannel(); - if (focusedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS, - "focus left window"); - synthesizeCancelationEventsForInputChannelLocked( - focusedInputChannel, options); - } - } - if (newFocusedWindowHandle != NULL) { -#if DEBUG_FOCUS - ALOGD("Focus entered window: %s", - newFocusedWindowHandle->getName().string()); -#endif - } - mFocusedWindowHandle = newFocusedWindowHandle; - } - - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - TouchedWindow& touchedWindow = mTouchState.windows.editItemAt(i); - if (!hasWindowHandleLocked(touchedWindow.windowHandle)) { -#if DEBUG_FOCUS - ALOGD("Touched window was removed: %s", - touchedWindow.windowHandle->getName().string()); -#endif - sp touchedInputChannel = - touchedWindow.windowHandle->getInputChannel(); - if (touchedInputChannel != NULL) { - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "touched window was removed"); - synthesizeCancelationEventsForInputChannelLocked( - touchedInputChannel, options); - } - mTouchState.windows.removeAt(i--); - } - } - - // Release information for windows that are no longer present. - // This ensures that unused input channels are released promptly. - // Otherwise, they might stick around until the window handle is destroyed - // which might not happen until the next GC. - for (size_t i = 0; i < oldWindowHandles.size(); i++) { - const sp& oldWindowHandle = oldWindowHandles.itemAt(i); - if (!hasWindowHandleLocked(oldWindowHandle)) { -#if DEBUG_FOCUS - ALOGD("Window went away: %s", oldWindowHandle->getName().string()); -#endif - oldWindowHandle->releaseInfo(); - } - } - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setFocusedApplication( - const sp& inputApplicationHandle) { -#if DEBUG_FOCUS - ALOGD("setFocusedApplication"); -#endif - { // acquire lock - AutoMutex _l(mLock); - - if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) { - if (mFocusedApplicationHandle != inputApplicationHandle) { - if (mFocusedApplicationHandle != NULL) { - resetANRTimeoutsLocked(); - mFocusedApplicationHandle->releaseInfo(); - } - mFocusedApplicationHandle = inputApplicationHandle; - } - } else if (mFocusedApplicationHandle != NULL) { - resetANRTimeoutsLocked(); - mFocusedApplicationHandle->releaseInfo(); - mFocusedApplicationHandle.clear(); - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); -} - -void InputDispatcher::setInputDispatchMode(bool enabled, bool frozen) { -#if DEBUG_FOCUS - ALOGD("setInputDispatchMode: enabled=%d, frozen=%d", enabled, frozen); -#endif - - bool changed; - { // acquire lock - AutoMutex _l(mLock); - - if (mDispatchEnabled != enabled || mDispatchFrozen != frozen) { - if (mDispatchFrozen && !frozen) { - resetANRTimeoutsLocked(); - } - - if (mDispatchEnabled && !enabled) { - resetAndDropEverythingLocked("dispatcher is being disabled"); - } - - mDispatchEnabled = enabled; - mDispatchFrozen = frozen; - changed = true; - } else { - changed = false; - } - -#if DEBUG_FOCUS - //logDispatchStateLocked(); -#endif - } // release lock - - if (changed) { - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - } -} - -void InputDispatcher::setInputFilterEnabled(bool enabled) { -#if DEBUG_FOCUS - ALOGD("setInputFilterEnabled: enabled=%d", enabled); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (mInputFilterEnabled == enabled) { - return; - } - - mInputFilterEnabled = enabled; - resetAndDropEverythingLocked("input filter is being enabled or disabled"); - } // release lock - - // Wake up poll loop since there might be work to do to drop everything. - mLooper->wake(); -} - -bool InputDispatcher::transferTouchFocus(const sp& fromChannel, - const sp& toChannel) { -#if DEBUG_FOCUS - ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s", - fromChannel->getName().string(), toChannel->getName().string()); -#endif - { // acquire lock - AutoMutex _l(mLock); - - sp fromWindowHandle = getWindowHandleLocked(fromChannel); - sp toWindowHandle = getWindowHandleLocked(toChannel); - if (fromWindowHandle == NULL || toWindowHandle == NULL) { -#if DEBUG_FOCUS - ALOGD("Cannot transfer focus because from or to window not found."); -#endif - return false; - } - if (fromWindowHandle == toWindowHandle) { -#if DEBUG_FOCUS - ALOGD("Trivial transfer to same window."); -#endif - return true; - } - if (fromWindowHandle->getInfo()->displayId != toWindowHandle->getInfo()->displayId) { -#if DEBUG_FOCUS - ALOGD("Cannot transfer focus because windows are on different displays."); -#endif - return false; - } - - bool found = false; - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - if (touchedWindow.windowHandle == fromWindowHandle) { - int32_t oldTargetFlags = touchedWindow.targetFlags; - BitSet32 pointerIds = touchedWindow.pointerIds; - - mTouchState.windows.removeAt(i); - - int32_t newTargetFlags = oldTargetFlags - & (InputTarget::FLAG_FOREGROUND - | InputTarget::FLAG_SPLIT | InputTarget::FLAG_DISPATCH_AS_IS); - mTouchState.addOrUpdateWindow(toWindowHandle, newTargetFlags, pointerIds); - - found = true; - break; - } - } - - if (! found) { -#if DEBUG_FOCUS - ALOGD("Focus transfer failed because from window did not have focus."); -#endif - return false; - } - - ssize_t fromConnectionIndex = getConnectionIndexLocked(fromChannel); - ssize_t toConnectionIndex = getConnectionIndexLocked(toChannel); - if (fromConnectionIndex >= 0 && toConnectionIndex >= 0) { - sp fromConnection = mConnectionsByFd.valueAt(fromConnectionIndex); - sp toConnection = mConnectionsByFd.valueAt(toConnectionIndex); - - fromConnection->inputState.copyPointerStateTo(toConnection->inputState); - CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS, - "transferring touch focus from this window to another window"); - synthesizeCancelationEventsForConnectionLocked(fromConnection, options); - } - -#if DEBUG_FOCUS - logDispatchStateLocked(); -#endif - } // release lock - - // Wake up poll loop since it may need to make new input dispatching choices. - mLooper->wake(); - return true; -} - -void InputDispatcher::resetAndDropEverythingLocked(const char* reason) { -#if DEBUG_FOCUS - ALOGD("Resetting and dropping all events (%s).", reason); -#endif - - CancelationOptions options(CancelationOptions::CANCEL_ALL_EVENTS, reason); - synthesizeCancelationEventsForAllConnectionsLocked(options); - - resetKeyRepeatLocked(); - releasePendingEventLocked(); - drainInboundQueueLocked(); - resetANRTimeoutsLocked(); - - mTouchState.reset(); - mLastHoverWindowHandle.clear(); -} - -void InputDispatcher::logDispatchStateLocked() { - String8 dump; - dumpDispatchStateLocked(dump); - - char* text = dump.lockBuffer(dump.size()); - char* start = text; - while (*start != '\0') { - char* end = strchr(start, '\n'); - if (*end == '\n') { - *(end++) = '\0'; - } - ALOGD("%s", start); - start = end; - } -} - -void InputDispatcher::dumpDispatchStateLocked(String8& dump) { - dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled); - dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen); - - if (mFocusedApplicationHandle != NULL) { - dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n", - mFocusedApplicationHandle->getName().string(), - mFocusedApplicationHandle->getDispatchingTimeout( - DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0); - } else { - dump.append(INDENT "FocusedApplication: \n"); - } - dump.appendFormat(INDENT "FocusedWindow: name='%s'\n", - mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : ""); - - dump.appendFormat(INDENT "TouchDown: %s\n", toString(mTouchState.down)); - dump.appendFormat(INDENT "TouchSplit: %s\n", toString(mTouchState.split)); - dump.appendFormat(INDENT "TouchDeviceId: %d\n", mTouchState.deviceId); - dump.appendFormat(INDENT "TouchSource: 0x%08x\n", mTouchState.source); - dump.appendFormat(INDENT "TouchDisplayId: %d\n", mTouchState.displayId); - if (!mTouchState.windows.isEmpty()) { - dump.append(INDENT "TouchedWindows:\n"); - for (size_t i = 0; i < mTouchState.windows.size(); i++) { - const TouchedWindow& touchedWindow = mTouchState.windows[i]; - dump.appendFormat(INDENT2 "%d: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n", - i, touchedWindow.windowHandle->getName().string(), - touchedWindow.pointerIds.value, - touchedWindow.targetFlags); - } - } else { - dump.append(INDENT "TouchedWindows: \n"); - } - - if (!mWindowHandles.isEmpty()) { - dump.append(INDENT "Windows:\n"); - for (size_t i = 0; i < mWindowHandles.size(); i++) { - const sp& windowHandle = mWindowHandles.itemAt(i); - const InputWindowInfo* windowInfo = windowHandle->getInfo(); - - dump.appendFormat(INDENT2 "%d: name='%s', displayId=%d, " - "paused=%s, hasFocus=%s, hasWallpaper=%s, " - "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, " - "frame=[%d,%d][%d,%d], scale=%f, " - "touchableRegion=", - i, windowInfo->name.string(), windowInfo->displayId, - toString(windowInfo->paused), - toString(windowInfo->hasFocus), - toString(windowInfo->hasWallpaper), - toString(windowInfo->visible), - toString(windowInfo->canReceiveKeys), - windowInfo->layoutParamsFlags, windowInfo->layoutParamsType, - windowInfo->layer, - windowInfo->frameLeft, windowInfo->frameTop, - windowInfo->frameRight, windowInfo->frameBottom, - windowInfo->scaleFactor); - dumpRegion(dump, windowInfo->touchableRegion); - dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures); - dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n", - windowInfo->ownerPid, windowInfo->ownerUid, - windowInfo->dispatchingTimeout / 1000000.0); - } - } else { - dump.append(INDENT "Windows: \n"); - } - - if (!mMonitoringChannels.isEmpty()) { - dump.append(INDENT "MonitoringChannels:\n"); - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - const sp& channel = mMonitoringChannels[i]; - dump.appendFormat(INDENT2 "%d: '%s'\n", i, channel->getName().string()); - } - } else { - dump.append(INDENT "MonitoringChannels: \n"); - } - - nsecs_t currentTime = now(); - - if (!mInboundQueue.isEmpty()) { - dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count()); - for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) { - dump.append(INDENT2); - entry->appendDescription(dump); - dump.appendFormat(", age=%0.1fms\n", - (currentTime - entry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT "InboundQueue: \n"); - } - - if (!mConnectionsByFd.isEmpty()) { - dump.append(INDENT "Connections:\n"); - for (size_t i = 0; i < mConnectionsByFd.size(); i++) { - const sp& connection = mConnectionsByFd.valueAt(i); - dump.appendFormat(INDENT2 "%d: channelName='%s', windowName='%s', " - "status=%s, monitor=%s, inputPublisherBlocked=%s\n", - i, connection->getInputChannelName(), connection->getWindowName(), - connection->getStatusLabel(), toString(connection->monitor), - toString(connection->inputPublisherBlocked)); - - if (!connection->outboundQueue.isEmpty()) { - dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n", - connection->outboundQueue.count()); - for (DispatchEntry* entry = connection->outboundQueue.head; entry; - entry = entry->next) { - dump.append(INDENT4); - entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f); - } - } else { - dump.append(INDENT3 "OutboundQueue: \n"); - } - - if (!connection->waitQueue.isEmpty()) { - dump.appendFormat(INDENT3 "WaitQueue: length=%u\n", - connection->waitQueue.count()); - for (DispatchEntry* entry = connection->waitQueue.head; entry; - entry = entry->next) { - dump.append(INDENT4); - entry->eventEntry->appendDescription(dump); - dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, " - "age=%0.1fms, wait=%0.1fms\n", - entry->targetFlags, entry->resolvedAction, - (currentTime - entry->eventEntry->eventTime) * 0.000001f, - (currentTime - entry->deliveryTime) * 0.000001f); - } - } else { - dump.append(INDENT3 "WaitQueue: \n"); - } - } - } else { - dump.append(INDENT "Connections: \n"); - } - - if (isAppSwitchPendingLocked()) { - dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n", - (mAppSwitchDueTime - now()) / 1000000.0); - } else { - dump.append(INDENT "AppSwitch: not pending\n"); - } - - dump.append(INDENT "Configuration:\n"); - dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n", - mConfig.keyRepeatDelay * 0.000001f); - dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n", - mConfig.keyRepeatTimeout * 0.000001f); -} - -status_t InputDispatcher::registerInputChannel(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor) { -#if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(), - toString(monitor)); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - if (getConnectionIndexLocked(inputChannel) >= 0) { - ALOGW("Attempted to register already registered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp connection = new Connection(inputChannel, inputWindowHandle, monitor); - - int fd = inputChannel->getFd(); - mConnectionsByFd.add(fd, connection); - - if (monitor) { - mMonitoringChannels.push(inputChannel); - } - - mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this); - } // release lock - - // Wake the looper because some connections have changed. - mLooper->wake(); - return OK; -} - -status_t InputDispatcher::unregisterInputChannel(const sp& inputChannel) { -#if DEBUG_REGISTRATION - ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string()); -#endif - - { // acquire lock - AutoMutex _l(mLock); - - status_t status = unregisterInputChannelLocked(inputChannel, false /*notify*/); - if (status) { - return status; - } - } // release lock - - // Wake the poll loop because removing the connection may have changed the current - // synchronization state. - mLooper->wake(); - return OK; -} - -status_t InputDispatcher::unregisterInputChannelLocked(const sp& inputChannel, - bool notify) { - ssize_t connectionIndex = getConnectionIndexLocked(inputChannel); - if (connectionIndex < 0) { - ALOGW("Attempted to unregister already unregistered input channel '%s'", - inputChannel->getName().string()); - return BAD_VALUE; - } - - sp connection = mConnectionsByFd.valueAt(connectionIndex); - mConnectionsByFd.removeItemsAt(connectionIndex); - - if (connection->monitor) { - removeMonitorChannelLocked(inputChannel); - } - - mLooper->removeFd(inputChannel->getFd()); - - nsecs_t currentTime = now(); - abortBrokenDispatchCycleLocked(currentTime, connection, notify); - - connection->status = Connection::STATUS_ZOMBIE; - return OK; -} - -void InputDispatcher::removeMonitorChannelLocked(const sp& inputChannel) { - for (size_t i = 0; i < mMonitoringChannels.size(); i++) { - if (mMonitoringChannels[i] == inputChannel) { - mMonitoringChannels.removeAt(i); - break; - } - } -} - -ssize_t InputDispatcher::getConnectionIndexLocked(const sp& inputChannel) { - ssize_t connectionIndex = mConnectionsByFd.indexOfKey(inputChannel->getFd()); - if (connectionIndex >= 0) { - sp connection = mConnectionsByFd.valueAt(connectionIndex); - if (connection->inputChannel.get() == inputChannel.get()) { - return connectionIndex; - } - } - - return -1; -} - -void InputDispatcher::onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled) { - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doDispatchCycleFinishedLockedInterruptible); - commandEntry->connection = connection; - commandEntry->eventTime = currentTime; - commandEntry->seq = seq; - commandEntry->handled = handled; -} - -void InputDispatcher::onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp& connection) { - ALOGE("channel '%s' ~ Channel is unrecoverably broken and will be disposed!", - connection->getInputChannelName()); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible); - commandEntry->connection = connection; -} - -void InputDispatcher::onANRLocked( - nsecs_t currentTime, const sp& applicationHandle, - const sp& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason) { - float dispatchLatency = (currentTime - eventTime) * 0.000001f; - float waitDuration = (currentTime - waitStartTime) * 0.000001f; - ALOGI("Application is not responding: %s. " - "It has been %0.1fms since event, %0.1fms since wait started. Reason: %s", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(), - dispatchLatency, waitDuration, reason); - - // Capture a record of the InputDispatcher state at the time of the ANR. - time_t t = time(NULL); - struct tm tm; - localtime_r(&t, &tm); - char timestr[64]; - strftime(timestr, sizeof(timestr), "%F %T", &tm); - mLastANRState.clear(); - mLastANRState.append(INDENT "ANR:\n"); - mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr); - mLastANRState.appendFormat(INDENT2 "Window: %s\n", - getApplicationWindowLabelLocked(applicationHandle, windowHandle).string()); - mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency); - mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration); - mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason); - dumpDispatchStateLocked(mLastANRState); - - CommandEntry* commandEntry = postCommandLocked( - & InputDispatcher::doNotifyANRLockedInterruptible); - commandEntry->inputApplicationHandle = applicationHandle; - commandEntry->inputWindowHandle = windowHandle; -} - -void InputDispatcher::doNotifyConfigurationChangedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->notifyConfigurationChanged(commandEntry->eventTime); - - mLock.lock(); -} - -void InputDispatcher::doNotifyInputChannelBrokenLockedInterruptible( - CommandEntry* commandEntry) { - sp connection = commandEntry->connection; - - if (connection->status != Connection::STATUS_ZOMBIE) { - mLock.unlock(); - - mPolicy->notifyInputChannelBroken(connection->inputWindowHandle); - - mLock.lock(); - } -} - -void InputDispatcher::doNotifyANRLockedInterruptible( - CommandEntry* commandEntry) { - mLock.unlock(); - - nsecs_t newTimeout = mPolicy->notifyANR( - commandEntry->inputApplicationHandle, commandEntry->inputWindowHandle); - - mLock.lock(); - - resumeAfterTargetsNotReadyTimeoutLocked(newTimeout, - commandEntry->inputWindowHandle != NULL - ? commandEntry->inputWindowHandle->getInputChannel() : NULL); -} - -void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible( - CommandEntry* commandEntry) { - KeyEntry* entry = commandEntry->keyEntry; - - KeyEvent event; - initializeKeyEvent(&event, entry); - - mLock.unlock(); - - nsecs_t delay = mPolicy->interceptKeyBeforeDispatching(commandEntry->inputWindowHandle, - &event, entry->policyFlags); - - mLock.lock(); - - if (delay < 0) { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_SKIP; - } else if (!delay) { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_CONTINUE; - } else { - entry->interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER; - entry->interceptKeyWakeupTime = now() + delay; - } - entry->release(); -} - -void InputDispatcher::doDispatchCycleFinishedLockedInterruptible( - CommandEntry* commandEntry) { - sp connection = commandEntry->connection; - nsecs_t finishTime = commandEntry->eventTime; - uint32_t seq = commandEntry->seq; - bool handled = commandEntry->handled; - - // Handle post-event policy actions. - DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq); - if (dispatchEntry) { - nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime; - if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) { - String8 msg; - msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ", - connection->getWindowName(), eventDuration * 0.000001f); - dispatchEntry->eventEntry->appendDescription(msg); - ALOGI("%s", msg.string()); - } - - bool restartEvent; - if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) { - KeyEntry* keyEntry = static_cast(dispatchEntry->eventEntry); - restartEvent = afterKeyEventLockedInterruptible(connection, - dispatchEntry, keyEntry, handled); - } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) { - MotionEntry* motionEntry = static_cast(dispatchEntry->eventEntry); - restartEvent = afterMotionEventLockedInterruptible(connection, - dispatchEntry, motionEntry, handled); - } else { - restartEvent = false; - } - - // Dequeue the event and start the next cycle. - // Note that because the lock might have been released, it is possible that the - // contents of the wait queue to have been drained, so we need to double-check - // a few things. - if (dispatchEntry == connection->findWaitQueueEntry(seq)) { - connection->waitQueue.dequeue(dispatchEntry); - traceWaitQueueLengthLocked(connection); - if (restartEvent && connection->status == Connection::STATUS_NORMAL) { - connection->outboundQueue.enqueueAtHead(dispatchEntry); - traceOutboundQueueLengthLocked(connection); - } else { - releaseDispatchEntryLocked(dispatchEntry); - } - } - - // Start the next dispatch cycle for this connection. - startDispatchCycleLocked(now(), connection); - } -} - -bool InputDispatcher::afterKeyEventLockedInterruptible(const sp& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled) { - if (!(keyEntry->flags & AKEY_EVENT_FLAG_FALLBACK)) { - // Get the fallback key state. - // Clear it out after dispatching the UP. - int32_t originalKeyCode = keyEntry->keyCode; - int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); - if (keyEntry->action == AKEY_EVENT_ACTION_UP) { - connection->inputState.removeFallbackKey(originalKeyCode); - } - - if (handled || !dispatchEntry->hasForegroundTarget()) { - // If the application handles the original key for which we previously - // generated a fallback or if the window is not a foreground window, - // then cancel the associated fallback key, if any. - if (fallbackKeyCode != -1) { - // Dispatch the unhandled key to the policy with the cancel flag. -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Asking policy to cancel fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); - - mLock.unlock(); - - mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - // Cancel the fallback key. - if (fallbackKeyCode != AKEYCODE_UNKNOWN) { - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "application handled the original non-fallback key " - "or is no longer a foreground target, " - "canceling previously dispatched fallback key"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - } - connection->inputState.removeFallbackKey(originalKeyCode); - } - } else { - // If the application did not handle a non-fallback key, first check - // that we are in a good state to perform unhandled key event processing - // Then ask the policy what to do with it. - bool initialDown = keyEntry->action == AKEY_EVENT_ACTION_DOWN - && keyEntry->repeatCount == 0; - if (fallbackKeyCode == -1 && !initialDown) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Skipping unhandled key event processing " - "since this is not an initial down. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - originalKeyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - return false; - } - - // Dispatch the unhandled key to the policy. -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Asking policy to perform fallback action. " - "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", - keyEntry->keyCode, keyEntry->action, keyEntry->repeatCount, - keyEntry->policyFlags); -#endif - KeyEvent event; - initializeKeyEvent(&event, keyEntry); - - mLock.unlock(); - - bool fallback = mPolicy->dispatchUnhandledKey(connection->inputWindowHandle, - &event, keyEntry->policyFlags, &event); - - mLock.lock(); - - if (connection->status != Connection::STATUS_NORMAL) { - connection->inputState.removeFallbackKey(originalKeyCode); - return false; - } - - // Latch the fallback keycode for this key on an initial down. - // The fallback keycode cannot change at any other point in the lifecycle. - if (initialDown) { - if (fallback) { - fallbackKeyCode = event.getKeyCode(); - } else { - fallbackKeyCode = AKEYCODE_UNKNOWN; - } - connection->inputState.setFallbackKey(originalKeyCode, fallbackKeyCode); - } - - ALOG_ASSERT(fallbackKeyCode != -1); - - // Cancel the fallback key if the policy decides not to send it anymore. - // We will continue to dispatch the key to the policy but we will no - // longer dispatch a fallback key to the application. - if (fallbackKeyCode != AKEYCODE_UNKNOWN - && (!fallback || fallbackKeyCode != event.getKeyCode())) { -#if DEBUG_OUTBOUND_EVENT_DETAILS - if (fallback) { - ALOGD("Unhandled key event: Policy requested to send key %d" - "as a fallback for %d, but on the DOWN it had requested " - "to send %d instead. Fallback canceled.", - event.getKeyCode(), originalKeyCode, fallbackKeyCode); - } else { - ALOGD("Unhandled key event: Policy did not request fallback for %d, " - "but on the DOWN it had requested to send %d. " - "Fallback canceled.", - originalKeyCode, fallbackKeyCode); - } -#endif - - CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, - "canceling fallback, policy no longer desires it"); - options.keyCode = fallbackKeyCode; - synthesizeCancelationEventsForConnectionLocked(connection, options); - - fallback = false; - fallbackKeyCode = AKEYCODE_UNKNOWN; - if (keyEntry->action != AKEY_EVENT_ACTION_UP) { - connection->inputState.setFallbackKey(originalKeyCode, - fallbackKeyCode); - } - } - -#if DEBUG_OUTBOUND_EVENT_DETAILS - { - String8 msg; - const KeyedVector& fallbackKeys = - connection->inputState.getFallbackKeys(); - for (size_t i = 0; i < fallbackKeys.size(); i++) { - msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i), - fallbackKeys.valueAt(i)); - } - ALOGD("Unhandled key event: %d currently tracked fallback keys%s.", - fallbackKeys.size(), msg.string()); - } -#endif - - if (fallback) { - // Restart the dispatch cycle using the fallback key. - keyEntry->eventTime = event.getEventTime(); - keyEntry->deviceId = event.getDeviceId(); - keyEntry->source = event.getSource(); - keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK; - keyEntry->keyCode = fallbackKeyCode; - keyEntry->scanCode = event.getScanCode(); - keyEntry->metaState = event.getMetaState(); - keyEntry->repeatCount = event.getRepeatCount(); - keyEntry->downTime = event.getDownTime(); - keyEntry->syntheticRepeat = false; - -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: Dispatching fallback key. " - "originalKeyCode=%d, fallbackKeyCode=%d, fallbackMetaState=%08x", - originalKeyCode, fallbackKeyCode, keyEntry->metaState); -#endif - return true; // restart the event - } else { -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Unhandled key event: No fallback key."); -#endif - } - } - } - return false; -} - -bool InputDispatcher::afterMotionEventLockedInterruptible(const sp& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) { - return false; -} - -void InputDispatcher::doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) { - mLock.unlock(); - - mPolicy->pokeUserActivity(commandEntry->eventTime, commandEntry->userActivityEventType); - - mLock.lock(); -} - -void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) { - event->initialize(entry->deviceId, entry->source, entry->action, entry->flags, - entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount, - entry->downTime, entry->eventTime); -} - -void InputDispatcher::updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication) { - // TODO Write some statistics about how long we spend waiting. -} - -void InputDispatcher::traceInboundQueueLengthLocked() { -#ifdef HAVE_ANDROID_OS - if (ATRACE_ENABLED()) { - ATRACE_INT("iq", mInboundQueue.count()); - } -#endif -} - -void InputDispatcher::traceOutboundQueueLengthLocked(const sp& connection) { -#ifdef HAVE_ANDROID_OS - if (ATRACE_ENABLED()) { - char counterName[40]; - snprintf(counterName, sizeof(counterName), "oq:%s", connection->getWindowName()); - ATRACE_INT(counterName, connection->outboundQueue.count()); - } -#endif -} - -void InputDispatcher::traceWaitQueueLengthLocked(const sp& connection) { -#ifdef HAVE_ANDROID_OS - if (ATRACE_ENABLED()) { - char counterName[40]; - snprintf(counterName, sizeof(counterName), "wq:%s", connection->getWindowName()); - ATRACE_INT(counterName, connection->waitQueue.count()); - } -#endif -} - -void InputDispatcher::dump(String8& dump) { - AutoMutex _l(mLock); - - dump.append("Input Dispatcher State:\n"); - dumpDispatchStateLocked(dump); - - if (!mLastANRState.isEmpty()) { - dump.append("\nInput Dispatcher State at time of last ANR:\n"); - dump.append(mLastANRState); - } -} - -void InputDispatcher::monitor() { - // Acquire and release the lock to ensure that the dispatcher has not deadlocked. - mLock.lock(); - mLooper->wake(); - mDispatcherIsAliveCondition.wait(mLock); - mLock.unlock(); -} - - -// --- InputDispatcher::Queue --- - -template -uint32_t InputDispatcher::Queue::count() const { - uint32_t result = 0; - for (const T* entry = head; entry; entry = entry->next) { - result += 1; - } - return result; -} - - -// --- InputDispatcher::InjectionState --- - -InputDispatcher::InjectionState::InjectionState(int32_t injectorPid, int32_t injectorUid) : - refCount(1), - injectorPid(injectorPid), injectorUid(injectorUid), - injectionResult(INPUT_EVENT_INJECTION_PENDING), injectionIsAsync(false), - pendingForegroundDispatches(0) { -} - -InputDispatcher::InjectionState::~InjectionState() { -} - -void InputDispatcher::InjectionState::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - - -// --- InputDispatcher::EventEntry --- - -InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) : - refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags), - injectionState(NULL), dispatchInProgress(false) { -} - -InputDispatcher::EventEntry::~EventEntry() { - releaseInjectionState(); -} - -void InputDispatcher::EventEntry::release() { - refCount -= 1; - if (refCount == 0) { - delete this; - } else { - ALOG_ASSERT(refCount > 0); - } -} - -void InputDispatcher::EventEntry::releaseInjectionState() { - if (injectionState) { - injectionState->release(); - injectionState = NULL; - } -} - - -// --- InputDispatcher::ConfigurationChangedEntry --- - -InputDispatcher::ConfigurationChangedEntry::ConfigurationChangedEntry(nsecs_t eventTime) : - EventEntry(TYPE_CONFIGURATION_CHANGED, eventTime, 0) { -} - -InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() { -} - -void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const { - msg.append("ConfigurationChangedEvent()"); -} - - -// --- InputDispatcher::DeviceResetEntry --- - -InputDispatcher::DeviceResetEntry::DeviceResetEntry(nsecs_t eventTime, int32_t deviceId) : - EventEntry(TYPE_DEVICE_RESET, eventTime, 0), - deviceId(deviceId) { -} - -InputDispatcher::DeviceResetEntry::~DeviceResetEntry() { -} - -void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const { - msg.appendFormat("DeviceResetEvent(deviceId=%d)", deviceId); -} - - -// --- InputDispatcher::KeyEntry --- - -InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime) : - EventEntry(TYPE_KEY, eventTime, policyFlags), - deviceId(deviceId), source(source), action(action), flags(flags), - keyCode(keyCode), scanCode(scanCode), metaState(metaState), - repeatCount(repeatCount), downTime(downTime), - syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN), - interceptKeyWakeupTime(0) { -} - -InputDispatcher::KeyEntry::~KeyEntry() { -} - -void InputDispatcher::KeyEntry::appendDescription(String8& msg) const { - msg.appendFormat("KeyEvent(action=%d, deviceId=%d, source=0x%08x)", - action, deviceId, source); -} - -void InputDispatcher::KeyEntry::recycle() { - releaseInjectionState(); - - dispatchInProgress = false; - syntheticRepeat = false; - interceptKeyResult = KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN; - interceptKeyWakeupTime = 0; -} - - -// --- InputDispatcher::MotionEntry --- - -InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, - int32_t edgeFlags, float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords) : - EventEntry(TYPE_MOTION, eventTime, policyFlags), - eventTime(eventTime), - deviceId(deviceId), source(source), action(action), flags(flags), - metaState(metaState), buttonState(buttonState), edgeFlags(edgeFlags), - xPrecision(xPrecision), yPrecision(yPrecision), - downTime(downTime), displayId(displayId), pointerCount(pointerCount) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -InputDispatcher::MotionEntry::~MotionEntry() { -} - -void InputDispatcher::MotionEntry::appendDescription(String8& msg) const { - msg.appendFormat("MotionEvent(action=%d, deviceId=%d, source=0x%08x, displayId=%d)", - action, deviceId, source, displayId); -} - - -// --- InputDispatcher::DispatchEntry --- - -volatile int32_t InputDispatcher::DispatchEntry::sNextSeqAtomic; - -InputDispatcher::DispatchEntry::DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor) : - seq(nextSeq()), - eventEntry(eventEntry), targetFlags(targetFlags), - xOffset(xOffset), yOffset(yOffset), scaleFactor(scaleFactor), - deliveryTime(0), resolvedAction(0), resolvedFlags(0) { - eventEntry->refCount += 1; -} - -InputDispatcher::DispatchEntry::~DispatchEntry() { - eventEntry->release(); -} - -uint32_t InputDispatcher::DispatchEntry::nextSeq() { - // Sequence number 0 is reserved and will never be returned. - uint32_t seq; - do { - seq = android_atomic_inc(&sNextSeqAtomic); - } while (!seq); - return seq; -} - - -// --- InputDispatcher::InputState --- - -InputDispatcher::InputState::InputState() { -} - -InputDispatcher::InputState::~InputState() { -} - -bool InputDispatcher::InputState::isNeutral() const { - return mKeyMementos.isEmpty() && mMotionMementos.isEmpty(); -} - -bool InputDispatcher::InputState::isHovering(int32_t deviceId, uint32_t source, - int32_t displayId) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.deviceId == deviceId - && memento.source == source - && memento.displayId == displayId - && memento.hovering) { - return true; - } - } - return false; -} - -bool InputDispatcher::InputState::trackKey(const KeyEntry* entry, - int32_t action, int32_t flags) { - switch (action) { - case AKEY_EVENT_ACTION_UP: { - if (entry->flags & AKEY_EVENT_FLAG_FALLBACK) { - for (size_t i = 0; i < mFallbackKeys.size(); ) { - if (mFallbackKeys.valueAt(i) == entry->keyCode) { - mFallbackKeys.removeItemsAt(i); - } else { - i += 1; - } - } - } - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.removeAt(index); - return true; - } - /* FIXME: We can't just drop the key up event because that prevents creating - * popup windows that are automatically shown when a key is held and then - * dismissed when the key is released. The problem is that the popup will - * not have received the original key down, so the key up will be considered - * to be inconsistent with its observed state. We could perhaps handle this - * by synthesizing a key down but that will cause other problems. - * - * So for now, allow inconsistent key up events to be dispatched. - * -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent key up event: deviceId=%d, source=%08x, " - "keyCode=%d, scanCode=%d", - entry->deviceId, entry->source, entry->keyCode, entry->scanCode); -#endif - return false; - */ - return true; - } - - case AKEY_EVENT_ACTION_DOWN: { - ssize_t index = findKeyMemento(entry); - if (index >= 0) { - mKeyMementos.removeAt(index); - } - addKeyMemento(entry, flags); - return true; - } - - default: - return true; - } -} - -bool InputDispatcher::InputState::trackMotion(const MotionEntry* entry, - int32_t action, int32_t flags) { - int32_t actionMasked = action & AMOTION_EVENT_ACTION_MASK; - switch (actionMasked) { - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, " - "actionMasked=%d", - entry->deviceId, entry->source, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - } - addMotionMemento(entry, flags, false /*hovering*/); - return true; - } - - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - case AMOTION_EVENT_ACTION_MOVE: { - ssize_t index = findMotionMemento(entry, false /*hovering*/); - if (index >= 0) { - MotionMemento& memento = mMotionMementos.editItemAt(index); - memento.setPointers(entry); - return true; - } - if (actionMasked == AMOTION_EVENT_ACTION_MOVE - && (entry->source & (AINPUT_SOURCE_CLASS_JOYSTICK - | AINPUT_SOURCE_CLASS_NAVIGATION))) { - // Joysticks and trackballs can send MOVE events without corresponding DOWN or UP. - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion pointer up/down or move event: " - "deviceId=%d, source=%08x, actionMasked=%d", - entry->deviceId, entry->source, actionMasked); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_EXIT: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - return true; - } -#if DEBUG_OUTBOUND_EVENT_DETAILS - ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x", - entry->deviceId, entry->source); -#endif - return false; - } - - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: { - ssize_t index = findMotionMemento(entry, true /*hovering*/); - if (index >= 0) { - mMotionMementos.removeAt(index); - } - addMotionMemento(entry, flags, true /*hovering*/); - return true; - } - - default: - return true; - } -} - -ssize_t InputDispatcher::InputState::findKeyMemento(const KeyEntry* entry) const { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.keyCode == entry->keyCode - && memento.scanCode == entry->scanCode) { - return i; - } - } - return -1; -} - -ssize_t InputDispatcher::InputState::findMotionMemento(const MotionEntry* entry, - bool hovering) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.deviceId == entry->deviceId - && memento.source == entry->source - && memento.displayId == entry->displayId - && memento.hovering == hovering) { - return i; - } - } - return -1; -} - -void InputDispatcher::InputState::addKeyMemento(const KeyEntry* entry, int32_t flags) { - mKeyMementos.push(); - KeyMemento& memento = mKeyMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.keyCode = entry->keyCode; - memento.scanCode = entry->scanCode; - memento.metaState = entry->metaState; - memento.flags = flags; - memento.downTime = entry->downTime; - memento.policyFlags = entry->policyFlags; -} - -void InputDispatcher::InputState::addMotionMemento(const MotionEntry* entry, - int32_t flags, bool hovering) { - mMotionMementos.push(); - MotionMemento& memento = mMotionMementos.editTop(); - memento.deviceId = entry->deviceId; - memento.source = entry->source; - memento.flags = flags; - memento.xPrecision = entry->xPrecision; - memento.yPrecision = entry->yPrecision; - memento.downTime = entry->downTime; - memento.displayId = entry->displayId; - memento.setPointers(entry); - memento.hovering = hovering; - memento.policyFlags = entry->policyFlags; -} - -void InputDispatcher::InputState::MotionMemento::setPointers(const MotionEntry* entry) { - pointerCount = entry->pointerCount; - for (uint32_t i = 0; i < entry->pointerCount; i++) { - pointerProperties[i].copyFrom(entry->pointerProperties[i]); - pointerCoords[i].copyFrom(entry->pointerCoords[i]); - } -} - -void InputDispatcher::InputState::synthesizeCancelationEvents(nsecs_t currentTime, - Vector& outEvents, const CancelationOptions& options) { - for (size_t i = 0; i < mKeyMementos.size(); i++) { - const KeyMemento& memento = mKeyMementos.itemAt(i); - if (shouldCancelKey(memento, options)) { - outEvents.push(new KeyEntry(currentTime, - memento.deviceId, memento.source, memento.policyFlags, - AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED, - memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime)); - } - } - - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (shouldCancelMotion(memento, options)) { - outEvents.push(new MotionEntry(currentTime, - memento.deviceId, memento.source, memento.policyFlags, - memento.hovering - ? AMOTION_EVENT_ACTION_HOVER_EXIT - : AMOTION_EVENT_ACTION_CANCEL, - memento.flags, 0, 0, 0, - memento.xPrecision, memento.yPrecision, memento.downTime, - memento.displayId, - memento.pointerCount, memento.pointerProperties, memento.pointerCoords)); - } - } -} - -void InputDispatcher::InputState::clear() { - mKeyMementos.clear(); - mMotionMementos.clear(); - mFallbackKeys.clear(); -} - -void InputDispatcher::InputState::copyPointerStateTo(InputState& other) const { - for (size_t i = 0; i < mMotionMementos.size(); i++) { - const MotionMemento& memento = mMotionMementos.itemAt(i); - if (memento.source & AINPUT_SOURCE_CLASS_POINTER) { - for (size_t j = 0; j < other.mMotionMementos.size(); ) { - const MotionMemento& otherMemento = other.mMotionMementos.itemAt(j); - if (memento.deviceId == otherMemento.deviceId - && memento.source == otherMemento.source - && memento.displayId == otherMemento.displayId) { - other.mMotionMementos.removeAt(j); - } else { - j += 1; - } - } - other.mMotionMementos.push(memento); - } - } -} - -int32_t InputDispatcher::InputState::getFallbackKey(int32_t originalKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - return index >= 0 ? mFallbackKeys.valueAt(index) : -1; -} - -void InputDispatcher::InputState::setFallbackKey(int32_t originalKeyCode, - int32_t fallbackKeyCode) { - ssize_t index = mFallbackKeys.indexOfKey(originalKeyCode); - if (index >= 0) { - mFallbackKeys.replaceValueAt(index, fallbackKeyCode); - } else { - mFallbackKeys.add(originalKeyCode, fallbackKeyCode); - } -} - -void InputDispatcher::InputState::removeFallbackKey(int32_t originalKeyCode) { - mFallbackKeys.removeItem(originalKeyCode); -} - -bool InputDispatcher::InputState::shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options) { - if (options.keyCode != -1 && memento.keyCode != options.keyCode) { - return false; - } - - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return true; - case CancelationOptions::CANCEL_FALLBACK_EVENTS: - return memento.flags & AKEY_EVENT_FLAG_FALLBACK; - default: - return false; - } -} - -bool InputDispatcher::InputState::shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options) { - if (options.deviceId != -1 && memento.deviceId != options.deviceId) { - return false; - } - - switch (options.mode) { - case CancelationOptions::CANCEL_ALL_EVENTS: - return true; - case CancelationOptions::CANCEL_POINTER_EVENTS: - return memento.source & AINPUT_SOURCE_CLASS_POINTER; - case CancelationOptions::CANCEL_NON_POINTER_EVENTS: - return !(memento.source & AINPUT_SOURCE_CLASS_POINTER); - default: - return false; - } -} - - -// --- InputDispatcher::Connection --- - -InputDispatcher::Connection::Connection(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor) : - status(STATUS_NORMAL), inputChannel(inputChannel), inputWindowHandle(inputWindowHandle), - monitor(monitor), - inputPublisher(inputChannel), inputPublisherBlocked(false) { -} - -InputDispatcher::Connection::~Connection() { -} - -const char* InputDispatcher::Connection::getWindowName() const { - if (inputWindowHandle != NULL) { - return inputWindowHandle->getName().string(); - } - if (monitor) { - return "monitor"; - } - return "?"; -} - -const char* InputDispatcher::Connection::getStatusLabel() const { - switch (status) { - case STATUS_NORMAL: - return "NORMAL"; - - case STATUS_BROKEN: - return "BROKEN"; - - case STATUS_ZOMBIE: - return "ZOMBIE"; - - default: - return "UNKNOWN"; - } -} - -InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) { - for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) { - if (entry->seq == seq) { - return entry; - } - } - return NULL; -} - - -// --- InputDispatcher::CommandEntry --- - -InputDispatcher::CommandEntry::CommandEntry(Command command) : - command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0), - seq(0), handled(false) { -} - -InputDispatcher::CommandEntry::~CommandEntry() { -} - - -// --- InputDispatcher::TouchState --- - -InputDispatcher::TouchState::TouchState() : - down(false), split(false), deviceId(-1), source(0), displayId(-1) { -} - -InputDispatcher::TouchState::~TouchState() { -} - -void InputDispatcher::TouchState::reset() { - down = false; - split = false; - deviceId = -1; - source = 0; - displayId = -1; - windows.clear(); -} - -void InputDispatcher::TouchState::copyFrom(const TouchState& other) { - down = other.down; - split = other.split; - deviceId = other.deviceId; - source = other.source; - displayId = other.displayId; - windows = other.windows; -} - -void InputDispatcher::TouchState::addOrUpdateWindow(const sp& windowHandle, - int32_t targetFlags, BitSet32 pointerIds) { - if (targetFlags & InputTarget::FLAG_SPLIT) { - split = true; - } - - for (size_t i = 0; i < windows.size(); i++) { - TouchedWindow& touchedWindow = windows.editItemAt(i); - if (touchedWindow.windowHandle == windowHandle) { - touchedWindow.targetFlags |= targetFlags; - if (targetFlags & InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT) { - touchedWindow.targetFlags &= ~InputTarget::FLAG_DISPATCH_AS_IS; - } - touchedWindow.pointerIds.value |= pointerIds.value; - return; - } - } - - windows.push(); - - TouchedWindow& touchedWindow = windows.editTop(); - touchedWindow.windowHandle = windowHandle; - touchedWindow.targetFlags = targetFlags; - touchedWindow.pointerIds = pointerIds; -} - -void InputDispatcher::TouchState::removeWindow(const sp& windowHandle) { - for (size_t i = 0; i < windows.size(); i++) { - if (windows.itemAt(i).windowHandle == windowHandle) { - windows.removeAt(i); - return; - } - } -} - -void InputDispatcher::TouchState::filterNonAsIsTouchWindows() { - for (size_t i = 0 ; i < windows.size(); ) { - TouchedWindow& window = windows.editItemAt(i); - if (window.targetFlags & (InputTarget::FLAG_DISPATCH_AS_IS - | InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER)) { - window.targetFlags &= ~InputTarget::FLAG_DISPATCH_MASK; - window.targetFlags |= InputTarget::FLAG_DISPATCH_AS_IS; - i += 1; - } else { - windows.removeAt(i); - } - } -} - -sp InputDispatcher::TouchState::getFirstForegroundWindowHandle() const { - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows.itemAt(i); - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - return window.windowHandle; - } - } - return NULL; -} - -bool InputDispatcher::TouchState::isSlippery() const { - // Must have exactly one foreground window. - bool haveSlipperyForegroundWindow = false; - for (size_t i = 0; i < windows.size(); i++) { - const TouchedWindow& window = windows.itemAt(i); - if (window.targetFlags & InputTarget::FLAG_FOREGROUND) { - if (haveSlipperyForegroundWindow - || !(window.windowHandle->getInfo()->layoutParamsFlags - & InputWindowInfo::FLAG_SLIPPERY)) { - return false; - } - haveSlipperyForegroundWindow = true; - } - } - return haveSlipperyForegroundWindow; -} - - -// --- InputDispatcherThread --- - -InputDispatcherThread::InputDispatcherThread(const sp& dispatcher) : - Thread(/*canCallJava*/ true), mDispatcher(dispatcher) { -} - -InputDispatcherThread::~InputDispatcherThread() { -} - -bool InputDispatcherThread::threadLoop() { - mDispatcher->dispatchOnce(); - return true; -} - -} // namespace android diff --git a/widget/gonk/libui/InputDispatcher.h b/widget/gonk/libui/InputDispatcher.h deleted file mode 100644 index 5453421f6..000000000 --- a/widget/gonk/libui/InputDispatcher.h +++ /dev/null @@ -1,1117 +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. - */ - -#ifndef _UI_INPUT_DISPATCHER_H -#define _UI_INPUT_DISPATCHER_H - -#include "Input.h" -#include "InputTransport.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "InputWindow.h" -#include "InputApplication.h" -#include "InputListener.h" - - -namespace android { - -/* - * Constants used to report the outcome of input event injection. - */ -enum { - /* (INTERNAL USE ONLY) Specifies that injection is pending and its outcome is unknown. */ - INPUT_EVENT_INJECTION_PENDING = -1, - - /* Injection succeeded. */ - INPUT_EVENT_INJECTION_SUCCEEDED = 0, - - /* Injection failed because the injector did not have permission to inject - * into the application with input focus. */ - INPUT_EVENT_INJECTION_PERMISSION_DENIED = 1, - - /* Injection failed because there were no available input targets. */ - INPUT_EVENT_INJECTION_FAILED = 2, - - /* Injection failed due to a timeout. */ - INPUT_EVENT_INJECTION_TIMED_OUT = 3 -}; - -/* - * Constants used to determine the input event injection synchronization mode. - */ -enum { - /* Injection is asynchronous and is assumed always to be successful. */ - INPUT_EVENT_INJECTION_SYNC_NONE = 0, - - /* Waits for previous events to be dispatched so that the input dispatcher can determine - * whether input event injection willbe permitted based on the current input focus. - * Does not wait for the input event to finish processing. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_RESULT = 1, - - /* Waits for the input event to be completely processed. */ - INPUT_EVENT_INJECTION_SYNC_WAIT_FOR_FINISHED = 2, -}; - - -/* - * An input target specifies how an input event is to be dispatched to a particular window - * including the window's input channel, control flags, a timeout, and an X / Y offset to - * be added to input event coordinates to compensate for the absolute position of the - * window area. - */ -struct InputTarget { - enum { - /* This flag indicates that the event is being delivered to a foreground application. */ - FLAG_FOREGROUND = 1 << 0, - - /* This flag indicates that the target of a MotionEvent is partly or wholly - * obscured by another visible window above it. The motion event should be - * delivered with flag AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. */ - FLAG_WINDOW_IS_OBSCURED = 1 << 1, - - /* This flag indicates that a motion event is being split across multiple windows. */ - FLAG_SPLIT = 1 << 2, - - /* This flag indicates that the pointer coordinates dispatched to the application - * will be zeroed out to avoid revealing information to an application. This is - * used in conjunction with FLAG_DISPATCH_AS_OUTSIDE to prevent apps not sharing - * the same UID from watching all touches. */ - FLAG_ZERO_COORDS = 1 << 3, - - /* This flag indicates that the event should be sent as is. - * Should always be set unless the event is to be transmuted. */ - FLAG_DISPATCH_AS_IS = 1 << 8, - - /* This flag indicates that a MotionEvent with AMOTION_EVENT_ACTION_DOWN falls outside - * of the area of this target and so should instead be delivered as an - * AMOTION_EVENT_ACTION_OUTSIDE to this target. */ - FLAG_DISPATCH_AS_OUTSIDE = 1 << 9, - - /* This flag indicates that a hover sequence is starting in the given window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_ENTER = 1 << 10, - - /* This flag indicates that a hover event happened outside of a window which handled - * previous hover events, signifying the end of the current hover sequence for that - * window. - * The event is transmuted into ACTION_HOVER_ENTER. */ - FLAG_DISPATCH_AS_HOVER_EXIT = 1 << 11, - - /* This flag indicates that the event should be canceled. - * It is used to transmute ACTION_MOVE into ACTION_CANCEL when a touch slips - * outside of a window. */ - FLAG_DISPATCH_AS_SLIPPERY_EXIT = 1 << 12, - - /* This flag indicates that the event should be dispatched as an initial down. - * It is used to transmute ACTION_MOVE into ACTION_DOWN when a touch slips - * into a new window. */ - FLAG_DISPATCH_AS_SLIPPERY_ENTER = 1 << 13, - - /* Mask for all dispatch modes. */ - FLAG_DISPATCH_MASK = FLAG_DISPATCH_AS_IS - | FLAG_DISPATCH_AS_OUTSIDE - | FLAG_DISPATCH_AS_HOVER_ENTER - | FLAG_DISPATCH_AS_HOVER_EXIT - | FLAG_DISPATCH_AS_SLIPPERY_EXIT - | FLAG_DISPATCH_AS_SLIPPERY_ENTER, - }; - - // The input channel to be targeted. - sp inputChannel; - - // Flags for the input target. - int32_t flags; - - // The x and y offset to add to a MotionEvent as it is delivered. - // (ignored for KeyEvents) - float xOffset, yOffset; - - // Scaling factor to apply to MotionEvent as it is delivered. - // (ignored for KeyEvents) - float scaleFactor; - - // The subset of pointer ids to include in motion events dispatched to this input target - // if FLAG_SPLIT is set. - BitSet32 pointerIds; -}; - - -/* - * Input dispatcher configuration. - * - * Specifies various options that modify the behavior of the input dispatcher. - * The values provided here are merely defaults. The actual values will come from ViewConfiguration - * and are passed into the dispatcher during initialization. - */ -struct InputDispatcherConfiguration { - // The key repeat initial timeout. - nsecs_t keyRepeatTimeout; - - // The key repeat inter-key delay. - nsecs_t keyRepeatDelay; - - InputDispatcherConfiguration() : - keyRepeatTimeout(500 * 1000000LL), - keyRepeatDelay(50 * 1000000LL) { } -}; - - -/* - * Input dispatcher policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class InputDispatcherPolicyInterface : public virtual RefBase { -protected: - InputDispatcherPolicyInterface() { } - virtual ~InputDispatcherPolicyInterface() { } - -public: - /* Notifies the system that a configuration change has occurred. */ - virtual void notifyConfigurationChanged(nsecs_t when) = 0; - - /* Notifies the system that an application is not responding. - * Returns a new timeout to continue waiting, or 0 to abort dispatch. */ - virtual nsecs_t notifyANR(const sp& inputApplicationHandle, - const sp& inputWindowHandle) = 0; - - /* Notifies the system that an input channel is unrecoverably broken. */ - virtual void notifyInputChannelBroken(const sp& inputWindowHandle) = 0; - - /* Gets the input dispatcher configuration. */ - virtual void getDispatcherConfiguration(InputDispatcherConfiguration* outConfig) = 0; - - /* Returns true if automatic key repeating is enabled. */ - virtual bool isKeyRepeatEnabled() = 0; - - /* Filters an input event. - * Return true to dispatch the event unmodified, false to consume the event. - * A filter can also transform and inject events later by passing POLICY_FLAG_FILTERED - * to injectInputEvent. - */ - virtual bool filterInputEvent(const InputEvent* inputEvent, uint32_t policyFlags) = 0; - - /* Intercepts a key event immediately before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptKeyBeforeQueueing(const KeyEvent* keyEvent, uint32_t& policyFlags) = 0; - - /* Intercepts a touch, trackball or other motion event before queueing it. - * The policy can use this method as an opportunity to perform power management functions - * and early event preprocessing such as updating policy flags. - * - * This method is expected to set the POLICY_FLAG_PASS_TO_USER policy flag if the event - * should be dispatched to applications. - */ - virtual void interceptMotionBeforeQueueing(nsecs_t when, uint32_t& policyFlags) = 0; - - /* Allows the policy a chance to intercept a key before dispatching. */ - virtual nsecs_t interceptKeyBeforeDispatching(const sp& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags) = 0; - - /* Allows the policy a chance to perform default processing for an unhandled key. - * Returns an alternate keycode to redispatch as a fallback, or 0 to give up. */ - virtual bool dispatchUnhandledKey(const sp& inputWindowHandle, - const KeyEvent* keyEvent, uint32_t policyFlags, KeyEvent* outFallbackKeyEvent) = 0; - - /* Notifies the policy about switch events. - */ - virtual void notifySwitch(nsecs_t when, - uint32_t switchValues, uint32_t switchMask, uint32_t policyFlags) = 0; - - /* Poke user activity for an event dispatched to a window. */ - virtual void pokeUserActivity(nsecs_t eventTime, int32_t eventType) = 0; - - /* Checks whether a given application pid/uid has permission to inject input events - * into other applications. - * - * This method is special in that its implementation promises to be non-reentrant and - * is safe to call while holding other locks. (Most other methods make no such guarantees!) - */ - virtual bool checkInjectEventsPermissionNonReentrant( - int32_t injectorPid, int32_t injectorUid) = 0; -}; - - -/* Notifies the system about input events generated by the input reader. - * The dispatcher is expected to be mostly asynchronous. */ -class InputDispatcherInterface : public virtual RefBase, public InputListenerInterface { -protected: - InputDispatcherInterface() { } - virtual ~InputDispatcherInterface() { } - -public: - /* Dumps the state of the input dispatcher. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the dispatch loop. - * Nominally processes one queued event, a timeout, or a response from an input consumer. - * - * This method should only be called on the input dispatcher thread. - */ - virtual void dispatchOnce() = 0; - - /* Injects an input event and optionally waits for sync. - * The synchronization mode determines whether the method blocks while waiting for - * input injection to proceed. - * Returns one of the INPUT_EVENT_INJECTION_XXX constants. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags) = 0; - - /* Sets the list of input windows. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputWindows(const Vector >& inputWindowHandles) = 0; - - /* Sets the focused application. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setFocusedApplication( - const sp& inputApplicationHandle) = 0; - - /* Sets the input dispatching mode. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void setInputDispatchMode(bool enabled, bool frozen) = 0; - - /* Sets whether input event filtering is enabled. - * When enabled, incoming input events are sent to the policy's filterInputEvent - * method instead of being dispatched. The filter is expected to use - * injectInputEvent to inject the events it would like to have dispatched. - * It should include POLICY_FLAG_FILTERED in the policy flags during injection. - */ - virtual void setInputFilterEnabled(bool enabled) = 0; - - /* Transfers touch focus from the window associated with one channel to the - * window associated with the other channel. - * - * Returns true on success. False if the window did not actually have touch focus. - */ - virtual bool transferTouchFocus(const sp& fromChannel, - const sp& toChannel) = 0; - - /* Registers or unregister input channels that may be used as targets for input events. - * If monitor is true, the channel will receive a copy of all input events. - * - * These methods may be called on any thread (usually by the input manager). - */ - virtual status_t registerInputChannel(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor) = 0; - virtual status_t unregisterInputChannel(const sp& inputChannel) = 0; -}; - -/* Dispatches events to input targets. Some functions of the input dispatcher, such as - * identifying input targets, are controlled by a separate policy object. - * - * IMPORTANT INVARIANT: - * Because the policy can potentially block or cause re-entrance into the input dispatcher, - * the input dispatcher never calls into the policy while holding its internal locks. - * The implementation is also carefully designed to recover from scenarios such as an - * input channel becoming unregistered while identifying input targets or processing timeouts. - * - * Methods marked 'Locked' must be called with the lock acquired. - * - * Methods marked 'LockedInterruptible' must be called with the lock acquired but - * may during the course of their execution release the lock, call into the policy, and - * then reacquire the lock. The caller is responsible for recovering gracefully. - * - * A 'LockedInterruptible' method may called a 'Locked' method, but NOT vice-versa. - */ -class InputDispatcher : public InputDispatcherInterface { -protected: - virtual ~InputDispatcher(); - -public: - explicit InputDispatcher(const sp& policy); - - virtual void dump(String8& dump); - virtual void monitor(); - - virtual void dispatchOnce(); - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags); - - virtual void setInputWindows(const Vector >& inputWindowHandles); - virtual void setFocusedApplication(const sp& inputApplicationHandle); - virtual void setInputDispatchMode(bool enabled, bool frozen); - virtual void setInputFilterEnabled(bool enabled); - - virtual bool transferTouchFocus(const sp& fromChannel, - const sp& toChannel); - - virtual status_t registerInputChannel(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor); - virtual status_t unregisterInputChannel(const sp& inputChannel); - -private: - template - struct Link { - T* next; - T* prev; - - protected: - inline Link() : next(NULL), prev(NULL) { } - }; - - struct InjectionState { - mutable int32_t refCount; - - int32_t injectorPid; - int32_t injectorUid; - int32_t injectionResult; // initially INPUT_EVENT_INJECTION_PENDING - bool injectionIsAsync; // set to true if injection is not waiting for the result - int32_t pendingForegroundDispatches; // the number of foreground dispatches in progress - - InjectionState(int32_t injectorPid, int32_t injectorUid); - void release(); - - private: - ~InjectionState(); - }; - - struct EventEntry : Link { - enum { - TYPE_CONFIGURATION_CHANGED, - TYPE_DEVICE_RESET, - TYPE_KEY, - TYPE_MOTION - }; - - mutable int32_t refCount; - int32_t type; - nsecs_t eventTime; - uint32_t policyFlags; - InjectionState* injectionState; - - bool dispatchInProgress; // initially false, set to true while dispatching - - inline bool isInjected() const { return injectionState != NULL; } - - void release(); - - virtual void appendDescription(String8& msg) const = 0; - - protected: - EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags); - virtual ~EventEntry(); - void releaseInjectionState(); - }; - - struct ConfigurationChangedEntry : EventEntry { - ConfigurationChangedEntry(nsecs_t eventTime); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~ConfigurationChangedEntry(); - }; - - struct DeviceResetEntry : EventEntry { - int32_t deviceId; - - DeviceResetEntry(nsecs_t eventTime, int32_t deviceId); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~DeviceResetEntry(); - }; - - struct KeyEntry : EventEntry { - int32_t deviceId; - uint32_t source; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t repeatCount; - nsecs_t downTime; - - bool syntheticRepeat; // set to true for synthetic key repeats - - enum InterceptKeyResult { - INTERCEPT_KEY_RESULT_UNKNOWN, - INTERCEPT_KEY_RESULT_SKIP, - INTERCEPT_KEY_RESULT_CONTINUE, - INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER, - }; - InterceptKeyResult interceptKeyResult; // set based on the interception result - nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER - - KeyEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action, - int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState, - int32_t repeatCount, nsecs_t downTime); - virtual void appendDescription(String8& msg) const; - void recycle(); - - protected: - virtual ~KeyEntry(); - }; - - struct MotionEntry : EventEntry { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - - MotionEntry(nsecs_t eventTime, - int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, - int32_t metaState, int32_t buttonState, int32_t edgeFlags, - float xPrecision, float yPrecision, - nsecs_t downTime, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords); - virtual void appendDescription(String8& msg) const; - - protected: - virtual ~MotionEntry(); - }; - - // Tracks the progress of dispatching a particular event to a particular connection. - struct DispatchEntry : Link { - const uint32_t seq; // unique sequence number, never 0 - - EventEntry* eventEntry; // the event to dispatch - int32_t targetFlags; - float xOffset; - float yOffset; - float scaleFactor; - nsecs_t deliveryTime; // time when the event was actually delivered - - // Set to the resolved action and flags when the event is enqueued. - int32_t resolvedAction; - int32_t resolvedFlags; - - DispatchEntry(EventEntry* eventEntry, - int32_t targetFlags, float xOffset, float yOffset, float scaleFactor); - ~DispatchEntry(); - - inline bool hasForegroundTarget() const { - return targetFlags & InputTarget::FLAG_FOREGROUND; - } - - inline bool isSplit() const { - return targetFlags & InputTarget::FLAG_SPLIT; - } - - private: - static volatile int32_t sNextSeqAtomic; - - static uint32_t nextSeq(); - }; - - // A command entry captures state and behavior for an action to be performed in the - // dispatch loop after the initial processing has taken place. It is essentially - // a kind of continuation used to postpone sensitive policy interactions to a point - // in the dispatch loop where it is safe to release the lock (generally after finishing - // the critical parts of the dispatch cycle). - // - // The special thing about commands is that they can voluntarily release and reacquire - // the dispatcher lock at will. Initially when the command starts running, the - // dispatcher lock is held. However, if the command needs to call into the policy to - // do some work, it can release the lock, do the work, then reacquire the lock again - // before returning. - // - // This mechanism is a bit clunky but it helps to preserve the invariant that the dispatch - // never calls into the policy while holding its lock. - // - // Commands are implicitly 'LockedInterruptible'. - struct CommandEntry; - typedef void (InputDispatcher::*Command)(CommandEntry* commandEntry); - - class Connection; - struct CommandEntry : Link { - CommandEntry(Command command); - ~CommandEntry(); - - Command command; - - // parameters for the command (usage varies by command) - sp connection; - nsecs_t eventTime; - KeyEntry* keyEntry; - sp inputApplicationHandle; - sp inputWindowHandle; - int32_t userActivityEventType; - uint32_t seq; - bool handled; - }; - - // Generic queue implementation. - template - struct Queue { - T* head; - T* tail; - - inline Queue() : head(NULL), tail(NULL) { - } - - inline bool isEmpty() const { - return !head; - } - - inline void enqueueAtTail(T* entry) { - entry->prev = tail; - if (tail) { - tail->next = entry; - } else { - head = entry; - } - entry->next = NULL; - tail = entry; - } - - inline void enqueueAtHead(T* entry) { - entry->next = head; - if (head) { - head->prev = entry; - } else { - tail = entry; - } - entry->prev = NULL; - head = entry; - } - - inline void dequeue(T* entry) { - if (entry->prev) { - entry->prev->next = entry->next; - } else { - head = entry->next; - } - if (entry->next) { - entry->next->prev = entry->prev; - } else { - tail = entry->prev; - } - } - - inline T* dequeueAtHead() { - T* entry = head; - head = entry->next; - if (head) { - head->prev = NULL; - } else { - tail = NULL; - } - return entry; - } - - uint32_t count() const; - }; - - /* Specifies which events are to be canceled and why. */ - struct CancelationOptions { - enum Mode { - CANCEL_ALL_EVENTS = 0, - CANCEL_POINTER_EVENTS = 1, - CANCEL_NON_POINTER_EVENTS = 2, - CANCEL_FALLBACK_EVENTS = 3, - }; - - // The criterion to use to determine which events should be canceled. - Mode mode; - - // Descriptive reason for the cancelation. - const char* reason; - - // The specific keycode of the key event to cancel, or -1 to cancel any key event. - int32_t keyCode; - - // The specific device id of events to cancel, or -1 to cancel events from any device. - int32_t deviceId; - - CancelationOptions(Mode mode, const char* reason) : - mode(mode), reason(reason), keyCode(-1), deviceId(-1) { } - }; - - /* Tracks dispatched key and motion event state so that cancelation events can be - * synthesized when events are dropped. */ - class InputState { - public: - InputState(); - ~InputState(); - - // Returns true if there is no state to be canceled. - bool isNeutral() const; - - // Returns true if the specified source is known to have received a hover enter - // motion event. - bool isHovering(int32_t deviceId, uint32_t source, int32_t displayId) const; - - // Records tracking information for a key event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackKey(const KeyEntry* entry, int32_t action, int32_t flags); - - // Records tracking information for a motion event that has just been published. - // Returns true if the event should be delivered, false if it is inconsistent - // and should be skipped. - bool trackMotion(const MotionEntry* entry, int32_t action, int32_t flags); - - // Synthesizes cancelation events for the current state and resets the tracked state. - void synthesizeCancelationEvents(nsecs_t currentTime, - Vector& outEvents, const CancelationOptions& options); - - // Clears the current state. - void clear(); - - // Copies pointer-related parts of the input state to another instance. - void copyPointerStateTo(InputState& other) const; - - // Gets the fallback key associated with a keycode. - // Returns -1 if none. - // Returns AKEYCODE_UNKNOWN if we are only dispatching the unhandled key to the policy. - int32_t getFallbackKey(int32_t originalKeyCode); - - // Sets the fallback key for a particular keycode. - void setFallbackKey(int32_t originalKeyCode, int32_t fallbackKeyCode); - - // Removes the fallback key for a particular keycode. - void removeFallbackKey(int32_t originalKeyCode); - - inline const KeyedVector& getFallbackKeys() const { - return mFallbackKeys; - } - - private: - struct KeyMemento { - int32_t deviceId; - uint32_t source; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t flags; - nsecs_t downTime; - uint32_t policyFlags; - }; - - struct MotionMemento { - int32_t deviceId; - uint32_t source; - int32_t flags; - float xPrecision; - float yPrecision; - nsecs_t downTime; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - bool hovering; - uint32_t policyFlags; - - void setPointers(const MotionEntry* entry); - }; - - Vector mKeyMementos; - Vector mMotionMementos; - KeyedVector mFallbackKeys; - - ssize_t findKeyMemento(const KeyEntry* entry) const; - ssize_t findMotionMemento(const MotionEntry* entry, bool hovering) const; - - void addKeyMemento(const KeyEntry* entry, int32_t flags); - void addMotionMemento(const MotionEntry* entry, int32_t flags, bool hovering); - - static bool shouldCancelKey(const KeyMemento& memento, - const CancelationOptions& options); - static bool shouldCancelMotion(const MotionMemento& memento, - const CancelationOptions& options); - }; - - /* Manages the dispatch state associated with a single input channel. */ - class Connection : public RefBase { - protected: - virtual ~Connection(); - - public: - enum Status { - // Everything is peachy. - STATUS_NORMAL, - // An unrecoverable communication error has occurred. - STATUS_BROKEN, - // The input channel has been unregistered. - STATUS_ZOMBIE - }; - - Status status; - sp inputChannel; // never null - sp inputWindowHandle; // may be null - bool monitor; - InputPublisher inputPublisher; - InputState inputState; - - // True if the socket is full and no further events can be published until - // the application consumes some of the input. - bool inputPublisherBlocked; - - // Queue of events that need to be published to the connection. - Queue outboundQueue; - - // Queue of events that have been published to the connection but that have not - // yet received a "finished" response from the application. - Queue waitQueue; - - explicit Connection(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor); - - inline const char* getInputChannelName() const { return inputChannel->getName().string(); } - - const char* getWindowName() const; - const char* getStatusLabel() const; - - DispatchEntry* findWaitQueueEntry(uint32_t seq); - }; - - enum DropReason { - DROP_REASON_NOT_DROPPED = 0, - DROP_REASON_POLICY = 1, - DROP_REASON_APP_SWITCH = 2, - DROP_REASON_DISABLED = 3, - DROP_REASON_BLOCKED = 4, - DROP_REASON_STALE = 5, - }; - - sp mPolicy; - InputDispatcherConfiguration mConfig; - - Mutex mLock; - - Condition mDispatcherIsAliveCondition; - - sp mLooper; - - EventEntry* mPendingEvent; - Queue mInboundQueue; - Queue mCommandQueue; - - void dispatchOnceInnerLocked(nsecs_t* nextWakeupTime); - - // Enqueues an inbound event. Returns true if mLooper->wake() should be called. - bool enqueueInboundEventLocked(EventEntry* entry); - - // Cleans up input state when dropping an inbound event. - void dropInboundEventLocked(EventEntry* entry, DropReason dropReason); - - // App switch latency optimization. - bool mAppSwitchSawKeyDown; - nsecs_t mAppSwitchDueTime; - - static bool isAppSwitchKeyCode(int32_t keyCode); - bool isAppSwitchKeyEventLocked(KeyEntry* keyEntry); - bool isAppSwitchPendingLocked(); - void resetPendingAppSwitchLocked(bool handled); - - // Stale event latency optimization. - static bool isStaleEventLocked(nsecs_t currentTime, EventEntry* entry); - - // Blocked event latency optimization. Drops old events when the user intends - // to transfer focus to a new application. - EventEntry* mNextUnblockedEvent; - - sp findTouchedWindowAtLocked(int32_t displayId, int32_t x, int32_t y); - - // All registered connections mapped by channel file descriptor. - KeyedVector > mConnectionsByFd; - - ssize_t getConnectionIndexLocked(const sp& inputChannel); - - // Input channels that will receive a copy of all input events. - Vector > mMonitoringChannels; - - // Event injection and synchronization. - Condition mInjectionResultAvailableCondition; - bool hasInjectionPermission(int32_t injectorPid, int32_t injectorUid); - void setInjectionResultLocked(EventEntry* entry, int32_t injectionResult); - - Condition mInjectionSyncFinishedCondition; - void incrementPendingForegroundDispatchesLocked(EventEntry* entry); - void decrementPendingForegroundDispatchesLocked(EventEntry* entry); - - // Key repeat tracking. - struct KeyRepeatState { - KeyEntry* lastKeyEntry; // or null if no repeat - nsecs_t nextRepeatTime; - } mKeyRepeatState; - - void resetKeyRepeatLocked(); - KeyEntry* synthesizeKeyRepeatLocked(nsecs_t currentTime); - - // Deferred command processing. - bool haveCommandsLocked() const; - bool runCommandsLockedInterruptible(); - CommandEntry* postCommandLocked(Command command); - - // Input filter processing. - bool shouldSendKeyToInputFilterLocked(const NotifyKeyArgs* args); - bool shouldSendMotionToInputFilterLocked(const NotifyMotionArgs* args); - - // Inbound event processing. - void drainInboundQueueLocked(); - void releasePendingEventLocked(); - void releaseInboundEventLocked(EventEntry* entry); - - // Dispatch state. - bool mDispatchEnabled; - bool mDispatchFrozen; - bool mInputFilterEnabled; - - Vector > mWindowHandles; - - sp getWindowHandleLocked(const sp& inputChannel) const; - bool hasWindowHandleLocked(const sp& windowHandle) const; - - // Focus tracking for keys, trackball, etc. - sp mFocusedWindowHandle; - - // Focus tracking for touch. - struct TouchedWindow { - sp windowHandle; - int32_t targetFlags; - BitSet32 pointerIds; // zero unless target flag FLAG_SPLIT is set - }; - struct TouchState { - bool down; - bool split; - int32_t deviceId; // id of the device that is currently down, others are rejected - uint32_t source; // source of the device that is current down, others are rejected - int32_t displayId; // id to the display that currently has a touch, others are rejected - Vector windows; - - TouchState(); - ~TouchState(); - void reset(); - void copyFrom(const TouchState& other); - void addOrUpdateWindow(const sp& windowHandle, - int32_t targetFlags, BitSet32 pointerIds); - void removeWindow(const sp& windowHandle); - void filterNonAsIsTouchWindows(); - sp getFirstForegroundWindowHandle() const; - bool isSlippery() const; - }; - - TouchState mTouchState; - TouchState mTempTouchState; - - // Focused application. - sp mFocusedApplicationHandle; - - // Dispatcher state at time of last ANR. - String8 mLastANRState; - - // Dispatch inbound events. - bool dispatchConfigurationChangedLocked( - nsecs_t currentTime, ConfigurationChangedEntry* entry); - bool dispatchDeviceResetLocked( - nsecs_t currentTime, DeviceResetEntry* entry); - bool dispatchKeyLocked( - nsecs_t currentTime, KeyEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime); - bool dispatchMotionLocked( - nsecs_t currentTime, MotionEntry* entry, - DropReason* dropReason, nsecs_t* nextWakeupTime); - void dispatchEventLocked(nsecs_t currentTime, EventEntry* entry, - const Vector& inputTargets); - - void logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry); - void logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry); - - // Keeping track of ANR timeouts. - enum InputTargetWaitCause { - INPUT_TARGET_WAIT_CAUSE_NONE, - INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY, - INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY, - }; - - InputTargetWaitCause mInputTargetWaitCause; - nsecs_t mInputTargetWaitStartTime; - nsecs_t mInputTargetWaitTimeoutTime; - bool mInputTargetWaitTimeoutExpired; - sp mInputTargetWaitApplicationHandle; - - // Contains the last window which received a hover event. - sp mLastHoverWindowHandle; - - // Finding targets for input events. - int32_t handleTargetsNotReadyLocked(nsecs_t currentTime, const EventEntry* entry, - const sp& applicationHandle, - const sp& windowHandle, - nsecs_t* nextWakeupTime, const char* reason); - void resumeAfterTargetsNotReadyTimeoutLocked(nsecs_t newTimeout, - const sp& inputChannel); - nsecs_t getTimeSpentWaitingForApplicationLocked(nsecs_t currentTime); - void resetANRTimeoutsLocked(); - - int32_t findFocusedWindowTargetsLocked(nsecs_t currentTime, const EventEntry* entry, - Vector& inputTargets, nsecs_t* nextWakeupTime); - int32_t findTouchedWindowTargetsLocked(nsecs_t currentTime, const MotionEntry* entry, - Vector& inputTargets, nsecs_t* nextWakeupTime, - bool* outConflictingPointerActions); - - void addWindowTargetLocked(const sp& windowHandle, - int32_t targetFlags, BitSet32 pointerIds, Vector& inputTargets); - void addMonitoringTargetsLocked(Vector& inputTargets); - - void pokeUserActivityLocked(const EventEntry* eventEntry); - bool checkInjectionPermission(const sp& windowHandle, - const InjectionState* injectionState); - bool isWindowObscuredAtPointLocked(const sp& windowHandle, - int32_t x, int32_t y) const; - bool isWindowReadyForMoreInputLocked(nsecs_t currentTime, - const sp& windowHandle, const EventEntry* eventEntry); - String8 getApplicationWindowLabelLocked(const sp& applicationHandle, - const sp& windowHandle); - - // Manage the dispatch cycle for a single connection. - // These methods are deliberately not Interruptible because doing all of the work - // with the mutex held makes it easier to ensure that connection invariants are maintained. - // If needed, the methods post commands to run later once the critical bits are done. - void prepareDispatchCycleLocked(nsecs_t currentTime, const sp& connection, - EventEntry* eventEntry, const InputTarget* inputTarget); - void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp& connection, - EventEntry* eventEntry, const InputTarget* inputTarget); - void enqueueDispatchEntryLocked(const sp& connection, - EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode); - void startDispatchCycleLocked(nsecs_t currentTime, const sp& connection); - void finishDispatchCycleLocked(nsecs_t currentTime, const sp& connection, - uint32_t seq, bool handled); - void abortBrokenDispatchCycleLocked(nsecs_t currentTime, const sp& connection, - bool notify); - void drainDispatchQueueLocked(Queue* queue); - void releaseDispatchEntryLocked(DispatchEntry* dispatchEntry); - static int handleReceiveCallback(int fd, int events, void* data); - - void synthesizeCancelationEventsForAllConnectionsLocked( - const CancelationOptions& options); - void synthesizeCancelationEventsForInputChannelLocked(const sp& channel, - const CancelationOptions& options); - void synthesizeCancelationEventsForConnectionLocked(const sp& connection, - const CancelationOptions& options); - - // Splitting motion events across windows. - MotionEntry* splitMotionEvent(const MotionEntry* originalMotionEntry, BitSet32 pointerIds); - - // Reset and drop everything the dispatcher is doing. - void resetAndDropEverythingLocked(const char* reason); - - // Dump state. - void dumpDispatchStateLocked(String8& dump); - void logDispatchStateLocked(); - - // Registration. - void removeMonitorChannelLocked(const sp& inputChannel); - status_t unregisterInputChannelLocked(const sp& inputChannel, bool notify); - - // Add or remove a connection to the mActiveConnections vector. - void activateConnectionLocked(Connection* connection); - void deactivateConnectionLocked(Connection* connection); - - // Interesting events that we might like to log or tell the framework about. - void onDispatchCycleFinishedLocked( - nsecs_t currentTime, const sp& connection, uint32_t seq, bool handled); - void onDispatchCycleBrokenLocked( - nsecs_t currentTime, const sp& connection); - void onANRLocked( - nsecs_t currentTime, const sp& applicationHandle, - const sp& windowHandle, - nsecs_t eventTime, nsecs_t waitStartTime, const char* reason); - - // Outbound policy interactions. - void doNotifyConfigurationChangedInterruptible(CommandEntry* commandEntry); - void doNotifyInputChannelBrokenLockedInterruptible(CommandEntry* commandEntry); - void doNotifyANRLockedInterruptible(CommandEntry* commandEntry); - void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry); - void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry); - bool afterKeyEventLockedInterruptible(const sp& connection, - DispatchEntry* dispatchEntry, KeyEntry* keyEntry, bool handled); - bool afterMotionEventLockedInterruptible(const sp& connection, - DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled); - void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry); - void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry); - - // Statistics gathering. - void updateDispatchStatisticsLocked(nsecs_t currentTime, const EventEntry* entry, - int32_t injectionResult, nsecs_t timeSpentWaitingForApplication); - void traceInboundQueueLengthLocked(); - void traceOutboundQueueLengthLocked(const sp& connection); - void traceWaitQueueLengthLocked(const sp& connection); -}; - -/* Enqueues and dispatches input events, endlessly. */ -class InputDispatcherThread : public Thread { -public: - explicit InputDispatcherThread(const sp& dispatcher); - ~InputDispatcherThread(); - -private: - virtual bool threadLoop(); - - sp mDispatcher; -}; - -} // namespace android - -#endif // _UI_INPUT_DISPATCHER_H diff --git a/widget/gonk/libui/InputListener.cpp b/widget/gonk/libui/InputListener.cpp deleted file mode 100644 index 3b673f0ad..000000000 --- a/widget/gonk/libui/InputListener.cpp +++ /dev/null @@ -1,182 +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. - */ - -#define LOG_TAG "InputListener" - -//#define LOG_NDEBUG 0 - -#include "InputListener.h" - -#include "cutils_log.h" - -namespace android { - -// --- NotifyConfigurationChangedArgs --- - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs(nsecs_t eventTime) : - eventTime(eventTime) { -} - -NotifyConfigurationChangedArgs::NotifyConfigurationChangedArgs( - const NotifyConfigurationChangedArgs& other) : - eventTime(other.eventTime) { -} - -void NotifyConfigurationChangedArgs::notify(const sp& listener) const { - listener->notifyConfigurationChanged(this); -} - - -// --- NotifyKeyArgs --- - -NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime) : - eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), keyCode(keyCode), scanCode(scanCode), - metaState(metaState), downTime(downTime) { -} - -NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), - policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - keyCode(other.keyCode), scanCode(other.scanCode), - metaState(other.metaState), downTime(other.downTime) { -} - -void NotifyKeyArgs::notify(const sp& listener) const { - listener->notifyKey(this); -} - - -// --- NotifyMotionArgs --- - -NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, - uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime) : - eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags), - action(action), flags(flags), metaState(metaState), buttonState(buttonState), - edgeFlags(edgeFlags), displayId(displayId), pointerCount(pointerCount), - xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) { - for (uint32_t i = 0; i < pointerCount; i++) { - this->pointerProperties[i].copyFrom(pointerProperties[i]); - this->pointerCoords[i].copyFrom(pointerCoords[i]); - } -} - -NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId), source(other.source), - policyFlags(other.policyFlags), - action(other.action), flags(other.flags), - metaState(other.metaState), buttonState(other.buttonState), - edgeFlags(other.edgeFlags), displayId(other.displayId), - pointerCount(other.pointerCount), - xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) { - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - } -} - -void NotifyMotionArgs::notify(const sp& listener) const { - listener->notifyMotion(this); -} - - -// --- NotifySwitchArgs --- - -NotifySwitchArgs::NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask) : - eventTime(eventTime), policyFlags(policyFlags), - switchValues(switchValues), switchMask(switchMask) { -} - -NotifySwitchArgs::NotifySwitchArgs(const NotifySwitchArgs& other) : - eventTime(other.eventTime), policyFlags(other.policyFlags), - switchValues(other.switchValues), switchMask(other.switchMask) { -} - -void NotifySwitchArgs::notify(const sp& listener) const { - listener->notifySwitch(this); -} - - -// --- NotifyDeviceResetArgs --- - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId) : - eventTime(eventTime), deviceId(deviceId) { -} - -NotifyDeviceResetArgs::NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other) : - eventTime(other.eventTime), deviceId(other.deviceId) { -} - -void NotifyDeviceResetArgs::notify(const sp& listener) const { - listener->notifyDeviceReset(this); -} - - -// --- QueuedInputListener --- - -QueuedInputListener::QueuedInputListener(const sp& innerListener) : - mInnerListener(innerListener) { -} - -QueuedInputListener::~QueuedInputListener() { - size_t count = mArgsQueue.size(); - for (size_t i = 0; i < count; i++) { - delete mArgsQueue[i]; - } -} - -void QueuedInputListener::notifyConfigurationChanged( - const NotifyConfigurationChangedArgs* args) { - mArgsQueue.push(new NotifyConfigurationChangedArgs(*args)); -} - -void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) { - mArgsQueue.push(new NotifyKeyArgs(*args)); -} - -void QueuedInputListener::notifyMotion(const NotifyMotionArgs* args) { - mArgsQueue.push(new NotifyMotionArgs(*args)); -} - -void QueuedInputListener::notifySwitch(const NotifySwitchArgs* args) { - mArgsQueue.push(new NotifySwitchArgs(*args)); -} - -void QueuedInputListener::notifyDeviceReset(const NotifyDeviceResetArgs* args) { - mArgsQueue.push(new NotifyDeviceResetArgs(*args)); -} - -void QueuedInputListener::flush() { - size_t count = mArgsQueue.size(); - for (size_t i = 0; i < count; i++) { - NotifyArgs* args = mArgsQueue[i]; - args->notify(mInnerListener); - delete args; - } - mArgsQueue.clear(); -} - - -} // namespace android diff --git a/widget/gonk/libui/InputListener.h b/widget/gonk/libui/InputListener.h deleted file mode 100644 index de799322f..000000000 --- a/widget/gonk/libui/InputListener.h +++ /dev/null @@ -1,196 +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. - */ - -#ifndef _UI_INPUT_LISTENER_H -#define _UI_INPUT_LISTENER_H - -#include "Input.h" -#include -#include - -namespace android { - -class InputListenerInterface; - - -/* Superclass of all input event argument objects */ -struct NotifyArgs { - virtual ~NotifyArgs() { } - - virtual void notify(const sp& listener) const = 0; -}; - - -/* Describes a configuration change event. */ -struct NotifyConfigurationChangedArgs : public NotifyArgs { - nsecs_t eventTime; - - inline NotifyConfigurationChangedArgs() { } - - NotifyConfigurationChangedArgs(nsecs_t eventTime); - - NotifyConfigurationChangedArgs(const NotifyConfigurationChangedArgs& other); - - virtual ~NotifyConfigurationChangedArgs() { } - - virtual void notify(const sp& listener) const; -}; - - -/* Describes a key event. */ -struct NotifyKeyArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - nsecs_t downTime; - - inline NotifyKeyArgs() { } - - NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, - int32_t metaState, nsecs_t downTime); - - NotifyKeyArgs(const NotifyKeyArgs& other); - - virtual ~NotifyKeyArgs() { } - - virtual void notify(const sp& listener) const; -}; - - -/* Describes a motion event. */ -struct NotifyMotionArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - uint32_t source; - uint32_t policyFlags; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - int32_t displayId; - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - float xPrecision; - float yPrecision; - nsecs_t downTime; - - inline NotifyMotionArgs() { } - - NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, int32_t displayId, uint32_t pointerCount, - const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, - float xPrecision, float yPrecision, nsecs_t downTime); - - NotifyMotionArgs(const NotifyMotionArgs& other); - - virtual ~NotifyMotionArgs() { } - - virtual void notify(const sp& listener) const; -}; - - -/* Describes a switch event. */ -struct NotifySwitchArgs : public NotifyArgs { - nsecs_t eventTime; - uint32_t policyFlags; - uint32_t switchValues; - uint32_t switchMask; - - inline NotifySwitchArgs() { } - - NotifySwitchArgs(nsecs_t eventTime, uint32_t policyFlags, - uint32_t switchValues, uint32_t switchMask); - - NotifySwitchArgs(const NotifySwitchArgs& other); - - virtual ~NotifySwitchArgs() { } - - virtual void notify(const sp& listener) const; -}; - - -/* Describes a device reset event, such as when a device is added, - * reconfigured, or removed. */ -struct NotifyDeviceResetArgs : public NotifyArgs { - nsecs_t eventTime; - int32_t deviceId; - - inline NotifyDeviceResetArgs() { } - - NotifyDeviceResetArgs(nsecs_t eventTime, int32_t deviceId); - - NotifyDeviceResetArgs(const NotifyDeviceResetArgs& other); - - virtual ~NotifyDeviceResetArgs() { } - - virtual void notify(const sp& listener) const; -}; - - -/* - * The interface used by the InputReader to notify the InputListener about input events. - */ -class InputListenerInterface : public virtual RefBase { -protected: - InputListenerInterface() { } - virtual ~InputListenerInterface() { } - -public: - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args) = 0; - virtual void notifyKey(const NotifyKeyArgs* args) = 0; - virtual void notifyMotion(const NotifyMotionArgs* args) = 0; - virtual void notifySwitch(const NotifySwitchArgs* args) = 0; - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args) = 0; -}; - - -/* - * An implementation of the listener interface that queues up and defers dispatch - * of decoded events until flushed. - */ -class QueuedInputListener : public InputListenerInterface { -protected: - virtual ~QueuedInputListener(); - -public: - QueuedInputListener(const sp& innerListener); - - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - void flush(); - -private: - sp mInnerListener; - Vector mArgsQueue; -}; - -} // namespace android - -#endif // _UI_INPUT_LISTENER_H diff --git a/widget/gonk/libui/InputManager.cpp b/widget/gonk/libui/InputManager.cpp deleted file mode 100644 index 91af056bf..000000000 --- a/widget/gonk/libui/InputManager.cpp +++ /dev/null @@ -1,93 +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. - */ - -#define LOG_TAG "InputManager" - -//#define LOG_NDEBUG 0 - -#include "InputManager.h" - -#include "cutils_log.h" - -namespace android { - -InputManager::InputManager( - const sp& eventHub, - const sp& readerPolicy, - const sp& dispatcherPolicy) { - mDispatcher = new InputDispatcher(dispatcherPolicy); - mReader = new InputReader(eventHub, readerPolicy, mDispatcher); - initialize(); -} - -InputManager::InputManager( - const sp& reader, - const sp& dispatcher) : - mReader(reader), - mDispatcher(dispatcher) { - initialize(); -} - -InputManager::~InputManager() { - stop(); -} - -void InputManager::initialize() { - mReaderThread = new InputReaderThread(mReader); - mDispatcherThread = new InputDispatcherThread(mDispatcher); -} - -status_t InputManager::start() { - status_t result = mDispatcherThread->run("InputDispatcher", PRIORITY_URGENT_DISPLAY); - if (result) { - ALOGE("Could not start InputDispatcher thread due to error %d.", result); - return result; - } - - result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); - if (result) { - ALOGE("Could not start InputReader thread due to error %d.", result); - - mDispatcherThread->requestExit(); - return result; - } - - return OK; -} - -status_t InputManager::stop() { - status_t result = mReaderThread->requestExitAndWait(); - if (result) { - ALOGW("Could not stop InputReader thread due to error %d.", result); - } - - result = mDispatcherThread->requestExitAndWait(); - if (result) { - ALOGW("Could not stop InputDispatcher thread due to error %d.", result); - } - - return OK; -} - -sp InputManager::getReader() { - return mReader; -} - -sp InputManager::getDispatcher() { - return mDispatcher; -} - -} // namespace android diff --git a/widget/gonk/libui/InputManager.h b/widget/gonk/libui/InputManager.h deleted file mode 100644 index 15a5176ec..000000000 --- a/widget/gonk/libui/InputManager.h +++ /dev/null @@ -1,109 +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. - */ - -#ifndef _UI_INPUT_MANAGER_H -#define _UI_INPUT_MANAGER_H - -/** - * Native input manager. - */ - -#include "EventHub.h" -#include "InputReader.h" -#include "InputDispatcher.h" - -#include "Input.h" -#include "InputTransport.h" -#include -#include -#include -#include -#include - -namespace android { - -/* - * The input manager is the core of the system event processing. - * - * The input manager uses two threads. - * - * 1. The InputReaderThread (called "InputReader") reads and preprocesses raw input events, - * applies policy, and posts messages to a queue managed by the DispatcherThread. - * 2. The InputDispatcherThread (called "InputDispatcher") thread waits for new events on the - * queue and asynchronously dispatches them to applications. - * - * By design, the InputReaderThread class and InputDispatcherThread class do not share any - * internal state. Moreover, all communication is done one way from the InputReaderThread - * into the InputDispatcherThread and never the reverse. Both classes may interact with the - * InputDispatchPolicy, however. - * - * The InputManager class never makes any calls into Java itself. Instead, the - * InputDispatchPolicy is responsible for performing all external interactions with the - * system, including calling DVM services. - */ -class InputManagerInterface : public virtual RefBase { -protected: - InputManagerInterface() { } - virtual ~InputManagerInterface() { } - -public: - /* Starts the input manager threads. */ - virtual status_t start() = 0; - - /* Stops the input manager threads and waits for them to exit. */ - virtual status_t stop() = 0; - - /* Gets the input reader. */ - virtual sp getReader() = 0; - - /* Gets the input dispatcher. */ - virtual sp getDispatcher() = 0; -}; - -class InputManager : public InputManagerInterface { -protected: - virtual ~InputManager(); - -public: - InputManager( - const sp& eventHub, - const sp& readerPolicy, - const sp& dispatcherPolicy); - - // (used for testing purposes) - InputManager( - const sp& reader, - const sp& dispatcher); - - virtual status_t start(); - virtual status_t stop(); - - virtual sp getReader(); - virtual sp getDispatcher(); - -private: - sp mReader; - sp mReaderThread; - - sp mDispatcher; - sp mDispatcherThread; - - void initialize(); -}; - -} // namespace android - -#endif // _UI_INPUT_MANAGER_H diff --git a/widget/gonk/libui/InputReader.cpp b/widget/gonk/libui/InputReader.cpp deleted file mode 100644 index 3699569aa..000000000 --- a/widget/gonk/libui/InputReader.cpp +++ /dev/null @@ -1,6510 +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. - */ - -#define LOG_TAG "InputReader" - -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -// Log debug messages for each raw event received from the EventHub. -#define DEBUG_RAW_EVENTS 0 - -// Log debug messages about touch screen filtering hacks. -#define DEBUG_HACKS 0 - -// Log debug messages about virtual key processing. -#define DEBUG_VIRTUAL_KEYS 0 - -// Log debug messages about pointers. -#define DEBUG_POINTERS 0 - -// Log debug messages about pointer assignment calculations. -#define DEBUG_POINTER_ASSIGNMENT 0 - -// Log debug messages about gesture detection. -#define DEBUG_GESTURES 0 - -// Log debug messages about the vibrator. -#define DEBUG_VIBRATOR 0 - -#include "InputReader.h" - -#include "Keyboard.h" -#include "VirtualKeyMap.h" - -#include -#include -#include -#include -#include -#include - -#define INDENT " " -#define INDENT2 " " -#define INDENT3 " " -#define INDENT4 " " -#define INDENT5 " " - -namespace android { - -// --- Constants --- - -// Maximum number of slots supported when using the slot-based Multitouch Protocol B. -static const size_t MAX_SLOTS = 32; - -// --- Static Functions --- - -template -inline static T abs(const T& value) { - return value < 0 ? - value : value; -} - -template -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -template -inline static void swap(T& a, T& b) { - T temp = a; - a = b; - b = temp; -} - -inline static float avg(float x, float y) { - return (x + y) / 2; -} - -inline static float distance(float x1, float y1, float x2, float y2) { - return hypotf(x1 - x2, y1 - y2); -} - -inline static int32_t signExtendNybble(int32_t value) { - return value >= 8 ? value - 16 : value; -} - -static inline const char* toString(bool value) { - return value ? "true" : "false"; -} - -static int32_t rotateValueUsingRotationMap(int32_t value, int32_t orientation, - const int32_t map[][4], size_t mapSize) { - if (orientation != DISPLAY_ORIENTATION_0) { - for (size_t i = 0; i < mapSize; i++) { - if (value == map[i][0]) { - return map[i][orientation]; - } - } - } - return value; -} - -static const int32_t keyCodeRotationMap[][4] = { - // key codes enumerated counter-clockwise with the original (unrotated) key first - // no rotation, 90 degree rotation, 180 degree rotation, 270 degree rotation - { AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT }, - { AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN }, - { AKEYCODE_DPAD_UP, AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT }, - { AKEYCODE_DPAD_LEFT, AKEYCODE_DPAD_DOWN, AKEYCODE_DPAD_RIGHT, AKEYCODE_DPAD_UP }, -}; -static const size_t keyCodeRotationMapSize = - sizeof(keyCodeRotationMap) / sizeof(keyCodeRotationMap[0]); - -static int32_t rotateKeyCode(int32_t keyCode, int32_t orientation) { - return rotateValueUsingRotationMap(keyCode, orientation, - keyCodeRotationMap, keyCodeRotationMapSize); -} - -static void rotateDelta(int32_t orientation, float* deltaX, float* deltaY) { - float temp; - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = *deltaX; - *deltaX = *deltaY; - *deltaY = -temp; - break; - - case DISPLAY_ORIENTATION_180: - *deltaX = -*deltaX; - *deltaY = -*deltaY; - break; - - case DISPLAY_ORIENTATION_270: - temp = *deltaX; - *deltaX = -*deltaY; - *deltaY = temp; - break; - } -} - -static inline bool sourcesMatchMask(uint32_t sources, uint32_t sourceMask) { - return (sources & sourceMask & ~ AINPUT_SOURCE_CLASS_MASK) != 0; -} - -// Returns true if the pointer should be reported as being down given the specified -// button states. This determines whether the event is reported as a touch event. -static bool isPointerDown(int32_t buttonState) { - return buttonState & - (AMOTION_EVENT_BUTTON_PRIMARY | AMOTION_EVENT_BUTTON_SECONDARY - | AMOTION_EVENT_BUTTON_TERTIARY); -} - -static float calculateCommonVector(float a, float b) { - if (a > 0 && b > 0) { - return a < b ? a : b; - } else if (a < 0 && b < 0) { - return a > b ? a : b; - } else { - return 0; - } -} - -static void synthesizeButtonKey(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState, - int32_t buttonState, int32_t keyCode) { - if ( - (action == AKEY_EVENT_ACTION_DOWN - && !(lastButtonState & buttonState) - && (currentButtonState & buttonState)) - || (action == AKEY_EVENT_ACTION_UP - && (lastButtonState & buttonState) - && !(currentButtonState & buttonState))) { - NotifyKeyArgs args(when, deviceId, source, policyFlags, - action, 0, keyCode, 0, context->getGlobalMetaState(), when); - context->getListener()->notifyKey(&args); - } -} - -static void synthesizeButtonKeys(InputReaderContext* context, int32_t action, - nsecs_t when, int32_t deviceId, uint32_t source, - uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) { - synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK); - synthesizeButtonKey(context, action, when, deviceId, source, policyFlags, - lastButtonState, currentButtonState, - AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD); -} - - -// --- InputReaderConfiguration --- - -bool InputReaderConfiguration::getDisplayInfo(bool external, DisplayViewport* outViewport) const { - const DisplayViewport& viewport = external ? mExternalDisplay : mInternalDisplay; - if (viewport.displayId >= 0) { - *outViewport = viewport; - return true; - } - return false; -} - -void InputReaderConfiguration::setDisplayInfo(bool external, const DisplayViewport& viewport) { - DisplayViewport& v = external ? mExternalDisplay : mInternalDisplay; - v = viewport; -} - - -// --- InputReader --- - -InputReader::InputReader(const sp& eventHub, - const sp& policy, - const sp& listener) : - mContext(this), mEventHub(eventHub), mPolicy(policy), - mGlobalMetaState(0), mGeneration(1), - mDisableVirtualKeysTimeout(LLONG_MIN), mNextTimeout(LLONG_MAX), - mConfigurationChangesToRefresh(0) { - mQueuedListener = new QueuedInputListener(listener); - - { // acquire lock - AutoMutex _l(mLock); - - refreshConfigurationLocked(0); - updateGlobalMetaStateLocked(); - } // release lock -} - -InputReader::~InputReader() { - for (size_t i = 0; i < mDevices.size(); i++) { - delete mDevices.valueAt(i); - } -} - -void InputReader::loopOnce() { - int32_t oldGeneration; - int32_t timeoutMillis; - bool inputDevicesChanged = false; - Vector inputDevices; - { // acquire lock - AutoMutex _l(mLock); - - oldGeneration = mGeneration; - timeoutMillis = -1; - - uint32_t changes = mConfigurationChangesToRefresh; - if (changes) { - mConfigurationChangesToRefresh = 0; - timeoutMillis = 0; - refreshConfigurationLocked(changes); - } else if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout); - } - } // release lock - - size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE); - - { // acquire lock - AutoMutex _l(mLock); - mReaderIsAliveCondition.broadcast(); - - if (count) { - processEventsLocked(mEventBuffer, count); - } - - if (mNextTimeout != LLONG_MAX) { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - if (now >= mNextTimeout) { -#if DEBUG_RAW_EVENTS - ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f); -#endif - mNextTimeout = LLONG_MAX; - timeoutExpiredLocked(now); - } - } - - if (oldGeneration != mGeneration) { - inputDevicesChanged = true; - getInputDevicesLocked(inputDevices); - } - } // release lock - - // Send out a message that the describes the changed input devices. - if (inputDevicesChanged) { - mPolicy->notifyInputDevicesChanged(inputDevices); - } - - // Flush queued events out to the listener. - // This must happen outside of the lock because the listener could potentially call - // back into the InputReader's methods, such as getScanCodeState, or become blocked - // on another thread similarly waiting to acquire the InputReader lock thereby - // resulting in a deadlock. This situation is actually quite plausible because the - // listener is actually the input dispatcher, which calls into the window manager, - // which occasionally calls into the input reader. - mQueuedListener->flush(); -} - -void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) { - for (const RawEvent* rawEvent = rawEvents; count;) { - int32_t type = rawEvent->type; - size_t batchSize = 1; - if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) { - int32_t deviceId = rawEvent->deviceId; - while (batchSize < count) { - if (rawEvent[batchSize].type >= EventHubInterface::FIRST_SYNTHETIC_EVENT - || rawEvent[batchSize].deviceId != deviceId) { - break; - } - batchSize += 1; - } -#if DEBUG_RAW_EVENTS - ALOGD("BatchSize: %d Count: %d", batchSize, count); -#endif - processEventsForDeviceLocked(deviceId, rawEvent, batchSize); - } else { - switch (rawEvent->type) { - case EventHubInterface::DEVICE_ADDED: - addDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::DEVICE_REMOVED: - removeDeviceLocked(rawEvent->when, rawEvent->deviceId); - break; - case EventHubInterface::FINISHED_DEVICE_SCAN: - handleConfigurationChangedLocked(rawEvent->when); - break; - default: - ALOG_ASSERT(false); // can't happen - break; - } - } - count -= batchSize; - rawEvent += batchSize; - } -} - -void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - ALOGW("Ignoring spurious device added event for deviceId %d.", deviceId); - return; - } - - InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId); - uint32_t classes = mEventHub->getDeviceClasses(deviceId); - - InputDevice* device = createDeviceLocked(deviceId, identifier, classes); - device->configure(when, &mConfig, 0); - device->reset(when); - - if (device->isIgnored()) { - ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId, - identifier.name.string()); - } else { - ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId, - identifier.name.string(), device->getSources()); - } - - mDevices.add(deviceId, device); - bumpGenerationLocked(); -} - -void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { - InputDevice* device = NULL; - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId); - return; - } - - device = mDevices.valueAt(deviceIndex); - mDevices.removeItemsAt(deviceIndex, 1); - bumpGenerationLocked(); - - if (device->isIgnored()) { - ALOGI("Device removed: id=%d, name='%s' (ignored non-input device)", - device->getId(), device->getName().string()); - } else { - ALOGI("Device removed: id=%d, name='%s', sources=0x%08x", - device->getId(), device->getName().string(), device->getSources()); - } - - device->reset(when); - delete device; -} - -InputDevice* InputReader::createDeviceLocked(int32_t deviceId, - const InputDeviceIdentifier& identifier, uint32_t classes) { - InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(), - identifier, classes); - - // External devices. - if (classes & INPUT_DEVICE_CLASS_EXTERNAL) { - device->setExternal(true); - } - - // Switch-like devices. - if (classes & INPUT_DEVICE_CLASS_SWITCH) { - device->addMapper(new SwitchInputMapper(device)); - } - - // Vibrator-like devices. - if (classes & INPUT_DEVICE_CLASS_VIBRATOR) { - device->addMapper(new VibratorInputMapper(device)); - } - - // Keyboard-like devices. - uint32_t keyboardSource = 0; - int32_t keyboardType = AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC; - if (classes & INPUT_DEVICE_CLASS_KEYBOARD) { - keyboardSource |= AINPUT_SOURCE_KEYBOARD; - } - if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) { - keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC; - } - if (classes & INPUT_DEVICE_CLASS_DPAD) { - keyboardSource |= AINPUT_SOURCE_DPAD; - } - if (classes & INPUT_DEVICE_CLASS_GAMEPAD) { - keyboardSource |= AINPUT_SOURCE_GAMEPAD; - } - - if (keyboardSource != 0) { - device->addMapper(new KeyboardInputMapper(device, keyboardSource, keyboardType)); - } - - // Cursor-like devices. - if (classes & INPUT_DEVICE_CLASS_CURSOR) { - device->addMapper(new CursorInputMapper(device)); - } - - // Touchscreens and touchpad devices. - if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) { - device->addMapper(new MultiTouchInputMapper(device)); - } else if (classes & INPUT_DEVICE_CLASS_TOUCH) { - device->addMapper(new SingleTouchInputMapper(device)); - } - - // Joystick-like devices. - if (classes & INPUT_DEVICE_CLASS_JOYSTICK) { - device->addMapper(new JoystickInputMapper(device)); - } - - return device; -} - -void InputReader::processEventsForDeviceLocked(int32_t deviceId, - const RawEvent* rawEvents, size_t count) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex < 0) { - ALOGW("Discarding event for unknown deviceId %d.", deviceId); - return; - } - - InputDevice* device = mDevices.valueAt(deviceIndex); - if (device->isIgnored()) { - //ALOGD("Discarding event for ignored deviceId %d.", deviceId); - return; - } - - device->process(rawEvents, count); -} - -void InputReader::timeoutExpiredLocked(nsecs_t when) { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - device->timeoutExpired(when); - } - } -} - -void InputReader::handleConfigurationChangedLocked(nsecs_t when) { - // Reset global meta state because it depends on the list of all configured devices. - updateGlobalMetaStateLocked(); - - // Enqueue configuration changed. - NotifyConfigurationChangedArgs args(when); - mQueuedListener->notifyConfigurationChanged(&args); -} - -void InputReader::refreshConfigurationLocked(uint32_t changes) { - mPolicy->getReaderConfiguration(&mConfig); - mEventHub->setExcludedDevices(mConfig.excludedDeviceNames); - - if (changes) { - ALOGI("Reconfiguring input devices. changes=0x%08x", changes); - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - if (changes & InputReaderConfiguration::CHANGE_MUST_REOPEN) { - mEventHub->requestReopenDevices(); - } else { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->configure(now, &mConfig, changes); - } - } - } -} - -void InputReader::updateGlobalMetaStateLocked() { - mGlobalMetaState = 0; - - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - mGlobalMetaState |= device->getMetaState(); - } -} - -int32_t InputReader::getGlobalMetaStateLocked() { - return mGlobalMetaState; -} - -void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { - mDisableVirtualKeysTimeout = time; -} - -bool InputReader::shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - if (now < mDisableVirtualKeysTimeout) { - ALOGI("Dropping virtual key from device %s because virtual keys are " - "temporarily disabled for the next %0.3fms. keyCode=%d, scanCode=%d", - device->getName().string(), - (mDisableVirtualKeysTimeout - now) * 0.000001, - keyCode, scanCode); - return true; - } else { - return false; - } -} - -void InputReader::fadePointerLocked() { - for (size_t i = 0; i < mDevices.size(); i++) { - InputDevice* device = mDevices.valueAt(i); - device->fadePointer(); - } -} - -void InputReader::requestTimeoutAtTimeLocked(nsecs_t when) { - if (when < mNextTimeout) { - mNextTimeout = when; - mEventHub->wake(); - } -} - -int32_t InputReader::bumpGenerationLocked() { - return ++mGeneration; -} - -void InputReader::getInputDevices(Vector& outInputDevices) { - AutoMutex _l(mLock); - getInputDevicesLocked(outInputDevices); -} - -void InputReader::getInputDevicesLocked(Vector& outInputDevices) { - outInputDevices.clear(); - - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (!device->isIgnored()) { - outInputDevices.push(); - device->getDeviceInfo(&outInputDevices.editTop()); - } - } -} - -int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState); -} - -int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState); -} - -int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) { - AutoMutex _l(mLock); - - return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState); -} - -int32_t InputReader::getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = (device->*getStateFunc)(sourceMask, code); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - // If any device reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one device reports it. - int32_t currentResult = (device->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - } - return result; -} - -bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - AutoMutex _l(mLock); - - memset(outFlags, 0, numCodes); - return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags); -} - -bool InputReader::markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - if (deviceId >= 0) { - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result = device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } else { - size_t numDevices = mDevices.size(); - for (size_t i = 0; i < numDevices; i++) { - InputDevice* device = mDevices.valueAt(i); - if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) { - result |= device->markSupportedKeyCodes(sourceMask, - numCodes, keyCodes, outFlags); - } - } - } - return result; -} - -void InputReader::requestRefreshConfiguration(uint32_t changes) { - AutoMutex _l(mLock); - - if (changes) { - bool needWake = !mConfigurationChangesToRefresh; - mConfigurationChangesToRefresh |= changes; - - if (needWake) { - mEventHub->wake(); - } - } -} - -void InputReader::vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputReader::cancelVibrate(int32_t deviceId, int32_t token) { - AutoMutex _l(mLock); - - ssize_t deviceIndex = mDevices.indexOfKey(deviceId); - if (deviceIndex >= 0) { - InputDevice* device = mDevices.valueAt(deviceIndex); - device->cancelVibrate(token); - } -} - -void InputReader::dump(String8& dump) { - AutoMutex _l(mLock); - - mEventHub->dump(dump); - dump.append("\n"); - - dump.append("Input Reader State:\n"); - - for (size_t i = 0; i < mDevices.size(); i++) { - mDevices.valueAt(i)->dump(dump); - } - - dump.append(INDENT "Configuration:\n"); - dump.append(INDENT2 "ExcludedDeviceNames: ["); - for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) { - if (i != 0) { - dump.append(", "); - } - dump.append(mConfig.excludedDeviceNames.itemAt(i).string()); - } - dump.append("]\n"); - dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n", - mConfig.virtualKeyQuietTime * 0.000001f); - - dump.appendFormat(INDENT2 "PointerVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.pointerVelocityControlParameters.scale, - mConfig.pointerVelocityControlParameters.lowThreshold, - mConfig.pointerVelocityControlParameters.highThreshold, - mConfig.pointerVelocityControlParameters.acceleration); - - dump.appendFormat(INDENT2 "WheelVelocityControlParameters: " - "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n", - mConfig.wheelVelocityControlParameters.scale, - mConfig.wheelVelocityControlParameters.lowThreshold, - mConfig.wheelVelocityControlParameters.highThreshold, - mConfig.wheelVelocityControlParameters.acceleration); - - dump.appendFormat(INDENT2 "PointerGesture:\n"); - dump.appendFormat(INDENT3 "Enabled: %s\n", - toString(mConfig.pointerGesturesEnabled)); - dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n", - mConfig.pointerGestureQuietInterval * 0.000001f); - dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n", - mConfig.pointerGestureDragMinSwitchSpeed); - dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n", - mConfig.pointerGestureTapInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n", - mConfig.pointerGestureTapDragInterval * 0.000001f); - dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n", - mConfig.pointerGestureTapSlop); - dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n", - mConfig.pointerGestureMultitouchSettleInterval * 0.000001f); - dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n", - mConfig.pointerGestureMultitouchMinDistance); - dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n", - mConfig.pointerGestureSwipeTransitionAngleCosine); - dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n", - mConfig.pointerGestureSwipeMaxWidthRatio); - dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n", - mConfig.pointerGestureMovementSpeedRatio); - dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n", - mConfig.pointerGestureZoomSpeedRatio); -} - -void InputReader::monitor() { - // Acquire and release the lock to ensure that the reader has not deadlocked. - mLock.lock(); - mEventHub->wake(); - mReaderIsAliveCondition.wait(mLock); - mLock.unlock(); - - // Check the EventHub - mEventHub->monitor(); -} - - -// --- InputReader::ContextImpl --- - -InputReader::ContextImpl::ContextImpl(InputReader* reader) : - mReader(reader) { -} - -void InputReader::ContextImpl::updateGlobalMetaState() { - // lock is already held by the input loop - mReader->updateGlobalMetaStateLocked(); -} - -int32_t InputReader::ContextImpl::getGlobalMetaState() { - // lock is already held by the input loop - return mReader->getGlobalMetaStateLocked(); -} - -void InputReader::ContextImpl::disableVirtualKeysUntil(nsecs_t time) { - // lock is already held by the input loop - mReader->disableVirtualKeysUntilLocked(time); -} - -bool InputReader::ContextImpl::shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) { - // lock is already held by the input loop - return mReader->shouldDropVirtualKeyLocked(now, device, keyCode, scanCode); -} - -void InputReader::ContextImpl::fadePointer() { - // lock is already held by the input loop - mReader->fadePointerLocked(); -} - -void InputReader::ContextImpl::requestTimeoutAtTime(nsecs_t when) { - // lock is already held by the input loop - mReader->requestTimeoutAtTimeLocked(when); -} - -int32_t InputReader::ContextImpl::bumpGeneration() { - // lock is already held by the input loop - return mReader->bumpGenerationLocked(); -} - -InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { - return mReader->mPolicy.get(); -} - -InputListenerInterface* InputReader::ContextImpl::getListener() { - return mReader->mQueuedListener.get(); -} - -EventHubInterface* InputReader::ContextImpl::getEventHub() { - return mReader->mEventHub.get(); -} - - -// --- InputReaderThread --- - -InputReaderThread::InputReaderThread(const sp& reader) : - Thread(/*canCallJava*/ true), mReader(reader) { -} - -InputReaderThread::~InputReaderThread() { -} - -bool InputReaderThread::threadLoop() { - mReader->loopOnce(); - return true; -} - - -// --- InputDevice --- - -InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - const InputDeviceIdentifier& identifier, uint32_t classes) : - mContext(context), mId(id), mGeneration(generation), - mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mDropUntilNextSync(false) { -} - -InputDevice::~InputDevice() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - delete mMappers[i]; - } - mMappers.clear(); -} - -void InputDevice::dump(String8& dump) { - InputDeviceInfo deviceInfo; - getDeviceInfo(& deviceInfo); - - dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(), - deviceInfo.getDisplayName().string()); - dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); - dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); - dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); - dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); - - const Vector& ranges = deviceInfo.getMotionRanges(); - if (!ranges.isEmpty()) { - dump.append(INDENT2 "Motion Ranges:\n"); - for (size_t i = 0; i < ranges.size(); i++) { - const InputDeviceInfo::MotionRange& range = ranges.itemAt(i); - const char* label = getAxisLabel(range.axis); - char name[32]; - if (label) { - strncpy(name, label, sizeof(name)); - name[sizeof(name) - 1] = '\0'; - } else { - snprintf(name, sizeof(name), "%d", range.axis); - } - dump.appendFormat(INDENT3 "%s: source=0x%08x, " - "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n", - name, range.source, range.min, range.max, range.flat, range.fuzz, - range.resolution); - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->dump(dump); - } -} - -void InputDevice::addMapper(InputMapper* mapper) { - mMappers.add(mapper); -} - -void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) { - mSources = 0; - - if (!isIgnored()) { - if (!changes) { // first time only - mContext->getEventHub()->getConfiguration(mId, &mConfiguration); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_KEYBOARD_LAYOUTS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - sp keyboardLayout = - mContext->getPolicy()->getKeyboardLayoutOverlay(mIdentifier.descriptor); - if (mContext->getEventHub()->setKeyboardLayoutOverlay(mId, keyboardLayout)) { - bumpGeneration(); - } - } - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DEVICE_ALIAS)) { - if (!(mClasses & INPUT_DEVICE_CLASS_VIRTUAL)) { - String8 alias = mContext->getPolicy()->getDeviceAlias(mIdentifier); - if (mAlias != alias) { - mAlias = alias; - bumpGeneration(); - } - } - } - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->configure(when, config, changes); - mSources |= mapper->getSources(); - } - } -} - -void InputDevice::reset(nsecs_t when) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->reset(when); - } - - mContext->updateGlobalMetaState(); - - notifyReset(when); -} - -void InputDevice::process(const RawEvent* rawEvents, size_t count) { - // Process all of the events in order for each mapper. - // We cannot simply ask each mapper to process them in bulk because mappers may - // have side-effects that must be interleaved. For example, joystick movement events and - // gamepad button presses are handled by different mappers but they should be dispatched - // in the order received. - size_t numMappers = mMappers.size(); - for (const RawEvent* rawEvent = rawEvents; count--; rawEvent++) { -#if DEBUG_RAW_EVENTS - ALOGD("Input event: device=%d type=0x%04x code=0x%04x value=0x%08x when=%lld", - rawEvent->deviceId, rawEvent->type, rawEvent->code, rawEvent->value, - rawEvent->when); -#endif - - if (mDropUntilNextSync) { - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - mDropUntilNextSync = false; -#if DEBUG_RAW_EVENTS - ALOGD("Recovered from input event buffer overrun."); -#endif - } else { -#if DEBUG_RAW_EVENTS - ALOGD("Dropped input event while waiting for next input sync."); -#endif - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_DROPPED) { - ALOGI("Detected input event buffer overrun for device %s.", getName().string()); - mDropUntilNextSync = true; - reset(rawEvent->when); - } else { - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->process(rawEvent); - } - } - } -} - -void InputDevice::timeoutExpired(nsecs_t when) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->timeoutExpired(when); - } -} - -void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { - outDeviceInfo->initialize(mId, mGeneration, mIdentifier, mAlias, mIsExternal); - - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->populateDeviceInfo(outDeviceInfo); - } -} - -int32_t InputDevice::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getState(sourceMask, keyCode, & InputMapper::getKeyCodeState); -} - -int32_t InputDevice::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getState(sourceMask, scanCode, & InputMapper::getScanCodeState); -} - -int32_t InputDevice::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getState(sourceMask, switchCode, & InputMapper::getSwitchState); -} - -int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc) { - int32_t result = AKEY_STATE_UNKNOWN; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - // If any mapper reports AKEY_STATE_DOWN or AKEY_STATE_VIRTUAL, return that - // value. Otherwise, return AKEY_STATE_UP as long as one mapper reports it. - int32_t currentResult = (mapper->*getStateFunc)(sourceMask, code); - if (currentResult >= AKEY_STATE_DOWN) { - return currentResult; - } else if (currentResult == AKEY_STATE_UP) { - result = currentResult; - } - } - } - return result; -} - -bool InputDevice::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - bool result = false; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - if (sourcesMatchMask(mapper->getSources(), sourceMask)) { - result |= mapper->markSupportedKeyCodes(sourceMask, numCodes, keyCodes, outFlags); - } - } - return result; -} - -void InputDevice::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->vibrate(pattern, patternSize, repeat, token); - } -} - -void InputDevice::cancelVibrate(int32_t token) { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->cancelVibrate(token); - } -} - -int32_t InputDevice::getMetaState() { - int32_t result = 0; - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - result |= mapper->getMetaState(); - } - return result; -} - -void InputDevice::fadePointer() { - size_t numMappers = mMappers.size(); - for (size_t i = 0; i < numMappers; i++) { - InputMapper* mapper = mMappers[i]; - mapper->fadePointer(); - } -} - -void InputDevice::bumpGeneration() { - mGeneration = mContext->bumpGeneration(); -} - -void InputDevice::notifyReset(nsecs_t when) { - NotifyDeviceResetArgs args(when, mId); - mContext->getListener()->notifyDeviceReset(&args); -} - - -// --- CursorButtonAccumulator --- - -CursorButtonAccumulator::CursorButtonAccumulator() { - clearButtons(); -} - -void CursorButtonAccumulator::reset(InputDevice* device) { - mBtnLeft = device->isKeyPressed(BTN_LEFT); - mBtnRight = device->isKeyPressed(BTN_RIGHT); - mBtnMiddle = device->isKeyPressed(BTN_MIDDLE); - mBtnBack = device->isKeyPressed(BTN_BACK); - mBtnSide = device->isKeyPressed(BTN_SIDE); - mBtnForward = device->isKeyPressed(BTN_FORWARD); - mBtnExtra = device->isKeyPressed(BTN_EXTRA); - mBtnTask = device->isKeyPressed(BTN_TASK); -} - -void CursorButtonAccumulator::clearButtons() { - mBtnLeft = 0; - mBtnRight = 0; - mBtnMiddle = 0; - mBtnBack = 0; - mBtnSide = 0; - mBtnForward = 0; - mBtnExtra = 0; - mBtnTask = 0; -} - -void CursorButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_LEFT: - mBtnLeft = rawEvent->value; - break; - case BTN_RIGHT: - mBtnRight = rawEvent->value; - break; - case BTN_MIDDLE: - mBtnMiddle = rawEvent->value; - break; - case BTN_BACK: - mBtnBack = rawEvent->value; - break; - case BTN_SIDE: - mBtnSide = rawEvent->value; - break; - case BTN_FORWARD: - mBtnForward = rawEvent->value; - break; - case BTN_EXTRA: - mBtnExtra = rawEvent->value; - break; - case BTN_TASK: - mBtnTask = rawEvent->value; - break; - } - } -} - -uint32_t CursorButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnLeft) { - result |= AMOTION_EVENT_BUTTON_PRIMARY; - } - if (mBtnRight) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnMiddle) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - if (mBtnBack || mBtnSide) { - result |= AMOTION_EVENT_BUTTON_BACK; - } - if (mBtnForward || mBtnExtra) { - result |= AMOTION_EVENT_BUTTON_FORWARD; - } - return result; -} - - -// --- CursorMotionAccumulator --- - -CursorMotionAccumulator::CursorMotionAccumulator() { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorMotionAccumulator::clearRelativeAxes() { - mRelX = 0; - mRelY = 0; -} - -void CursorMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_X: - mRelX = rawEvent->value; - break; - case REL_Y: - mRelY = rawEvent->value; - break; - } - } -} - -void CursorMotionAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- CursorScrollAccumulator --- - -CursorScrollAccumulator::CursorScrollAccumulator() : - mHaveRelWheel(false), mHaveRelHWheel(false) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::configure(InputDevice* device) { - mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL); - mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL); -} - -void CursorScrollAccumulator::reset(InputDevice* device) { - clearRelativeAxes(); -} - -void CursorScrollAccumulator::clearRelativeAxes() { - mRelWheel = 0; - mRelHWheel = 0; -} - -void CursorScrollAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_REL) { - switch (rawEvent->code) { - case REL_WHEEL: - mRelWheel = rawEvent->value; - break; - case REL_HWHEEL: - mRelHWheel = rawEvent->value; - break; - } - } -} - -void CursorScrollAccumulator::finishSync() { - clearRelativeAxes(); -} - - -// --- TouchButtonAccumulator --- - -TouchButtonAccumulator::TouchButtonAccumulator() : - mHaveBtnTouch(false), mHaveStylus(false) { - clearButtons(); -} - -void TouchButtonAccumulator::configure(InputDevice* device) { - mHaveBtnTouch = device->hasKey(BTN_TOUCH); - mHaveStylus = device->hasKey(BTN_TOOL_PEN) - || device->hasKey(BTN_TOOL_RUBBER) - || device->hasKey(BTN_TOOL_BRUSH) - || device->hasKey(BTN_TOOL_PENCIL) - || device->hasKey(BTN_TOOL_AIRBRUSH); -} - -void TouchButtonAccumulator::reset(InputDevice* device) { - mBtnTouch = device->isKeyPressed(BTN_TOUCH); - mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); - mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); - mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); - mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); - mBtnToolBrush = device->isKeyPressed(BTN_TOOL_BRUSH); - mBtnToolPencil = device->isKeyPressed(BTN_TOOL_PENCIL); - mBtnToolAirbrush = device->isKeyPressed(BTN_TOOL_AIRBRUSH); - mBtnToolMouse = device->isKeyPressed(BTN_TOOL_MOUSE); - mBtnToolLens = device->isKeyPressed(BTN_TOOL_LENS); - mBtnToolDoubleTap = device->isKeyPressed(BTN_TOOL_DOUBLETAP); - mBtnToolTripleTap = device->isKeyPressed(BTN_TOOL_TRIPLETAP); - mBtnToolQuadTap = device->isKeyPressed(BTN_TOOL_QUADTAP); -} - -void TouchButtonAccumulator::clearButtons() { - mBtnTouch = 0; - mBtnStylus = 0; - mBtnStylus2 = 0; - mBtnToolFinger = 0; - mBtnToolPen = 0; - mBtnToolRubber = 0; - mBtnToolBrush = 0; - mBtnToolPencil = 0; - mBtnToolAirbrush = 0; - mBtnToolMouse = 0; - mBtnToolLens = 0; - mBtnToolDoubleTap = 0; - mBtnToolTripleTap = 0; - mBtnToolQuadTap = 0; -} - -void TouchButtonAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_KEY) { - switch (rawEvent->code) { - case BTN_TOUCH: - mBtnTouch = rawEvent->value; - break; - case BTN_STYLUS: - mBtnStylus = rawEvent->value; - break; - case BTN_STYLUS2: - mBtnStylus2 = rawEvent->value; - break; - case BTN_TOOL_FINGER: - mBtnToolFinger = rawEvent->value; - break; - case BTN_TOOL_PEN: - mBtnToolPen = rawEvent->value; - break; - case BTN_TOOL_RUBBER: - mBtnToolRubber = rawEvent->value; - break; - case BTN_TOOL_BRUSH: - mBtnToolBrush = rawEvent->value; - break; - case BTN_TOOL_PENCIL: - mBtnToolPencil = rawEvent->value; - break; - case BTN_TOOL_AIRBRUSH: - mBtnToolAirbrush = rawEvent->value; - break; - case BTN_TOOL_MOUSE: - mBtnToolMouse = rawEvent->value; - break; - case BTN_TOOL_LENS: - mBtnToolLens = rawEvent->value; - break; - case BTN_TOOL_DOUBLETAP: - mBtnToolDoubleTap = rawEvent->value; - break; - case BTN_TOOL_TRIPLETAP: - mBtnToolTripleTap = rawEvent->value; - break; - case BTN_TOOL_QUADTAP: - mBtnToolQuadTap = rawEvent->value; - break; - } - } -} - -uint32_t TouchButtonAccumulator::getButtonState() const { - uint32_t result = 0; - if (mBtnStylus) { - result |= AMOTION_EVENT_BUTTON_SECONDARY; - } - if (mBtnStylus2) { - result |= AMOTION_EVENT_BUTTON_TERTIARY; - } - return result; -} - -int32_t TouchButtonAccumulator::getToolType() const { - if (mBtnToolMouse || mBtnToolLens) { - return AMOTION_EVENT_TOOL_TYPE_MOUSE; - } - if (mBtnToolRubber) { - return AMOTION_EVENT_TOOL_TYPE_ERASER; - } - if (mBtnToolPen || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush) { - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - if (mBtnToolFinger || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap) { - return AMOTION_EVENT_TOOL_TYPE_FINGER; - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -bool TouchButtonAccumulator::isToolActive() const { - return mBtnTouch || mBtnToolFinger || mBtnToolPen || mBtnToolRubber - || mBtnToolBrush || mBtnToolPencil || mBtnToolAirbrush - || mBtnToolMouse || mBtnToolLens - || mBtnToolDoubleTap || mBtnToolTripleTap || mBtnToolQuadTap; -} - -bool TouchButtonAccumulator::isHovering() const { - return mHaveBtnTouch && !mBtnTouch; -} - -bool TouchButtonAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- RawPointerAxes --- - -RawPointerAxes::RawPointerAxes() { - clear(); -} - -void RawPointerAxes::clear() { - x.clear(); - y.clear(); - pressure.clear(); - touchMajor.clear(); - touchMinor.clear(); - toolMajor.clear(); - toolMinor.clear(); - orientation.clear(); - distance.clear(); - tiltX.clear(); - tiltY.clear(); - trackingId.clear(); - slot.clear(); -} - - -// --- RawPointerData --- - -RawPointerData::RawPointerData() { - clear(); -} - -void RawPointerData::clear() { - pointerCount = 0; - clearIdBits(); -} - -void RawPointerData::copyFrom(const RawPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointers[i] = other.pointers[i]; - - int id = pointers[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - -void RawPointerData::getCentroidOfTouchingPointers(float* outX, float* outY) const { - float x = 0, y = 0; - uint32_t count = touchingIdBits.count(); - if (count) { - for (BitSet32 idBits(touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const Pointer& pointer = pointerForId(id); - x += pointer.x; - y += pointer.y; - } - x /= count; - y /= count; - } - *outX = x; - *outY = y; -} - - -// --- CookedPointerData --- - -CookedPointerData::CookedPointerData() { - clear(); -} - -void CookedPointerData::clear() { - pointerCount = 0; - hoveringIdBits.clear(); - touchingIdBits.clear(); -} - -void CookedPointerData::copyFrom(const CookedPointerData& other) { - pointerCount = other.pointerCount; - hoveringIdBits = other.hoveringIdBits; - touchingIdBits = other.touchingIdBits; - - for (uint32_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(other.pointerProperties[i]); - pointerCoords[i].copyFrom(other.pointerCoords[i]); - - int id = pointerProperties[i].id; - idToIndex[id] = other.idToIndex[id]; - } -} - - -// --- SingleTouchMotionAccumulator --- - -SingleTouchMotionAccumulator::SingleTouchMotionAccumulator() { - clearAbsoluteAxes(); -} - -void SingleTouchMotionAccumulator::reset(InputDevice* device) { - mAbsX = device->getAbsoluteAxisValue(ABS_X); - mAbsY = device->getAbsoluteAxisValue(ABS_Y); - mAbsPressure = device->getAbsoluteAxisValue(ABS_PRESSURE); - mAbsToolWidth = device->getAbsoluteAxisValue(ABS_TOOL_WIDTH); - mAbsDistance = device->getAbsoluteAxisValue(ABS_DISTANCE); - mAbsTiltX = device->getAbsoluteAxisValue(ABS_TILT_X); - mAbsTiltY = device->getAbsoluteAxisValue(ABS_TILT_Y); -} - -void SingleTouchMotionAccumulator::clearAbsoluteAxes() { - mAbsX = 0; - mAbsY = 0; - mAbsPressure = 0; - mAbsToolWidth = 0; - mAbsDistance = 0; - mAbsTiltX = 0; - mAbsTiltY = 0; -} - -void SingleTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { - switch (rawEvent->code) { - case ABS_X: - mAbsX = rawEvent->value; - break; - case ABS_Y: - mAbsY = rawEvent->value; - break; - case ABS_PRESSURE: - mAbsPressure = rawEvent->value; - break; - case ABS_TOOL_WIDTH: - mAbsToolWidth = rawEvent->value; - break; - case ABS_DISTANCE: - mAbsDistance = rawEvent->value; - break; - case ABS_TILT_X: - mAbsTiltX = rawEvent->value; - break; - case ABS_TILT_Y: - mAbsTiltY = rawEvent->value; - break; - } - } -} - - -// --- MultiTouchMotionAccumulator --- - -MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() : - mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false), - mHaveStylus(false) { -} - -MultiTouchMotionAccumulator::~MultiTouchMotionAccumulator() { - delete[] mSlots; -} - -void MultiTouchMotionAccumulator::configure(InputDevice* device, - size_t slotCount, bool usingSlotsProtocol) { - mSlotCount = slotCount; - mUsingSlotsProtocol = usingSlotsProtocol; - mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE); - - delete[] mSlots; - mSlots = new Slot[slotCount]; -} - -void MultiTouchMotionAccumulator::reset(InputDevice* device) { - // Unfortunately there is no way to read the initial contents of the slots. - // So when we reset the accumulator, we must assume they are all zeroes. - if (mUsingSlotsProtocol) { - // Query the driver for the current slot index and use it as the initial slot - // before we start reading events from the device. It is possible that the - // current slot index will not be the same as it was when the first event was - // written into the evdev buffer, which means the input mapper could start - // out of sync with the initial state of the events in the evdev buffer. - // In the extremely unlikely case that this happens, the data from - // two slots will be confused until the next ABS_MT_SLOT event is received. - // This can cause the touch point to "jump", but at least there will be - // no stuck touches. - int32_t initialSlot; - status_t status = device->getEventHub()->getAbsoluteAxisValue(device->getId(), - ABS_MT_SLOT, &initialSlot); - if (status) { - ALOGD("Could not retrieve current multitouch slot index. status=%d", status); - initialSlot = -1; - } - clearSlots(initialSlot); - } else { - clearSlots(-1); - } -} - -void MultiTouchMotionAccumulator::clearSlots(int32_t initialSlot) { - if (mSlots) { - for (size_t i = 0; i < mSlotCount; i++) { - mSlots[i].clear(); - } - } - mCurrentSlot = initialSlot; -} - -void MultiTouchMotionAccumulator::process(const RawEvent* rawEvent) { - if (rawEvent->type == EV_ABS) { -#if DEBUG_POINTERS - bool newSlot = false; -#endif - if (mUsingSlotsProtocol) { - if (rawEvent->code == ABS_MT_SLOT) { - mCurrentSlot = rawEvent->value; -#if DEBUG_POINTERS - newSlot = true; -#endif - } - } else if (mCurrentSlot < 0) { - mCurrentSlot = 0; - } - - if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) { -#if DEBUG_POINTERS - if (newSlot) { - ALOGW("MultiTouch device emitted invalid slot index %d but it " - "should be between 0 and %d; ignoring this slot.", - mCurrentSlot, mSlotCount - 1); - } -#endif - } else { - Slot* slot = &mSlots[mCurrentSlot]; - - switch (rawEvent->code) { - case ABS_MT_POSITION_X: - slot->mInUse = true; - slot->mAbsMTPositionX = rawEvent->value; - break; - case ABS_MT_POSITION_Y: - slot->mInUse = true; - slot->mAbsMTPositionY = rawEvent->value; - break; - case ABS_MT_TOUCH_MAJOR: - slot->mInUse = true; - slot->mAbsMTTouchMajor = rawEvent->value; - break; - case ABS_MT_TOUCH_MINOR: - slot->mInUse = true; - slot->mAbsMTTouchMinor = rawEvent->value; - slot->mHaveAbsMTTouchMinor = true; - break; - case ABS_MT_WIDTH_MAJOR: - slot->mInUse = true; - slot->mAbsMTWidthMajor = rawEvent->value; - break; - case ABS_MT_WIDTH_MINOR: - slot->mInUse = true; - slot->mAbsMTWidthMinor = rawEvent->value; - slot->mHaveAbsMTWidthMinor = true; - break; - case ABS_MT_ORIENTATION: - slot->mInUse = true; - slot->mAbsMTOrientation = rawEvent->value; - break; - case ABS_MT_TRACKING_ID: - if (mUsingSlotsProtocol && rawEvent->value < 0) { - // The slot is no longer in use but it retains its previous contents, - // which may be reused for subsequent touches. - slot->mInUse = false; - } else { - slot->mInUse = true; - slot->mAbsMTTrackingId = rawEvent->value; - } - break; - case ABS_MT_PRESSURE: - slot->mInUse = true; - slot->mAbsMTPressure = rawEvent->value; - break; - case ABS_MT_DISTANCE: - slot->mInUse = true; - slot->mAbsMTDistance = rawEvent->value; - break; - case ABS_MT_TOOL_TYPE: - slot->mInUse = true; - slot->mAbsMTToolType = rawEvent->value; - slot->mHaveAbsMTToolType = true; - break; - } - } - } else if (rawEvent->type == EV_SYN && rawEvent->code == SYN_MT_REPORT) { - // MultiTouch Sync: The driver has returned all data for *one* of the pointers. - mCurrentSlot += 1; - } -} - -void MultiTouchMotionAccumulator::finishSync() { - if (!mUsingSlotsProtocol) { - clearSlots(-1); - } -} - -bool MultiTouchMotionAccumulator::hasStylus() const { - return mHaveStylus; -} - - -// --- MultiTouchMotionAccumulator::Slot --- - -MultiTouchMotionAccumulator::Slot::Slot() { - clear(); -} - -void MultiTouchMotionAccumulator::Slot::clear() { - mInUse = false; - mHaveAbsMTTouchMinor = false; - mHaveAbsMTWidthMinor = false; - mHaveAbsMTToolType = false; - mAbsMTPositionX = 0; - mAbsMTPositionY = 0; - mAbsMTTouchMajor = 0; - mAbsMTTouchMinor = 0; - mAbsMTWidthMajor = 0; - mAbsMTWidthMinor = 0; - mAbsMTOrientation = 0; - mAbsMTTrackingId = -1; - mAbsMTPressure = 0; - mAbsMTDistance = 0; - mAbsMTToolType = 0; -} - -int32_t MultiTouchMotionAccumulator::Slot::getToolType() const { - if (mHaveAbsMTToolType) { - switch (mAbsMTToolType) { - case MT_TOOL_FINGER: - return AMOTION_EVENT_TOOL_TYPE_FINGER; - case MT_TOOL_PEN: - return AMOTION_EVENT_TOOL_TYPE_STYLUS; - } - } - return AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - - -// --- InputMapper --- - -InputMapper::InputMapper(InputDevice* device) : - mDevice(device), mContext(device->getContext()) { -} - -InputMapper::~InputMapper() { -} - -void InputMapper::populateDeviceInfo(InputDeviceInfo* info) { - info->addSource(getSources()); -} - -void InputMapper::dump(String8& dump) { -} - -void InputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { -} - -void InputMapper::reset(nsecs_t when) { -} - -void InputMapper::timeoutExpired(nsecs_t when) { -} - -int32_t InputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return AKEY_STATE_UNKNOWN; -} - -int32_t InputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return AKEY_STATE_UNKNOWN; -} - -bool InputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return false; -} - -void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -} - -void InputMapper::cancelVibrate(int32_t token) { -} - -int32_t InputMapper::getMetaState() { - return 0; -} - -void InputMapper::fadePointer() { -} - -status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) { - return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo); -} - -void InputMapper::bumpGeneration() { - mDevice->bumpGeneration(); -} - -void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, - const RawAbsoluteAxisInfo& axis, const char* name) { - if (axis.valid) { - dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n", - name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution); - } else { - dump.appendFormat(INDENT4 "%s: unknown range\n", name); - } -} - - -// --- SwitchInputMapper --- - -SwitchInputMapper::SwitchInputMapper(InputDevice* device) : - InputMapper(device), mUpdatedSwitchValues(0), mUpdatedSwitchMask(0) { -} - -SwitchInputMapper::~SwitchInputMapper() { -} - -uint32_t SwitchInputMapper::getSources() { - return AINPUT_SOURCE_SWITCH; -} - -void SwitchInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_SW: - processSwitch(rawEvent->code, rawEvent->value); - break; - - case EV_SYN: - if (rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } - } -} - -void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) { - if (switchCode >= 0 && switchCode < 32) { - if (switchValue) { - mUpdatedSwitchValues |= 1 << switchCode; - } - mUpdatedSwitchMask |= 1 << switchCode; - } -} - -void SwitchInputMapper::sync(nsecs_t when) { - if (mUpdatedSwitchMask) { - NotifySwitchArgs args(when, 0, mUpdatedSwitchValues, mUpdatedSwitchMask); - getListener()->notifySwitch(&args); - - mUpdatedSwitchValues = 0; - mUpdatedSwitchMask = 0; - } -} - -int32_t SwitchInputMapper::getSwitchState(uint32_t sourceMask, int32_t switchCode) { - return getEventHub()->getSwitchState(getDeviceId(), switchCode); -} - - -// --- VibratorInputMapper --- - -VibratorInputMapper::VibratorInputMapper(InputDevice* device) : - InputMapper(device), mVibrating(false) { -} - -VibratorInputMapper::~VibratorInputMapper() { -} - -uint32_t VibratorInputMapper::getSources() { - return 0; -} - -void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setVibrator(true); -} - -void VibratorInputMapper::process(const RawEvent* rawEvent) { - // TODO: Handle FF_STATUS, although it does not seem to be widely supported. -} - -void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token) { -#if DEBUG_VIBRATOR - String8 patternStr; - for (size_t i = 0; i < patternSize; i++) { - if (i != 0) { - patternStr.append(", "); - } - patternStr.appendFormat("%lld", pattern[i]); - } - ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%ld, token=%d", - getDeviceId(), patternStr.string(), repeat, token); -#endif - - mVibrating = true; - memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t)); - mPatternSize = patternSize; - mRepeat = repeat; - mToken = token; - mIndex = -1; - - nextStep(); -} - -void VibratorInputMapper::cancelVibrate(int32_t token) { -#if DEBUG_VIBRATOR - ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token); -#endif - - if (mVibrating && mToken == token) { - stopVibrating(); - } -} - -void VibratorInputMapper::timeoutExpired(nsecs_t when) { - if (mVibrating) { - if (when >= mNextStepTime) { - nextStep(); - } else { - getContext()->requestTimeoutAtTime(mNextStepTime); - } - } -} - -void VibratorInputMapper::nextStep() { - mIndex += 1; - if (size_t(mIndex) >= mPatternSize) { - if (mRepeat < 0) { - // We are done. - stopVibrating(); - return; - } - mIndex = mRepeat; - } - - bool vibratorOn = mIndex & 1; - nsecs_t duration = mPattern[mIndex]; - if (vibratorOn) { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending vibrate deviceId=%d, duration=%lld", - getDeviceId(), duration); -#endif - getEventHub()->vibrate(getDeviceId(), duration); - } else { -#if DEBUG_VIBRATOR - ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); - } - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - mNextStepTime = now + duration; - getContext()->requestTimeoutAtTime(mNextStepTime); -#if DEBUG_VIBRATOR - ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f); -#endif -} - -void VibratorInputMapper::stopVibrating() { - mVibrating = false; -#if DEBUG_VIBRATOR - ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId()); -#endif - getEventHub()->cancelVibrate(getDeviceId()); -} - -void VibratorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Vibrator Input Mapper:\n"); - dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating)); -} - - -// --- KeyboardInputMapper --- - -KeyboardInputMapper::KeyboardInputMapper(InputDevice* device, - uint32_t source, int32_t keyboardType) : - InputMapper(device), mSource(source), - mKeyboardType(keyboardType) { -} - -KeyboardInputMapper::~KeyboardInputMapper() { -} - -uint32_t KeyboardInputMapper::getSources() { - return mSource; -} - -void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - info->setKeyboardType(mKeyboardType); - info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId())); -} - -void KeyboardInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Keyboard Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "KeyDowns: %d keys currently down\n", mKeyDowns.size()); - dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); -} - - -void KeyboardInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - DisplayViewport v; - if (config->getDisplayInfo(false /*external*/, &v)) { - mOrientation = v.orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } -} - -void KeyboardInputMapper::configureParameters() { - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("keyboard.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void KeyboardInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void KeyboardInputMapper::reset(nsecs_t when) { - mMetaState = AMETA_NONE; - mDownTime = 0; - mKeyDowns.clear(); - mCurrentHidUsage = 0; - - resetLedState(); - - InputMapper::reset(when); -} - -void KeyboardInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_KEY: { - int32_t scanCode = rawEvent->code; - int32_t usageCode = mCurrentHidUsage; - mCurrentHidUsage = 0; - - if (isKeyboardOrGamepadKey(scanCode)) { - int32_t keyCode; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) { - keyCode = AKEYCODE_UNKNOWN; - flags = 0; - } - processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags); - } - break; - } - case EV_MSC: { - if (rawEvent->code == MSC_SCAN) { - mCurrentHidUsage = rawEvent->value; - } - break; - } - case EV_SYN: { - if (rawEvent->code == SYN_REPORT) { - mCurrentHidUsage = 0; - } - } - } -} - -bool KeyboardInputMapper::isKeyboardOrGamepadKey(int32_t scanCode) { - return scanCode < BTN_MOUSE - || scanCode >= KEY_OK - || (scanCode >= BTN_MISC && scanCode < BTN_MOUSE) - || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI); -} - -void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, - int32_t scanCode, uint32_t policyFlags) { - - if (down) { - // Rotate key codes according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - keyCode = rotateKeyCode(keyCode, mOrientation); - } - - // Add key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key repeat, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; - } else { - // key down - if ((policyFlags & POLICY_FLAG_VIRTUAL) - && mContext->shouldDropVirtualKey(when, - getDevice(), keyCode, scanCode)) { - return; - } - - mKeyDowns.push(); - KeyDown& keyDown = mKeyDowns.editTop(); - keyDown.keyCode = keyCode; - keyDown.scanCode = scanCode; - } - - mDownTime = when; - } else { - // Remove key down. - ssize_t keyDownIndex = findKeyDown(scanCode); - if (keyDownIndex >= 0) { - // key up, be sure to use same keycode as before in case of rotation - keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode; - mKeyDowns.removeAt(size_t(keyDownIndex)); - } else { - // key was not actually down - ALOGI("Dropping key up from device %s because the key was not down. " - "keyCode=%d, scanCode=%d", - getDeviceName().string(), keyCode, scanCode); - return; - } - } - - bool metaStateChanged = false; - int32_t oldMetaState = mMetaState; - int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState); - if (oldMetaState != newMetaState) { - mMetaState = newMetaState; - metaStateChanged = true; - updateLedState(false); - } - - nsecs_t downTime = mDownTime; - - // Key down on external an keyboard should wake the device. - // We don't do this for internal keyboards to prevent them from waking up in your pocket. - // For internal keyboards, the key layout file should specify the policy flags for - // each wake key individually. - // TODO: Use the input device configuration to control this behavior more finely. - if (down && getDevice()->isExternal() - && !(policyFlags & (POLICY_FLAG_WAKE | POLICY_FLAG_WAKE_DROPPED))) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - - if (metaStateChanged) { - getContext()->updateGlobalMetaState(); - } - - if (down && !isMetaKey(keyCode)) { - getContext()->fadePointer(); - } - - NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime); - getListener()->notifyKey(&args); -} - -ssize_t KeyboardInputMapper::findKeyDown(int32_t scanCode) { - size_t n = mKeyDowns.size(); - for (size_t i = 0; i < n; i++) { - if (mKeyDowns[i].scanCode == scanCode) { - return i; - } - } - return -1; -} - -int32_t KeyboardInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - return getEventHub()->getKeyCodeState(getDeviceId(), keyCode); -} - -int32_t KeyboardInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); -} - -bool KeyboardInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - return getEventHub()->markSupportedKeyCodes(getDeviceId(), numCodes, keyCodes, outFlags); -} - -int32_t KeyboardInputMapper::getMetaState() { - return mMetaState; -} - -void KeyboardInputMapper::resetLedState() { - initializeLedState(mCapsLockLedState, LED_CAPSL); - initializeLedState(mNumLockLedState, LED_NUML); - initializeLedState(mScrollLockLedState, LED_SCROLLL); - - updateLedState(true); -} - -void KeyboardInputMapper::initializeLedState(LedState& ledState, int32_t led) { - ledState.avail = getEventHub()->hasLed(getDeviceId(), led); - ledState.on = false; -} - -void KeyboardInputMapper::updateLedState(bool reset) { - updateLedStateForModifier(mCapsLockLedState, LED_CAPSL, - AMETA_CAPS_LOCK_ON, reset); - updateLedStateForModifier(mNumLockLedState, LED_NUML, - AMETA_NUM_LOCK_ON, reset); - updateLedStateForModifier(mScrollLockLedState, LED_SCROLLL, - AMETA_SCROLL_LOCK_ON, reset); -} - -void KeyboardInputMapper::updateLedStateForModifier(LedState& ledState, - int32_t led, int32_t modifier, bool reset) { - if (ledState.avail) { - bool desiredState = (mMetaState & modifier) != 0; - if (reset || ledState.on != desiredState) { - getEventHub()->setLedState(getDeviceId(), led, desiredState); - ledState.on = desiredState; - } - } -} - - -// --- CursorInputMapper --- - -CursorInputMapper::CursorInputMapper(InputDevice* device) : - InputMapper(device) { -} - -CursorInputMapper::~CursorInputMapper() { -} - -uint32_t CursorInputMapper::getSources() { - return mSource; -} - -void CursorInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mParameters.mode == Parameters::MODE_POINTER) { - float minX, minY, maxX, maxY; - if (mPointerController->getBounds(&minX, &minY, &maxX, &maxY)) { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, minX, maxX, 0.0f, 0.0f, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, minY, maxY, 0.0f, 0.0f, 0.0f); - } - } else { - info->addMotionRange(AMOTION_EVENT_AXIS_X, mSource, -1.0f, 1.0f, 0.0f, mXScale, 0.0f); - info->addMotionRange(AMOTION_EVENT_AXIS_Y, mSource, -1.0f, 1.0f, 0.0f, mYScale, 0.0f); - } - info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, mSource, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f); - } -} - -void CursorInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Cursor Input Mapper:\n"); - dumpParameters(dump); - dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT3 "HaveVWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeVWheel())); - dump.appendFormat(INDENT3 "HaveHWheel: %s\n", - toString(mCursorScrollAccumulator.haveRelativeHWheel())); - dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale); - dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale); - dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation); - dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState); - dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState))); - dump.appendFormat(INDENT3 "DownTime: %lld\n", mDownTime); -} - -void CursorInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - mCursorScrollAccumulator.configure(getDevice()); - - // Configure basic parameters. - configureParameters(); - - // Configure device mode. - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - mSource = AINPUT_SOURCE_MOUSE; - mXPrecision = 1.0f; - mYPrecision = 1.0f; - mXScale = 1.0f; - mYScale = 1.0f; - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - break; - case Parameters::MODE_NAVIGATION: - mSource = AINPUT_SOURCE_TRACKBALL; - mXPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mYPrecision = TRACKBALL_MOVEMENT_THRESHOLD; - mXScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - mYScale = 1.0f / TRACKBALL_MOVEMENT_THRESHOLD; - break; - } - - mVWheelScale = 1.0f; - mHWheelScale = 1.0f; - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - mPointerVelocityControl.setParameters(config->pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(config->wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(config->wheelVelocityControlParameters); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) { - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) { - DisplayViewport v; - if (config->getDisplayInfo(false /*external*/, &v)) { - mOrientation = v.orientation; - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - } else { - mOrientation = DISPLAY_ORIENTATION_0; - } - bumpGeneration(); - } -} - -void CursorInputMapper::configureParameters() { - mParameters.mode = Parameters::MODE_POINTER; - String8 cursorModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("cursor.mode"), cursorModeString)) { - if (cursorModeString == "navigation") { - mParameters.mode = Parameters::MODE_NAVIGATION; - } else if (cursorModeString != "pointer" && cursorModeString != "default") { - ALOGW("Invalid value for cursor.mode: '%s'", cursorModeString.string()); - } - } - - mParameters.orientationAware = false; - getDevice()->getConfiguration().tryGetProperty(String8("cursor.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - if (mParameters.mode == Parameters::MODE_POINTER || mParameters.orientationAware) { - mParameters.hasAssociatedDisplay = true; - } -} - -void CursorInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n", - toString(mParameters.hasAssociatedDisplay)); - - switch (mParameters.mode) { - case Parameters::MODE_POINTER: - dump.append(INDENT4 "Mode: pointer\n"); - break; - case Parameters::MODE_NAVIGATION: - dump.append(INDENT4 "Mode: navigation\n"); - break; - default: - ALOG_ASSERT(false); - } - - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void CursorInputMapper::reset(nsecs_t when) { - mButtonState = 0; - mDownTime = 0; - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCursorButtonAccumulator.reset(getDevice()); - mCursorMotionAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - - InputMapper::reset(when); -} - -void CursorInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorMotionAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void CursorInputMapper::sync(nsecs_t when) { - int32_t lastButtonState = mButtonState; - int32_t currentButtonState = mCursorButtonAccumulator.getButtonState(); - mButtonState = currentButtonState; - - bool wasDown = isPointerDown(lastButtonState); - bool down = isPointerDown(currentButtonState); - bool downChanged; - if (!wasDown && down) { - mDownTime = when; - downChanged = true; - } else if (wasDown && !down) { - downChanged = true; - } else { - downChanged = false; - } - nsecs_t downTime = mDownTime; - bool buttonsChanged = currentButtonState != lastButtonState; - bool buttonsPressed = currentButtonState & ~lastButtonState; - - float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale; - float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale; - bool moved = deltaX != 0 || deltaY != 0; - - // Rotate delta according to orientation if needed. - if (mParameters.orientationAware && mParameters.hasAssociatedDisplay - && (deltaX != 0.0f || deltaY != 0.0f)) { - rotateDelta(mOrientation, &deltaX, &deltaY); - } - - // Move the pointer. - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - float vscroll = mCursorScrollAccumulator.getRelativeVWheel(); - float hscroll = mCursorScrollAccumulator.getRelativeHWheel(); - bool scrolled = vscroll != 0 || hscroll != 0; - - mWheelYVelocityControl.move(when, NULL, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, NULL); - - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - int32_t displayId; - if (mPointerController != NULL) { - if (moved || scrolled || buttonsChanged) { - mPointerController->setPresentation( - PointerControllerInterface::PRESENTATION_POINTER); - - if (moved) { - mPointerController->move(deltaX, deltaY); - } - - if (buttonsChanged) { - mPointerController->setButtonState(currentButtonState); - } - - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - - float x, y; - mPointerController->getPosition(&x, &y); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - displayId = ADISPLAY_ID_DEFAULT; - } else { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY); - displayId = ADISPLAY_ID_NONE; - } - - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f); - - // Moving an external trackball or mouse should wake the device. - // We don't do this for internal cursor devices to prevent them from waking up - // the device in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - if ((buttonsPressed || moved || scrolled) && getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - - // Synthesize key down from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, lastButtonState, currentButtonState); - - // Send motion event. - if (downChanged || moved || scrolled || buttonsChanged) { - int32_t metaState = mContext->getGlobalMetaState(); - int32_t motionEventAction; - if (downChanged) { - motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP; - } else if (down || mPointerController == NULL) { - motionEventAction = AMOTION_EVENT_ACTION_MOVE; - } else { - motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE; - } - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - motionEventAction, 0, metaState, currentButtonState, 0, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&args); - - // Send hover move after UP to tell the application that the mouse is hovering now. - if (motionEventAction == AMOTION_EVENT_ACTION_UP - && mPointerController != NULL) { - NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&hoverArgs); - } - - // Send scroll events. - if (scrolled) { - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, currentButtonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - displayId, 1, &pointerProperties, &pointerCoords, - mXPrecision, mYPrecision, downTime); - getListener()->notifyMotion(&scrollArgs); - } - } - - // Synthesize key up from buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, lastButtonState, currentButtonState); - - mCursorMotionAccumulator.finishSync(); - mCursorScrollAccumulator.finishSync(); -} - -int32_t CursorInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (scanCode >= BTN_MOUSE && scanCode < BTN_JOYSTICK) { - return getEventHub()->getScanCodeState(getDeviceId(), scanCode); - } else { - return AKEY_STATE_UNKNOWN; - } -} - -void CursorInputMapper::fadePointer() { - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - - -// --- TouchInputMapper --- - -TouchInputMapper::TouchInputMapper(InputDevice* device) : - InputMapper(device), - mSource(0), mDeviceMode(DEVICE_MODE_DISABLED), - mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0), - mSurfaceOrientation(DISPLAY_ORIENTATION_0) { -} - -TouchInputMapper::~TouchInputMapper() { -} - -uint32_t TouchInputMapper::getSources() { - return mSource; -} - -void TouchInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - if (mDeviceMode != DEVICE_MODE_DISABLED) { - info->addMotionRange(mOrientedRanges.x); - info->addMotionRange(mOrientedRanges.y); - info->addMotionRange(mOrientedRanges.pressure); - - if (mOrientedRanges.haveSize) { - info->addMotionRange(mOrientedRanges.size); - } - - if (mOrientedRanges.haveTouchSize) { - info->addMotionRange(mOrientedRanges.touchMajor); - info->addMotionRange(mOrientedRanges.touchMinor); - } - - if (mOrientedRanges.haveToolSize) { - info->addMotionRange(mOrientedRanges.toolMajor); - info->addMotionRange(mOrientedRanges.toolMinor); - } - - if (mOrientedRanges.haveOrientation) { - info->addMotionRange(mOrientedRanges.orientation); - } - - if (mOrientedRanges.haveDistance) { - info->addMotionRange(mOrientedRanges.distance); - } - - if (mOrientedRanges.haveTilt) { - info->addMotionRange(mOrientedRanges.tilt); - } - - if (mCursorScrollAccumulator.haveRelativeVWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_VSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCursorScrollAccumulator.haveRelativeHWheel()) { - info->addMotionRange(AMOTION_EVENT_AXIS_HSCROLL, mSource, -1.0f, 1.0f, 0.0f, 0.0f, - 0.0f); - } - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - const InputDeviceInfo::MotionRange& x = mOrientedRanges.x; - const InputDeviceInfo::MotionRange& y = mOrientedRanges.y; - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_1, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_2, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_3, mSource, x.min, x.max, x.flat, - x.fuzz, x.resolution); - info->addMotionRange(AMOTION_EVENT_AXIS_GENERIC_4, mSource, y.min, y.max, y.flat, - y.fuzz, y.resolution); - } - } -} - -void TouchInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Touch Input Mapper:\n"); - dumpParameters(dump); - dumpVirtualKeys(dump); - dumpRawPointerAxes(dump); - dumpCalibration(dump); - dumpSurface(dump); - - dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n"); - dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate); - dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate); - dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale); - dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale); - dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision); - dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision); - dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale); - dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale); - dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale); - dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale); - dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale); - dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt)); - dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter); - dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale); - dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); - dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); - - dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " - "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " - "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " - "toolType=%d, isHovering=%s\n", i, - pointer.id, pointer.x, pointer.y, pointer.pressure, - pointer.touchMajor, pointer.touchMinor, - pointer.toolMajor, pointer.toolMinor, - pointer.orientation, pointer.tiltX, pointer.tiltY, pointer.distance, - pointer.toolType, toString(pointer.isHovering)); - } - - dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; - dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " - "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " - "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " - "toolType=%d, isHovering=%s\n", i, - pointerProperties.id, - pointerCoords.getX(), - pointerCoords.getY(), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), - pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), - pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); - } - - if (mDeviceMode == DEVICE_MODE_POINTER) { - dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); - dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", - mPointerXMovementScale); - dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n", - mPointerYMovementScale); - dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n", - mPointerXZoomScale); - dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n", - mPointerYZoomScale); - dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n", - mPointerGestureMaxSwipeWidth); - } -} - -void TouchInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - mConfig = *config; - - if (!changes) { // first time only - // Configure basic parameters. - configureParameters(); - - // Configure common accumulators. - mCursorScrollAccumulator.configure(getDevice()); - mTouchButtonAccumulator.configure(getDevice()); - - // Configure absolute axis information. - configureRawPointerAxes(); - - // Prepare input device calibration. - parseCalibration(); - resolveCalibration(); - } - - if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) { - // Update pointer speed. - mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters); - mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters); - } - - bool resetNeeded = false; - if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO - | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { - // Configure device sources, surface dimensions, orientation and - // scaling factors. - configureSurface(when, &resetNeeded); - } - - if (changes && resetNeeded) { - // Send reset, unless this is the first time the device has been configured, - // in which case the reader will call reset itself after all mappers are ready. - getDevice()->notifyReset(when); - } -} - -void TouchInputMapper::configureParameters() { - // Use the pointer presentation mode for devices that do not support distinct - // multitouch. The spot-based presentation relies on being able to accurately - // locate two or more fingers on the touch pad. - mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT) - ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS; - - String8 gestureModeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"), - gestureModeString)) { - if (gestureModeString == "pointer") { - mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER; - } else if (gestureModeString == "spots") { - mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS; - } else if (gestureModeString != "default") { - ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string()); - } - } - - if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) { - // The device is a touch screen. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) { - // The device is a pointing device like a track pad. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) - || getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) { - // The device is a cursor device with a touch pad attached. - // By default don't use the touch pad to move the pointer. - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else { - // The device is a touch pad of unknown purpose. - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } - - String8 deviceTypeString; - if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"), - deviceTypeString)) { - if (deviceTypeString == "touchScreen") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN; - } else if (deviceTypeString == "touchPad") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD; - } else if (deviceTypeString == "touchNavigation") { - mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION; - } else if (deviceTypeString == "pointer") { - mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER; - } else if (deviceTypeString != "default") { - ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string()); - } - } - - mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN; - getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"), - mParameters.orientationAware); - - mParameters.hasAssociatedDisplay = false; - mParameters.associatedDisplayIsExternal = false; - if (mParameters.orientationAware - || mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - || mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) { - mParameters.hasAssociatedDisplay = true; - mParameters.associatedDisplayIsExternal = - mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && getDevice()->isExternal(); - } -} - -void TouchInputMapper::dumpParameters(String8& dump) { - dump.append(INDENT3 "Parameters:\n"); - - switch (mParameters.gestureMode) { - case Parameters::GESTURE_MODE_POINTER: - dump.append(INDENT4 "GestureMode: pointer\n"); - break; - case Parameters::GESTURE_MODE_SPOTS: - dump.append(INDENT4 "GestureMode: spots\n"); - break; - default: - assert(false); - } - - switch (mParameters.deviceType) { - case Parameters::DEVICE_TYPE_TOUCH_SCREEN: - dump.append(INDENT4 "DeviceType: touchScreen\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_PAD: - dump.append(INDENT4 "DeviceType: touchPad\n"); - break; - case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION: - dump.append(INDENT4 "DeviceType: touchNavigation\n"); - break; - case Parameters::DEVICE_TYPE_POINTER: - dump.append(INDENT4 "DeviceType: pointer\n"); - break; - default: - ALOG_ASSERT(false); - } - - dump.appendFormat(INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s\n", - toString(mParameters.hasAssociatedDisplay), - toString(mParameters.associatedDisplayIsExternal)); - dump.appendFormat(INDENT4 "OrientationAware: %s\n", - toString(mParameters.orientationAware)); -} - -void TouchInputMapper::configureRawPointerAxes() { - mRawPointerAxes.clear(); -} - -void TouchInputMapper::dumpRawPointerAxes(String8& dump) { - dump.append(INDENT3 "Raw Touch Axes:\n"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMajor, "TouchMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.touchMinor, "TouchMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMajor, "ToolMajor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.toolMinor, "ToolMinor"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.orientation, "Orientation"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.distance, "Distance"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltX, "TiltX"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.tiltY, "TiltY"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.trackingId, "TrackingId"); - dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); -} - -void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { - int32_t oldDeviceMode = mDeviceMode; - - // Determine device mode. - if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER - && mConfig.pointerGesturesEnabled) { - mSource = AINPUT_SOURCE_MOUSE; - mDeviceMode = DEVICE_MODE_POINTER; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN - && mParameters.hasAssociatedDisplay) { - mSource = AINPUT_SOURCE_TOUCHSCREEN; - mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { - mSource |= AINPUT_SOURCE_STYLUS; - } - } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { - mSource = AINPUT_SOURCE_TOUCH_NAVIGATION; - mDeviceMode = DEVICE_MODE_NAVIGATION; - } else { - mSource = AINPUT_SOURCE_TOUCHPAD; - mDeviceMode = DEVICE_MODE_UNSCALED; - } - - // Ensure we have valid X and Y axes. - if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) { - ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis! " - "The device will be inoperable.", getDeviceName().string()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - - // Raw width and height in the natural orientation. - int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - - // Get associated display dimensions. - bool viewportChanged = false; - DisplayViewport newViewport; - if (mParameters.hasAssociatedDisplay) { - if (!mConfig.getDisplayInfo(mParameters.associatedDisplayIsExternal, &newViewport)) { - ALOGI(INDENT "Touch device '%s' could not query the properties of its associated " - "display. The device will be inoperable until the display size " - "becomes available.", - getDeviceName().string()); - mDeviceMode = DEVICE_MODE_DISABLED; - return; - } - } else { - newViewport.setNonDisplayViewport(rawWidth, rawHeight); - } - if (mViewport != newViewport) { - mViewport = newViewport; - viewportChanged = true; - - if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) { - // Convert rotated viewport to natural surface coordinates. - int32_t naturalLogicalWidth, naturalLogicalHeight; - int32_t naturalPhysicalWidth, naturalPhysicalHeight; - int32_t naturalPhysicalLeft, naturalPhysicalTop; - int32_t naturalDeviceWidth, naturalDeviceHeight; - switch (mViewport.orientation) { - case DISPLAY_ORIENTATION_90: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom; - naturalPhysicalTop = mViewport.physicalLeft; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_180: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight; - naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - case DISPLAY_ORIENTATION_270: - naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop; - naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft; - naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalLeft = mViewport.physicalTop; - naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight; - naturalDeviceWidth = mViewport.deviceHeight; - naturalDeviceHeight = mViewport.deviceWidth; - break; - case DISPLAY_ORIENTATION_0: - default: - naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft; - naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop; - naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft; - naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop; - naturalPhysicalLeft = mViewport.physicalLeft; - naturalPhysicalTop = mViewport.physicalTop; - naturalDeviceWidth = mViewport.deviceWidth; - naturalDeviceHeight = mViewport.deviceHeight; - break; - } - - mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth; - mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight; - mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth; - mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight; - - mSurfaceOrientation = mParameters.orientationAware ? - mViewport.orientation : DISPLAY_ORIENTATION_0; - } else { - mSurfaceWidth = rawWidth; - mSurfaceHeight = rawHeight; - mSurfaceLeft = 0; - mSurfaceTop = 0; - mSurfaceOrientation = DISPLAY_ORIENTATION_0; - } - } - - // If moving between pointer modes, need to reset some state. - bool deviceModeChanged = mDeviceMode != oldDeviceMode; - if (deviceModeChanged) { - mOrientedRanges.clear(); - } - - // Create pointer controller if needed. - if (mDeviceMode == DEVICE_MODE_POINTER || - (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) { - if (mPointerController == NULL) { - mPointerController = getPolicy()->obtainPointerController(getDeviceId()); - } - } else { - mPointerController.clear(); - } - - if (viewportChanged || deviceModeChanged) { - ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, " - "display id %d", - getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight, - mSurfaceOrientation, mDeviceMode, mViewport.displayId); - - // Configure X and Y factors. - mXScale = float(mSurfaceWidth) / rawWidth; - mYScale = float(mSurfaceHeight) / rawHeight; - mXTranslate = -mSurfaceLeft; - mYTranslate = -mSurfaceTop; - mXPrecision = 1.0f / mXScale; - mYPrecision = 1.0f / mYScale; - - mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X; - mOrientedRanges.x.source = mSource; - mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y; - mOrientedRanges.y.source = mSource; - - configureVirtualKeys(); - - // Scale factor for terms that are not oriented in a particular axis. - // If the pixels are square then xScale == yScale otherwise we fake it - // by choosing an average. - mGeometricScale = avg(mXScale, mYScale); - - // Size of diagonal axis. - float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Size factors. - if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) { - if (mRawPointerAxes.touchMajor.valid - && mRawPointerAxes.touchMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue; - } else if (mRawPointerAxes.toolMajor.valid - && mRawPointerAxes.toolMajor.maxValue != 0) { - mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue; - } else { - mSizeScale = 0.0f; - } - - mOrientedRanges.haveTouchSize = true; - mOrientedRanges.haveToolSize = true; - mOrientedRanges.haveSize = true; - - mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR; - mOrientedRanges.touchMajor.source = mSource; - mOrientedRanges.touchMajor.min = 0; - mOrientedRanges.touchMajor.max = diagonalSize; - mOrientedRanges.touchMajor.flat = 0; - mOrientedRanges.touchMajor.fuzz = 0; - mOrientedRanges.touchMajor.resolution = 0; - - mOrientedRanges.touchMinor = mOrientedRanges.touchMajor; - mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR; - - mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR; - mOrientedRanges.toolMajor.source = mSource; - mOrientedRanges.toolMajor.min = 0; - mOrientedRanges.toolMajor.max = diagonalSize; - mOrientedRanges.toolMajor.flat = 0; - mOrientedRanges.toolMajor.fuzz = 0; - mOrientedRanges.toolMajor.resolution = 0; - - mOrientedRanges.toolMinor = mOrientedRanges.toolMajor; - mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR; - - mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE; - mOrientedRanges.size.source = mSource; - mOrientedRanges.size.min = 0; - mOrientedRanges.size.max = 1.0; - mOrientedRanges.size.flat = 0; - mOrientedRanges.size.fuzz = 0; - mOrientedRanges.size.resolution = 0; - } else { - mSizeScale = 0.0f; - } - - // Pressure factors. - mPressureScale = 0; - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL - || mCalibration.pressureCalibration - == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) { - if (mCalibration.havePressureScale) { - mPressureScale = mCalibration.pressureScale; - } else if (mRawPointerAxes.pressure.valid - && mRawPointerAxes.pressure.maxValue != 0) { - mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue; - } - } - - mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE; - mOrientedRanges.pressure.source = mSource; - mOrientedRanges.pressure.min = 0; - mOrientedRanges.pressure.max = 1.0; - mOrientedRanges.pressure.flat = 0; - mOrientedRanges.pressure.fuzz = 0; - mOrientedRanges.pressure.resolution = 0; - - // Tilt - mTiltXCenter = 0; - mTiltXScale = 0; - mTiltYCenter = 0; - mTiltYScale = 0; - mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid; - if (mHaveTilt) { - mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, - mRawPointerAxes.tiltX.maxValue); - mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, - mRawPointerAxes.tiltY.maxValue); - mTiltXScale = M_PI / 180; - mTiltYScale = M_PI / 180; - - mOrientedRanges.haveTilt = true; - - mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT; - mOrientedRanges.tilt.source = mSource; - mOrientedRanges.tilt.min = 0; - mOrientedRanges.tilt.max = M_PI_2; - mOrientedRanges.tilt.flat = 0; - mOrientedRanges.tilt.fuzz = 0; - mOrientedRanges.tilt.resolution = 0; - } - - // Orientation - mOrientationScale = 0; - if (mHaveTilt) { - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI; - mOrientedRanges.orientation.max = M_PI; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } else if (mCalibration.orientationCalibration != - Calibration::ORIENTATION_CALIBRATION_NONE) { - if (mCalibration.orientationCalibration - == Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) { - if (mRawPointerAxes.orientation.valid) { - if (mRawPointerAxes.orientation.maxValue > 0) { - mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue; - } else if (mRawPointerAxes.orientation.minValue < 0) { - mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue; - } else { - mOrientationScale = 0; - } - } - } - - mOrientedRanges.haveOrientation = true; - - mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION; - mOrientedRanges.orientation.source = mSource; - mOrientedRanges.orientation.min = -M_PI_2; - mOrientedRanges.orientation.max = M_PI_2; - mOrientedRanges.orientation.flat = 0; - mOrientedRanges.orientation.fuzz = 0; - mOrientedRanges.orientation.resolution = 0; - } - - // Distance - mDistanceScale = 0; - if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) { - if (mCalibration.distanceCalibration - == Calibration::DISTANCE_CALIBRATION_SCALED) { - if (mCalibration.haveDistanceScale) { - mDistanceScale = mCalibration.distanceScale; - } else { - mDistanceScale = 1.0f; - } - } - - mOrientedRanges.haveDistance = true; - - mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE; - mOrientedRanges.distance.source = mSource; - mOrientedRanges.distance.min = - mRawPointerAxes.distance.minValue * mDistanceScale; - mOrientedRanges.distance.max = - mRawPointerAxes.distance.maxValue * mDistanceScale; - mOrientedRanges.distance.flat = 0; - mOrientedRanges.distance.fuzz = - mRawPointerAxes.distance.fuzz * mDistanceScale; - mOrientedRanges.distance.resolution = 0; - } - - // Compute oriented precision, scales and ranges. - // Note that the maximum value reported is an inclusive maximum value so it is one - // unit less than the total width or height of surface. - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - mOrientedXPrecision = mYPrecision; - mOrientedYPrecision = mXPrecision; - - mOrientedRanges.x.min = mYTranslate; - mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale; - - mOrientedRanges.y.min = mXTranslate; - mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale; - break; - - default: - mOrientedXPrecision = mXPrecision; - mOrientedYPrecision = mYPrecision; - - mOrientedRanges.x.min = mXTranslate; - mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1; - mOrientedRanges.x.flat = 0; - mOrientedRanges.x.fuzz = 0; - mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale; - - mOrientedRanges.y.min = mYTranslate; - mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1; - mOrientedRanges.y.flat = 0; - mOrientedRanges.y.fuzz = 0; - mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale; - break; - } - - if (mDeviceMode == DEVICE_MODE_POINTER) { - // Compute pointer gesture detection parameters. - float rawDiagonal = hypotf(rawWidth, rawHeight); - float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight); - - // Scale movements such that one whole swipe of the touch pad covers a - // given area relative to the diagonal size of the display when no acceleration - // is applied. - // Assume that the touch pad has a square aspect ratio such that movements in - // X and Y of the same number of raw units cover the same physical distance. - mPointerXMovementScale = mConfig.pointerGestureMovementSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYMovementScale = mPointerXMovementScale; - - // Scale zooms to cover a smaller range of the display than movements do. - // This value determines the area around the pointer that is affected by freeform - // pointer gestures. - mPointerXZoomScale = mConfig.pointerGestureZoomSpeedRatio - * displayDiagonal / rawDiagonal; - mPointerYZoomScale = mPointerXZoomScale; - - // Max width between pointers to detect a swipe gesture is more than some fraction - // of the diagonal axis of the touch pad. Touches that are wider than this are - // translated into freeform gestures. - mPointerGestureMaxSwipeWidth = - mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal; - - // Abort current pointer usages because the state has changed. - abortPointerUsage(when, 0 /*policyFlags*/); - } - - // Inform the dispatcher about the changes. - *outResetNeeded = true; - bumpGeneration(); - } -} - -void TouchInputMapper::dumpSurface(String8& dump) { - dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, " - "logicalFrame=[%d, %d, %d, %d], " - "physicalFrame=[%d, %d, %d, %d], " - "deviceSize=[%d, %d]\n", - mViewport.displayId, mViewport.orientation, - mViewport.logicalLeft, mViewport.logicalTop, - mViewport.logicalRight, mViewport.logicalBottom, - mViewport.physicalLeft, mViewport.physicalTop, - mViewport.physicalRight, mViewport.physicalBottom, - mViewport.deviceWidth, mViewport.deviceHeight); - - dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth); - dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight); - dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft); - dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop); - dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation); -} - -void TouchInputMapper::configureVirtualKeys() { - Vector virtualKeyDefinitions; - getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions); - - mVirtualKeys.clear(); - - if (virtualKeyDefinitions.size() == 0) { - return; - } - - mVirtualKeys.setCapacity(virtualKeyDefinitions.size()); - - int32_t touchScreenLeft = mRawPointerAxes.x.minValue; - int32_t touchScreenTop = mRawPointerAxes.y.minValue; - int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1; - int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1; - - for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) { - const VirtualKeyDefinition& virtualKeyDefinition = - virtualKeyDefinitions[i]; - - mVirtualKeys.add(); - VirtualKey& virtualKey = mVirtualKeys.editTop(); - - virtualKey.scanCode = virtualKeyDefinition.scanCode; - int32_t keyCode; - uint32_t flags; - if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) { - ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", - virtualKey.scanCode); - mVirtualKeys.pop(); // drop the key - continue; - } - - virtualKey.keyCode = keyCode; - virtualKey.flags = flags; - - // convert the key definition's display coordinates into touch coordinates for a hit box - int32_t halfWidth = virtualKeyDefinition.width / 2; - int32_t halfHeight = virtualKeyDefinition.height / 2; - - virtualKey.hitLeft = (virtualKeyDefinition.centerX - halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitRight= (virtualKeyDefinition.centerX + halfWidth) - * touchScreenWidth / mSurfaceWidth + touchScreenLeft; - virtualKey.hitTop = (virtualKeyDefinition.centerY - halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - virtualKey.hitBottom = (virtualKeyDefinition.centerY + halfHeight) - * touchScreenHeight / mSurfaceHeight + touchScreenTop; - } -} - -void TouchInputMapper::dumpVirtualKeys(String8& dump) { - if (!mVirtualKeys.isEmpty()) { - dump.append(INDENT3 "Virtual Keys:\n"); - - for (size_t i = 0; i < mVirtualKeys.size(); i++) { - const VirtualKey& virtualKey = mVirtualKeys.itemAt(i); - dump.appendFormat(INDENT4 "%d: scanCode=%d, keyCode=%d, " - "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n", - i, virtualKey.scanCode, virtualKey.keyCode, - virtualKey.hitLeft, virtualKey.hitRight, - virtualKey.hitTop, virtualKey.hitBottom); - } - } -} - -void TouchInputMapper::parseCalibration() { - const PropertyMap& in = getDevice()->getConfiguration(); - Calibration& out = mCalibration; - - // Size - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT; - String8 sizeCalibrationString; - if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) { - if (sizeCalibrationString == "none") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } else if (sizeCalibrationString == "geometric") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } else if (sizeCalibrationString == "diameter") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER; - } else if (sizeCalibrationString == "box") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX; - } else if (sizeCalibrationString == "area") { - out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA; - } else if (sizeCalibrationString != "default") { - ALOGW("Invalid value for touch.size.calibration: '%s'", - sizeCalibrationString.string()); - } - } - - out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), - out.sizeScale); - out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), - out.sizeBias); - out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), - out.sizeIsSummed); - - // Pressure - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT; - String8 pressureCalibrationString; - if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) { - if (pressureCalibrationString == "none") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } else if (pressureCalibrationString == "physical") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } else if (pressureCalibrationString == "amplitude") { - out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE; - } else if (pressureCalibrationString != "default") { - ALOGW("Invalid value for touch.pressure.calibration: '%s'", - pressureCalibrationString.string()); - } - } - - out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), - out.pressureScale); - - // Orientation - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT; - String8 orientationCalibrationString; - if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) { - if (orientationCalibrationString == "none") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } else if (orientationCalibrationString == "interpolated") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } else if (orientationCalibrationString == "vector") { - out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR; - } else if (orientationCalibrationString != "default") { - ALOGW("Invalid value for touch.orientation.calibration: '%s'", - orientationCalibrationString.string()); - } - } - - // Distance - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT; - String8 distanceCalibrationString; - if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) { - if (distanceCalibrationString == "none") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } else if (distanceCalibrationString == "scaled") { - out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } else if (distanceCalibrationString != "default") { - ALOGW("Invalid value for touch.distance.calibration: '%s'", - distanceCalibrationString.string()); - } - } - - out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), - out.distanceScale); - - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT; - String8 coverageCalibrationString; - if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) { - if (coverageCalibrationString == "none") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } else if (coverageCalibrationString == "box") { - out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX; - } else if (coverageCalibrationString != "default") { - ALOGW("Invalid value for touch.coverage.calibration: '%s'", - coverageCalibrationString.string()); - } - } -} - -void TouchInputMapper::resolveCalibration() { - // Size - if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) { - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC; - } - } else { - mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE; - } - - // Pressure - if (mRawPointerAxes.pressure.valid) { - if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL; - } - } else { - mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE; - } - - // Orientation - if (mRawPointerAxes.orientation.valid) { - if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED; - } - } else { - mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE; - } - - // Distance - if (mRawPointerAxes.distance.valid) { - if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED; - } - } else { - mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE; - } - - // Coverage - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) { - mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE; - } -} - -void TouchInputMapper::dumpCalibration(String8& dump) { - dump.append(INDENT3 "Calibration:\n"); - - // Size - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.size.calibration: none\n"); - break; - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - dump.append(INDENT4 "touch.size.calibration: geometric\n"); - break; - case Calibration::SIZE_CALIBRATION_DIAMETER: - dump.append(INDENT4 "touch.size.calibration: diameter\n"); - break; - case Calibration::SIZE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.size.calibration: box\n"); - break; - case Calibration::SIZE_CALIBRATION_AREA: - dump.append(INDENT4 "touch.size.calibration: area\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveSizeScale) { - dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n", - mCalibration.sizeScale); - } - - if (mCalibration.haveSizeBias) { - dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n", - mCalibration.sizeBias); - } - - if (mCalibration.haveSizeIsSummed) { - dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n", - toString(mCalibration.sizeIsSummed)); - } - - // Pressure - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.pressure.calibration: none\n"); - break; - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - dump.append(INDENT4 "touch.pressure.calibration: physical\n"); - break; - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - dump.append(INDENT4 "touch.pressure.calibration: amplitude\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.havePressureScale) { - dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n", - mCalibration.pressureScale); - } - - // Orientation - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_NONE: - dump.append(INDENT4 "touch.orientation.calibration: none\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - dump.append(INDENT4 "touch.orientation.calibration: interpolated\n"); - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: - dump.append(INDENT4 "touch.orientation.calibration: vector\n"); - break; - default: - ALOG_ASSERT(false); - } - - // Distance - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.distance.calibration: none\n"); - break; - case Calibration::DISTANCE_CALIBRATION_SCALED: - dump.append(INDENT4 "touch.distance.calibration: scaled\n"); - break; - default: - ALOG_ASSERT(false); - } - - if (mCalibration.haveDistanceScale) { - dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n", - mCalibration.distanceScale); - } - - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_NONE: - dump.append(INDENT4 "touch.coverage.calibration: none\n"); - break; - case Calibration::COVERAGE_CALIBRATION_BOX: - dump.append(INDENT4 "touch.coverage.calibration: box\n"); - break; - default: - ALOG_ASSERT(false); - } -} - -void TouchInputMapper::reset(nsecs_t when) { - mCursorButtonAccumulator.reset(getDevice()); - mCursorScrollAccumulator.reset(getDevice()); - mTouchButtonAccumulator.reset(getDevice()); - - mPointerVelocityControl.reset(); - mWheelXVelocityControl.reset(); - mWheelYVelocityControl.reset(); - - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); - mPointerUsage = POINTER_USAGE_NONE; - mSentHoverEnter = false; - mDownTime = 0; - - mCurrentVirtualKey.down = false; - - mPointerGesture.reset(); - mPointerSimple.reset(); - - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } - - InputMapper::reset(when); -} - -void TouchInputMapper::process(const RawEvent* rawEvent) { - mCursorButtonAccumulator.process(rawEvent); - mCursorScrollAccumulator.process(rawEvent); - mTouchButtonAccumulator.process(rawEvent); - - if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { - sync(rawEvent->when); - } -} - -void TouchInputMapper::sync(nsecs_t when) { - // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() - | mCursorButtonAccumulator.getButtonState(); - - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); - mCursorScrollAccumulator.finishSync(); - - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); - -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); - } -#endif - - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); - - if (mDeviceMode == DEVICE_MODE_DISABLED) { - // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } - - // Initial downs on external touch devices should wake the device. - // We don't do this for internal touch screens to prevent them from waking - // up in your pocket. - // TODO: Use the input device configuration to control this behavior more finely. - if (getDevice()->isExternal()) { - policyFlags |= POLICY_FLAG_WAKE_DROPPED; - } - } - - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); - - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); - } - - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); - - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } - } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } - } - - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } - - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } - - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); - } - - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); - } - - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; - - // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; -} - -void TouchInputMapper::timeoutExpired(nsecs_t when) { - if (mDeviceMode == DEVICE_MODE_POINTER) { - if (mPointerUsage == POINTER_USAGE_GESTURES) { - dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); - } - } -} - -bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { - // Check for release of a virtual key. - if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { - // Pointer went up while virtual key was down. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key up: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - return true; - } - - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { - // Pointer is still within the space of the virtual key. - return true; - } - } - - // Pointer left virtual key area or another pointer also went down. - // Send key cancellation but do not consume the touch yet. - // This is useful when the user swipes through from the virtual key area - // into the main display surface. - mCurrentVirtualKey.down = false; - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Canceling key: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_UP, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY - | AKEY_EVENT_FLAG_CANCELED); - } - } - - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { - // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (!isPointInsideSurface(pointer.x, pointer.y)) { - // If exactly one pointer went down, check for virtual key hit. - // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); - if (virtualKey) { - mCurrentVirtualKey.down = true; - mCurrentVirtualKey.downTime = when; - mCurrentVirtualKey.keyCode = virtualKey->keyCode; - mCurrentVirtualKey.scanCode = virtualKey->scanCode; - mCurrentVirtualKey.ignored = mContext->shouldDropVirtualKey( - when, getDevice(), virtualKey->keyCode, virtualKey->scanCode); - - if (!mCurrentVirtualKey.ignored) { -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Generating key down: keyCode=%d, scanCode=%d", - mCurrentVirtualKey.keyCode, - mCurrentVirtualKey.scanCode); -#endif - dispatchVirtualKey(when, policyFlags, - AKEY_EVENT_ACTION_DOWN, - AKEY_EVENT_FLAG_FROM_SYSTEM | AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY); - } - } - } - return true; - } - } - - // Disable all virtual key touches that happen within a short time interval of the - // most recent touch within the screen area. The idea is to filter out stray - // virtual key presses when interacting with the touch screen. - // - // Problems we're trying to solve: - // - // 1. While scrolling a list or dragging the window shade, the user swipes down into a - // virtual key area that is implemented by a separate touch panel and accidentally - // triggers a virtual key. - // - // 2. While typing in the on screen keyboard, the user taps slightly outside the screen - // area and accidentally triggers a virtual key. This often happens when virtual keys - // are layed out below the screen near to where the on screen keyboard's space bar - // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { - mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); - } - return false; -} - -void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags) { - int32_t keyCode = mCurrentVirtualKey.keyCode; - int32_t scanCode = mCurrentVirtualKey.scanCode; - nsecs_t downTime = mCurrentVirtualKey.downTime; - int32_t metaState = mContext->getGlobalMetaState(); - policyFlags |= POLICY_FLAG_VIRTUAL; - - NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags, - keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime); - getListener()->notifyKey(&args); -} - -void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - - if (currentIdBits == lastIdBits) { - if (!currentIdBits.isEmpty()) { - // No pointer id changes so this is a move event. - // The listener takes care of batching moves so we don't have to deal with that here. - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - currentIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } else { - // There may be pointers going up and pointers going down and pointers moving - // all at the same time. - BitSet32 upIdBits(lastIdBits.value & ~currentIdBits.value); - BitSet32 downIdBits(currentIdBits.value & ~lastIdBits.value); - BitSet32 moveIdBits(lastIdBits.value & currentIdBits.value); - BitSet32 dispatchedIdBits(lastIdBits.value); - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - moveIdBits); - if (buttonState != mLastButtonState) { - moveNeeded = true; - } - - // Dispatch pointer up events. - while (!upIdBits.isEmpty()) { - uint32_t upId = upIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - dispatchedIdBits, upId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - dispatchedIdBits.clearBit(upId); - } - - // Dispatch move events if any of the remaining pointers moved from their old locations. - // Although applications receive new locations as part of individual pointer up - // events, they do not generally handle them except when presented in a move event. - if (moveNeeded) { - ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - - // Dispatch pointer down events using the new pointer locations. - while (!downIdBits.isEmpty()) { - uint32_t downId = downIdBits.clearFirstMarkedBit(); - dispatchedIdBits.markBit(downId); - - if (dispatchedIdBits.count() == 1) { - // First pointer is going down. Set down time. - mDownTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - dispatchedIdBits, downId, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } - } -} - -void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { - if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { - int32_t metaState = getContext()->getGlobalMetaState(); - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = false; - } -} - -void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - mSentHoverEnter = true; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, - mOrientedXPrecision, mOrientedYPrecision, mDownTime); - } -} - -void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; - - // Walk through the the active pointers and map device coordinates onto - // surface coordinates and adjust for display orientation. - for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; - - // Size - float touchMajor, touchMinor, toolMajor, toolMinor, size; - switch (mCalibration.sizeCalibration) { - case Calibration::SIZE_CALIBRATION_GEOMETRIC: - case Calibration::SIZE_CALIBRATION_DIAMETER: - case Calibration::SIZE_CALIBRATION_BOX: - case Calibration::SIZE_CALIBRATION_AREA: - if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.toolMajor.valid) { - touchMajor = in.touchMajor; - touchMinor = mRawPointerAxes.touchMinor.valid ? in.touchMinor : in.touchMajor; - toolMajor = in.toolMajor; - toolMinor = mRawPointerAxes.toolMinor.valid ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.touchMajor.valid) { - toolMajor = touchMajor = in.touchMajor; - toolMinor = touchMinor = mRawPointerAxes.touchMinor.valid - ? in.touchMinor : in.touchMajor; - size = mRawPointerAxes.touchMinor.valid - ? avg(in.touchMajor, in.touchMinor) : in.touchMajor; - } else if (mRawPointerAxes.toolMajor.valid) { - touchMajor = toolMajor = in.toolMajor; - touchMinor = toolMinor = mRawPointerAxes.toolMinor.valid - ? in.toolMinor : in.toolMajor; - size = mRawPointerAxes.toolMinor.valid - ? avg(in.toolMajor, in.toolMinor) : in.toolMajor; - } else { - ALOG_ASSERT(false, "No touch or tool axes. " - "Size calibration should have been resolved to NONE."); - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - } - - if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); - if (touchingCount > 1) { - touchMajor /= touchingCount; - touchMinor /= touchingCount; - toolMajor /= touchingCount; - toolMinor /= touchingCount; - size /= touchingCount; - } - } - - if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_GEOMETRIC) { - touchMajor *= mGeometricScale; - touchMinor *= mGeometricScale; - toolMajor *= mGeometricScale; - toolMinor *= mGeometricScale; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_AREA) { - touchMajor = touchMajor > 0 ? sqrtf(touchMajor) : 0; - touchMinor = touchMajor; - toolMajor = toolMajor > 0 ? sqrtf(toolMajor) : 0; - toolMinor = toolMajor; - } else if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DIAMETER) { - touchMinor = touchMajor; - toolMinor = toolMajor; - } - - mCalibration.applySizeScaleAndBias(&touchMajor); - mCalibration.applySizeScaleAndBias(&touchMinor); - mCalibration.applySizeScaleAndBias(&toolMajor); - mCalibration.applySizeScaleAndBias(&toolMinor); - size *= mSizeScale; - break; - default: - touchMajor = 0; - touchMinor = 0; - toolMajor = 0; - toolMinor = 0; - size = 0; - break; - } - - // Pressure - float pressure; - switch (mCalibration.pressureCalibration) { - case Calibration::PRESSURE_CALIBRATION_PHYSICAL: - case Calibration::PRESSURE_CALIBRATION_AMPLITUDE: - pressure = in.pressure * mPressureScale; - break; - default: - pressure = in.isHovering ? 0 : 1; - break; - } - - // Tilt and Orientation - float tilt; - float orientation; - if (mHaveTilt) { - float tiltXAngle = (in.tiltX - mTiltXCenter) * mTiltXScale; - float tiltYAngle = (in.tiltY - mTiltYCenter) * mTiltYScale; - orientation = atan2f(-sinf(tiltXAngle), sinf(tiltYAngle)); - tilt = acosf(cosf(tiltXAngle) * cosf(tiltYAngle)); - } else { - tilt = 0; - - switch (mCalibration.orientationCalibration) { - case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED: - orientation = in.orientation * mOrientationScale; - break; - case Calibration::ORIENTATION_CALIBRATION_VECTOR: { - int32_t c1 = signExtendNybble((in.orientation & 0xf0) >> 4); - int32_t c2 = signExtendNybble(in.orientation & 0x0f); - if (c1 != 0 || c2 != 0) { - orientation = atan2f(c1, c2) * 0.5f; - float confidence = hypotf(c1, c2); - float scale = 1.0f + confidence / 16.0f; - touchMajor *= scale; - touchMinor /= scale; - toolMajor *= scale; - toolMinor /= scale; - } else { - orientation = 0; - } - break; - } - default: - orientation = 0; - } - } - - // Distance - float distance; - switch (mCalibration.distanceCalibration) { - case Calibration::DISTANCE_CALIBRATION_SCALED: - distance = in.distance * mDistanceScale; - break; - default: - distance = 0; - } - - // Coverage - int32_t rawLeft, rawTop, rawRight, rawBottom; - switch (mCalibration.coverageCalibration) { - case Calibration::COVERAGE_CALIBRATION_BOX: - rawLeft = (in.toolMinor & 0xffff0000) >> 16; - rawRight = in.toolMinor & 0x0000ffff; - rawBottom = in.toolMajor & 0x0000ffff; - rawTop = (in.toolMajor & 0xffff0000) >> 16; - break; - default: - rawLeft = rawTop = rawRight = rawBottom = 0; - break; - } - - // X, Y, and the bounding box for coverage information - // Adjust coords for surface orientation. - float x, y, left, top, right, bottom; - switch (mSurfaceOrientation) { - case DISPLAY_ORIENTATION_90: - x = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - y = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; - left = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - right = float(rawBottom- mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - bottom = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - top = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - orientation -= M_PI_2; - if (orientation < - M_PI_2) { - orientation += M_PI; - } - break; - case DISPLAY_ORIENTATION_180: - x = float(mRawPointerAxes.x.maxValue - in.x) * mXScale + mXTranslate; - y = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; - left = float(mRawPointerAxes.x.maxValue - rawRight) * mXScale + mXTranslate; - right = float(mRawPointerAxes.x.maxValue - rawLeft) * mXScale + mXTranslate; - bottom = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - top = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - break; - case DISPLAY_ORIENTATION_270: - x = float(mRawPointerAxes.y.maxValue - in.y) * mYScale + mYTranslate; - y = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - left = float(mRawPointerAxes.y.maxValue - rawBottom) * mYScale + mYTranslate; - right = float(mRawPointerAxes.y.maxValue - rawTop) * mYScale + mYTranslate; - bottom = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - top = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - orientation += M_PI_2; - if (orientation > M_PI_2) { - orientation -= M_PI; - } - break; - default: - x = float(in.x - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - y = float(in.y - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - left = float(rawLeft - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - right = float(rawRight - mRawPointerAxes.x.minValue) * mXScale + mXTranslate; - bottom = float(rawBottom - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - top = float(rawTop - mRawPointerAxes.y.minValue) * mYScale + mYTranslate; - break; - } - - // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; - out.clear(); - out.setAxisValue(AMOTION_EVENT_AXIS_X, x); - out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - out.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, pressure); - out.setAxisValue(AMOTION_EVENT_AXIS_SIZE, size); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR, touchMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR, touchMinor); - out.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, orientation); - out.setAxisValue(AMOTION_EVENT_AXIS_TILT, tilt); - out.setAxisValue(AMOTION_EVENT_AXIS_DISTANCE, distance); - if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_BOX) { - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_1, left); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_2, top); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_3, right); - out.setAxisValue(AMOTION_EVENT_AXIS_GENERIC_4, bottom); - } else { - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, toolMajor); - out.setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, toolMinor); - } - - // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; - uint32_t id = in.id; - properties.clear(); - properties.id = id; - properties.toolType = in.toolType; - - // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; - } -} - -void TouchInputMapper::dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, - PointerUsage pointerUsage) { - if (pointerUsage != mPointerUsage) { - abortPointerUsage(when, policyFlags); - mPointerUsage = pointerUsage; - } - - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - dispatchPointerGestures(when, policyFlags, false /*isTimeout*/); - break; - case POINTER_USAGE_STYLUS: - dispatchPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - dispatchPointerMouse(when, policyFlags); - break; - default: - break; - } -} - -void TouchInputMapper::abortPointerUsage(nsecs_t when, uint32_t policyFlags) { - switch (mPointerUsage) { - case POINTER_USAGE_GESTURES: - abortPointerGestures(when, policyFlags); - break; - case POINTER_USAGE_STYLUS: - abortPointerStylus(when, policyFlags); - break; - case POINTER_USAGE_MOUSE: - abortPointerMouse(when, policyFlags); - break; - default: - break; - } - - mPointerUsage = POINTER_USAGE_NONE; -} - -void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, - bool isTimeout) { - // Update current gesture coordinates. - bool cancelPreviousGesture, finishPreviousGesture; - bool sendEvents = preparePointerGestures(when, - &cancelPreviousGesture, &finishPreviousGesture, isTimeout); - if (!sendEvents) { - return; - } - if (finishPreviousGesture) { - cancelPreviousGesture = false; - } - - // Update the pointer presentation and spots. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - if (finishPreviousGesture || cancelPreviousGesture) { - mPointerController->clearSpots(); - } - mPointerController->setSpots(mPointerGesture.currentGestureCoords, - mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits); - } else { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - } - - // Show or hide the pointer if needed. - switch (mPointerGesture.currentGestureMode) { - case PointerGesture::NEUTRAL: - case PointerGesture::QUIET: - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS - && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) { - // Remind the user of where the pointer is after finishing a gesture with spots. - mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL); - } - break; - case PointerGesture::TAP: - case PointerGesture::TAP_DRAG: - case PointerGesture::BUTTON_CLICK_OR_DRAG: - case PointerGesture::HOVER: - case PointerGesture::PRESS: - // Unfade the pointer when the current gesture manipulates the - // area directly under the pointer. - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - break; - case PointerGesture::SWIPE: - case PointerGesture::FREEFORM: - // Fade the pointer when the current gesture manipulates a different - // area and there are spots to guide the user experience. - if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } else { - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } - break; - } - - // Send events! - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - - // Update last coordinates of pointers that have moved so that we observe the new - // pointer positions at the same time as other pointers that have just gone up. - bool down = mPointerGesture.currentGestureMode == PointerGesture::TAP - || mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - || mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE - || mPointerGesture.currentGestureMode == PointerGesture::FREEFORM; - bool moveNeeded = false; - if (down && !cancelPreviousGesture && !finishPreviousGesture - && !mPointerGesture.lastGestureIdBits.isEmpty() - && !mPointerGesture.currentGestureIdBits.isEmpty()) { - BitSet32 movedGestureIdBits(mPointerGesture.currentGestureIdBits.value - & mPointerGesture.lastGestureIdBits.value); - moveNeeded = updateMovedPointers(mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - movedGestureIdBits); - if (buttonState != mLastButtonState) { - moveNeeded = true; - } - } - - // Send motion events for all pointers that went up or were canceled. - BitSet32 dispatchedGestureIdBits(mPointerGesture.lastGestureIdBits); - if (!dispatchedGestureIdBits.isEmpty()) { - if (cancelPreviousGesture) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clear(); - } else { - BitSet32 upGestureIdBits; - if (finishPreviousGesture) { - upGestureIdBits = dispatchedGestureIdBits; - } else { - upGestureIdBits.value = dispatchedGestureIdBits.value - & ~mPointerGesture.currentGestureIdBits.value; - } - while (!upGestureIdBits.isEmpty()) { - uint32_t id = upGestureIdBits.clearFirstMarkedBit(); - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_UP, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - - dispatchedGestureIdBits.clearBit(id); - } - } - } - - // Send motion events for all pointers that moved. - if (moveNeeded) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Send motion events for all pointers that went down. - if (down) { - BitSet32 downGestureIdBits(mPointerGesture.currentGestureIdBits.value - & ~dispatchedGestureIdBits.value); - while (!downGestureIdBits.isEmpty()) { - uint32_t id = downGestureIdBits.clearFirstMarkedBit(); - dispatchedGestureIdBits.markBit(id); - - if (dispatchedGestureIdBits.count() == 1) { - mPointerGesture.downTime = when; - } - - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - dispatchedGestureIdBits, id, - 0, 0, mPointerGesture.downTime); - } - } - - // Send motion events for hover. - if (mPointerGesture.currentGestureMode == PointerGesture::HOVER) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.currentGestureProperties, - mPointerGesture.currentGestureCoords, mPointerGesture.currentGestureIdToIndex, - mPointerGesture.currentGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } else if (dispatchedGestureIdBits.isEmpty() - && !mPointerGesture.lastGestureIdBits.isEmpty()) { - // Synthesize a hover move event after all pointers go up to indicate that - // the pointer is hovering again even if the user is not currently touching - // the touch pad. This ensures that a view will receive a fresh hover enter - // event after a tap. - float x, y; - mPointerController->getPosition(&x, &y); - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - - PointerCoords pointerCoords; - pointerCoords.clear(); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, - metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mViewport.displayId, 1, &pointerProperties, &pointerCoords, - 0, 0, mPointerGesture.downTime); - getListener()->notifyMotion(&args); - } - - // Update state. - mPointerGesture.lastGestureMode = mPointerGesture.currentGestureMode; - if (!down) { - mPointerGesture.lastGestureIdBits.clear(); - } else { - mPointerGesture.lastGestureIdBits = mPointerGesture.currentGestureIdBits; - for (BitSet32 idBits(mPointerGesture.currentGestureIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - mPointerGesture.lastGestureProperties[index].copyFrom( - mPointerGesture.currentGestureProperties[index]); - mPointerGesture.lastGestureCoords[index].copyFrom( - mPointerGesture.currentGestureCoords[index]); - mPointerGesture.lastGestureIdToIndex[id] = index; - } - } -} - -void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) { - // Cancel previously dispatches pointers. - if (!mPointerGesture.lastGestureIdBits.isEmpty()) { - int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, - AMOTION_EVENT_EDGE_FLAG_NONE, - mPointerGesture.lastGestureProperties, - mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, - mPointerGesture.lastGestureIdBits, -1, - 0, 0, mPointerGesture.downTime); - } - - // Reset the current pointer gesture. - mPointerGesture.reset(); - mPointerVelocityControl.reset(); - - // Remove any current spots. - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - mPointerController->clearSpots(); - } -} - -bool TouchInputMapper::preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, bool isTimeout) { - *outCancelPreviousGesture = false; - *outFinishPreviousGesture = false; - - // Handle TAP timeout. - if (isTimeout) { -#if DEBUG_GESTURES - ALOGD("Gestures: Processing timeout"); -#endif - - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - // The tap/drag timeout has not yet expired. - getContext()->requestTimeoutAtTime(mPointerGesture.tapUpTime - + mConfig.pointerGestureTapDragInterval); - } else { - // The tap is finished. -#if DEBUG_GESTURES - ALOGD("Gestures: TAP finished"); -#endif - *outFinishPreviousGesture = true; - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - return true; - } - } - - // We did not handle this timeout. - return false; - } - - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); - - // Update the velocity tracker. - { - VelocityTracker::Position positions[MAX_POINTERS]; - uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - positions[count].x = pointer.x * mPointerXMovementScale; - positions[count].y = pointer.y * mPointerYMovementScale; - } - mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); - } - - // Pick a new active touch id if needed. - // Choose an arbitrary pointer that just went down, if there is one. - // Otherwise choose an arbitrary remaining pointer. - // This guarantees we always have an active touch id when there is at least one pointer. - // We keep the same active touch id for as long as possible. - int32_t lastActiveTouchId = mPointerGesture.activeTouchId; - int32_t activeTouchId = lastActiveTouchId; - if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); - mPointerGesture.firstTouchTime = when; - } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { - if (!mCurrentFingerIdBits.isEmpty()) { - activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); - } else { - activeTouchId = mPointerGesture.activeTouchId = -1; - } - } - - // Determine whether we are in quiet time. - bool isQuietTime = false; - if (activeTouchId < 0) { - mPointerGesture.resetQuietTime(); - } else { - isQuietTime = when < mPointerGesture.quietTime + mConfig.pointerGestureQuietInterval; - if (!isQuietTime) { - if ((mPointerGesture.lastGestureMode == PointerGesture::PRESS - || mPointerGesture.lastGestureMode == PointerGesture::SWIPE - || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) - && currentFingerCount < 2) { - // Enter quiet time when exiting swipe or freeform state. - // This is to prevent accidentally entering the hover state and flinging the - // pointer when finishing a swipe and there is still one pointer left onscreen. - isQuietTime = true; - } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG - && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { - // Enter quiet time when releasing the button and there are still two or more - // fingers down. This may indicate that one finger was used to press the button - // but it has not gone up yet. - isQuietTime = true; - } - if (isQuietTime) { - mPointerGesture.quietTime = when; - } - } - } - - // Switch states based on button and pointer state. - if (isQuietTime) { - // Case 1: Quiet time. (QUIET) -#if DEBUG_GESTURES - ALOGD("Gestures: QUIET for next %0.3fms", (mPointerGesture.quietTime - + mConfig.pointerGestureQuietInterval - when) * 0.000001f); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::QUIET) { - *outFinishPreviousGesture = true; - } - - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::QUIET; - mPointerGesture.currentGestureIdBits.clear(); - - mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { - // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) - // The pointer follows the active touch point. - // Emit DOWN, MOVE, UP events at the pointer location. - // - // Only the active touch matters; other fingers are ignored. This policy helps - // to handle the case where the user places a second finger on the touch pad - // to apply the necessary force to depress an integrated button below the surface. - // We don't want the second finger to be delivered to applications. - // - // For this to work well, we need to make sure to track the pointer that is really - // active. If the user first puts one finger down to click then adds another - // finger to drag then the active pointer should switch to the finger that is - // being dragged. -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG activeTouchId=%d, " - "currentFingerCount=%d", activeTouchId, currentFingerCount); -#endif - // Reset state when just starting. - if (mPointerGesture.lastGestureMode != PointerGesture::BUTTON_CLICK_OR_DRAG) { - *outFinishPreviousGesture = true; - mPointerGesture.activeGestureId = 0; - } - - // Switch pointers if needed. - // Find the fastest pointer and follow it. - if (activeTouchId >= 0 && currentFingerCount > 1) { - int32_t bestId = -1; - float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - float vx, vy; - if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { - float speed = hypotf(vx, vy); - if (speed > bestSpeed) { - bestId = id; - bestSpeed = speed; - } - } - } - if (bestId >= 0 && bestId != activeTouchId) { - mPointerGesture.activeTouchId = activeTouchId = bestId; -#if DEBUG_GESTURES - ALOGD("Gestures: BUTTON_CLICK_OR_DRAG switched pointers, " - "bestId=%d, bestSpeed=%0.3f", bestId, bestSpeed); -#endif - } - } - - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the click will occur at the position of the anchor - // spot and all other spots will move there. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureMode = PointerGesture::BUTTON_CLICK_OR_DRAG; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (currentFingerCount == 0) { - // Case 3. No fingers down and button is not pressed. (NEUTRAL) - if (mPointerGesture.lastGestureMode != PointerGesture::NEUTRAL) { - *outFinishPreviousGesture = true; - } - - // Watch for taps coming out of HOVER or TAP_DRAG mode. - // Checking for taps after TAP_DRAG allows us to detect double-taps. - bool tapped = false; - if ((mPointerGesture.lastGestureMode == PointerGesture::HOVER - || mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) - && lastFingerCount == 1) { - if (when <= mPointerGesture.tapDownTime + mConfig.pointerGestureTapInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP"); -#endif - - mPointerGesture.tapUpTime = when; - getContext()->requestTimeoutAtTime(when - + mConfig.pointerGestureTapDragInterval); - - mPointerGesture.activeGestureId = 0; - mPointerGesture.currentGestureMode = PointerGesture::TAP; - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit( - mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[ - mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = - mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.tapX); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.tapY); - mPointerGesture.currentGestureCoords[0].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - - tapped = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP, %0.3fms since down", - (when - mPointerGesture.tapDownTime) * 0.000001f); -#endif - } - } - - mPointerVelocityControl.reset(); - - if (!tapped) { -#if DEBUG_GESTURES - ALOGD("Gestures: NEUTRAL"); -#endif - mPointerGesture.activeGestureId = -1; - mPointerGesture.currentGestureMode = PointerGesture::NEUTRAL; - mPointerGesture.currentGestureIdBits.clear(); - } - } else if (currentFingerCount == 1) { - // Case 4. Exactly one finger down, button is not pressed. (HOVER or TAP_DRAG) - // The pointer follows the active touch point. - // When in HOVER, emit HOVER_MOVE events at the pointer location. - // When in TAP_DRAG, emit MOVE events at the pointer location. - ALOG_ASSERT(activeTouchId >= 0); - - mPointerGesture.currentGestureMode = PointerGesture::HOVER; - if (mPointerGesture.lastGestureMode == PointerGesture::TAP) { - if (when <= mPointerGesture.tapUpTime + mConfig.pointerGestureTapDragInterval) { - float x, y; - mPointerController->getPosition(&x, &y); - if (fabs(x - mPointerGesture.tapX) <= mConfig.pointerGestureTapSlop - && fabs(y - mPointerGesture.tapY) <= mConfig.pointerGestureTapSlop) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, deltaX=%f, deltaY=%f", - x - mPointerGesture.tapX, - y - mPointerGesture.tapY); -#endif - } - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: Not a TAP_DRAG, %0.3fms time since up", - (when - mPointerGesture.tapUpTime) * 0.000001f); -#endif - } - } else if (mPointerGesture.lastGestureMode == PointerGesture::TAP_DRAG) { - mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; - } - - if (mLastFingerIdBits.hasBit(activeTouchId)) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); - float deltaX = (currentPointer.x - lastPointer.x) - * mPointerXMovementScale; - float deltaY = (currentPointer.y - lastPointer.y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - // Move the pointer using a relative motion. - // When using spots, the hover or drag will occur at the position of the anchor spot. - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - bool down; - if (mPointerGesture.currentGestureMode == PointerGesture::TAP_DRAG) { -#if DEBUG_GESTURES - ALOGD("Gestures: TAP_DRAG"); -#endif - down = true; - } else { -#if DEBUG_GESTURES - ALOGD("Gestures: HOVER"); -#endif - if (mPointerGesture.lastGestureMode != PointerGesture::HOVER) { - *outFinishPreviousGesture = true; - } - mPointerGesture.activeGestureId = 0; - down = false; - } - - float x, y; - mPointerController->getPosition(&x, &y); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - down ? 1.0f : 0.0f); - - if (lastFingerCount == 0 && currentFingerCount != 0) { - mPointerGesture.resetTap(); - mPointerGesture.tapDownTime = when; - mPointerGesture.tapX = x; - mPointerGesture.tapY = y; - } - } else { - // Case 5. At least two fingers down, button is not pressed. (PRESS, SWIPE or FREEFORM) - // We need to provide feedback for each finger that goes down so we cannot wait - // for the fingers to move before deciding what to do. - // - // The ambiguous case is deciding what to do when there are two fingers down but they - // have not moved enough to determine whether they are part of a drag or part of a - // freeform gesture, or just a press or long-press at the pointer location. - // - // When there are two fingers we start with the PRESS hypothesis and we generate a - // down at the pointer location. - // - // When the two fingers move enough or when additional fingers are added, we make - // a decision to transition into SWIPE or FREEFORM mode accordingly. - ALOG_ASSERT(activeTouchId >= 0); - - bool settled = when >= mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval; - if (mPointerGesture.lastGestureMode != PointerGesture::PRESS - && mPointerGesture.lastGestureMode != PointerGesture::SWIPE - && mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - *outFinishPreviousGesture = true; - } else if (!settled && currentFingerCount > lastFingerCount) { - // Additional pointers have gone down but not yet settled. - // Reset the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Resetting gesture since additional pointers went down for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - *outCancelPreviousGesture = true; - } else { - // Continue previous gesture. - mPointerGesture.currentGestureMode = mPointerGesture.lastGestureMode; - } - - if (*outFinishPreviousGesture || *outCancelPreviousGesture) { - mPointerGesture.currentGestureMode = PointerGesture::PRESS; - mPointerGesture.activeGestureId = 0; - mPointerGesture.referenceIdBits.clear(); - mPointerVelocityControl.reset(); - - // Use the centroid and pointer location as the reference points for the gesture. -#if DEBUG_GESTURES - ALOGD("Gestures: Using centroid as reference for MULTITOUCH, " - "settle time remaining %0.3fms", (mPointerGesture.firstTouchTime - + mConfig.pointerGestureMultitouchSettleInterval - when) - * 0.000001f); -#endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( - &mPointerGesture.referenceTouchX, - &mPointerGesture.referenceTouchY); - mPointerController->getPosition(&mPointerGesture.referenceGestureX, - &mPointerGesture.referenceGestureY); - } - - // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value - & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - mPointerGesture.referenceDeltas[id].dx = 0; - mPointerGesture.referenceDeltas[id].dy = 0; - } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; - - // Add delta for all fingers and calculate a common movement delta. - float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); - for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { - bool first = (idBits == commonIdBits); - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx += cpd.x - lpd.x; - delta.dy += cpd.y - lpd.y; - - if (first) { - commonDeltaX = delta.dx; - commonDeltaY = delta.dy; - } else { - commonDeltaX = calculateCommonVector(commonDeltaX, delta.dx); - commonDeltaY = calculateCommonVector(commonDeltaY, delta.dy); - } - } - - // Consider transitions from PRESS to SWIPE or MULTITOUCH. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS) { - float dist[MAX_POINTER_ID + 1]; - int32_t distOverThreshold = 0; - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - dist[id] = hypotf(delta.dx * mPointerXZoomScale, - delta.dy * mPointerYZoomScale); - if (dist[id] > mConfig.pointerGestureMultitouchMinDistance) { - distOverThreshold += 1; - } - } - - // Only transition when at least two pointers have moved further than - // the minimum distance threshold. - if (distOverThreshold >= 2) { - if (currentFingerCount > 2) { - // There are more than two pointers, switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); - uint32_t id1 = idBits.clearFirstMarkedBit(); - uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); - float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); - if (mutualDistance > mPointerGestureMaxSwipeWidth) { - // There are two pointers but they are too far apart for a SWIPE, - // switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, distance %0.3f > %0.3f", - mutualDistance, mPointerGestureMaxSwipeWidth); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } else { - // There are two pointers. Wait for both pointers to start moving - // before deciding whether this is a SWIPE or FREEFORM gesture. - float dist1 = dist[id1]; - float dist2 = dist[id2]; - if (dist1 >= mConfig.pointerGestureMultitouchMinDistance - && dist2 >= mConfig.pointerGestureMultitouchMinDistance) { - // Calculate the dot product of the displacement vectors. - // When the vectors are oriented in approximately the same direction, - // the angle betweeen them is near zero and the cosine of the angle - // approches 1.0. Recall that dot(v1, v2) = cos(angle) * mag(v1) * mag(v2). - PointerGesture::Delta& delta1 = mPointerGesture.referenceDeltas[id1]; - PointerGesture::Delta& delta2 = mPointerGesture.referenceDeltas[id2]; - float dx1 = delta1.dx * mPointerXZoomScale; - float dy1 = delta1.dy * mPointerYZoomScale; - float dx2 = delta2.dx * mPointerXZoomScale; - float dy2 = delta2.dy * mPointerYZoomScale; - float dot = dx1 * dx2 + dy1 * dy2; - float cosine = dot / (dist1 * dist2); // denominator always > 0 - if (cosine >= mConfig.pointerGestureSwipeTransitionAngleCosine) { - // Pointers are moving in the same direction. Switch to SWIPE. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to SWIPE, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f >= %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - mPointerGesture.currentGestureMode = PointerGesture::SWIPE; - } else { - // Pointers are moving in different directions. Switch to FREEFORM. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS transitioned to FREEFORM, " - "dist1 %0.3f >= %0.3f, dist2 %0.3f >= %0.3f, " - "cosine %0.3f < %0.3f", - dist1, mConfig.pointerGestureMultitouchMinDistance, - dist2, mConfig.pointerGestureMultitouchMinDistance, - cosine, mConfig.pointerGestureSwipeTransitionAngleCosine); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - } - } - } - } else if (mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // Switch from SWIPE to FREEFORM if additional pointers go down. - // Cancel previous gesture. - if (currentFingerCount > 2) { -#if DEBUG_GESTURES - ALOGD("Gestures: SWIPE transitioned to FREEFORM, number of pointers %d > 2", - currentFingerCount); -#endif - *outCancelPreviousGesture = true; - mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; - } - } - - // Move the reference points based on the overall group motion of the fingers - // except in PRESS mode while waiting for a transition to occur. - if (mPointerGesture.currentGestureMode != PointerGesture::PRESS - && (commonDeltaX || commonDeltaY)) { - for (BitSet32 idBits(mPointerGesture.referenceIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; - delta.dx = 0; - delta.dy = 0; - } - - mPointerGesture.referenceTouchX += commonDeltaX; - mPointerGesture.referenceTouchY += commonDeltaY; - - commonDeltaX *= mPointerXMovementScale; - commonDeltaY *= mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &commonDeltaX, &commonDeltaY); - mPointerVelocityControl.move(when, &commonDeltaX, &commonDeltaY); - - mPointerGesture.referenceGestureX += commonDeltaX; - mPointerGesture.referenceGestureY += commonDeltaY; - } - - // Report gestures. - if (mPointerGesture.currentGestureMode == PointerGesture::PRESS - || mPointerGesture.currentGestureMode == PointerGesture::SWIPE) { - // PRESS or SWIPE mode. -#if DEBUG_GESTURES - ALOGD("Gestures: PRESS or SWIPE activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - mPointerGesture.currentGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.currentGestureIdToIndex[mPointerGesture.activeGestureId] = 0; - mPointerGesture.currentGestureProperties[0].clear(); - mPointerGesture.currentGestureProperties[0].id = mPointerGesture.activeGestureId; - mPointerGesture.currentGestureProperties[0].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[0].clear(); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, - mPointerGesture.referenceGestureX); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, - mPointerGesture.referenceGestureY); - mPointerGesture.currentGestureCoords[0].setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } else if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) { - // FREEFORM mode. -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM activeTouchId=%d," - "activeGestureId=%d, currentTouchPointerCount=%d", - activeTouchId, mPointerGesture.activeGestureId, currentFingerCount); -#endif - ALOG_ASSERT(mPointerGesture.activeGestureId >= 0); - - mPointerGesture.currentGestureIdBits.clear(); - - BitSet32 mappedTouchIdBits; - BitSet32 usedGestureIdBits; - if (mPointerGesture.lastGestureMode != PointerGesture::FREEFORM) { - // Initially, assign the active gesture id to the active touch point - // if there is one. No other touch id bits are mapped yet. - if (!*outCancelPreviousGesture) { - mappedTouchIdBits.markBit(activeTouchId); - usedGestureIdBits.markBit(mPointerGesture.activeGestureId); - mPointerGesture.freeformTouchToGestureIdMap[activeTouchId] = - mPointerGesture.activeGestureId; - } else { - mPointerGesture.activeGestureId = -1; - } - } else { - // Otherwise, assume we mapped all touches from the previous frame. - // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; - usedGestureIdBits = mPointerGesture.lastGestureIdBits; - - // Check whether we need to choose a new active gesture id because the - // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); - !upTouchIdBits.isEmpty(); ) { - uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); - uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; - if (upGestureId == uint32_t(mPointerGesture.activeGestureId)) { - mPointerGesture.activeGestureId = -1; - break; - } - } - } - -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM follow up " - "mappedTouchIdBits=0x%08x, usedGestureIdBits=0x%08x, " - "activeGestureId=%d", - mappedTouchIdBits.value, usedGestureIdBits.value, - mPointerGesture.activeGestureId); -#endif - - BitSet32 idBits(mCurrentFingerIdBits); - for (uint32_t i = 0; i < currentFingerCount; i++) { - uint32_t touchId = idBits.clearFirstMarkedBit(); - uint32_t gestureId; - if (!mappedTouchIdBits.hasBit(touchId)) { - gestureId = usedGestureIdBits.markFirstUnmarkedBit(); - mPointerGesture.freeformTouchToGestureIdMap[touchId] = gestureId; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "new mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } else { - gestureId = mPointerGesture.freeformTouchToGestureIdMap[touchId]; -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM " - "existing mapping for touch id %d -> gesture id %d", - touchId, gestureId); -#endif - } - mPointerGesture.currentGestureIdBits.markBit(gestureId); - mPointerGesture.currentGestureIdToIndex[gestureId] = i; - - const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); - float deltaX = (pointer.x - mPointerGesture.referenceTouchX) - * mPointerXZoomScale; - float deltaY = (pointer.y - mPointerGesture.referenceTouchY) - * mPointerYZoomScale; - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - - mPointerGesture.currentGestureProperties[i].clear(); - mPointerGesture.currentGestureProperties[i].id = gestureId; - mPointerGesture.currentGestureProperties[i].toolType = - AMOTION_EVENT_TOOL_TYPE_FINGER; - mPointerGesture.currentGestureCoords[i].clear(); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_X, mPointerGesture.referenceGestureX + deltaX); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_Y, mPointerGesture.referenceGestureY + deltaY); - mPointerGesture.currentGestureCoords[i].setAxisValue( - AMOTION_EVENT_AXIS_PRESSURE, 1.0f); - } - - if (mPointerGesture.activeGestureId < 0) { - mPointerGesture.activeGestureId = - mPointerGesture.currentGestureIdBits.firstMarkedBit(); -#if DEBUG_GESTURES - ALOGD("Gestures: FREEFORM new " - "activeGestureId=%d", mPointerGesture.activeGestureId); -#endif - } - } - } - - mPointerController->setButtonState(mCurrentButtonState); - -#if DEBUG_GESTURES - ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " - "currentGestureMode=%d, currentGestureIdBits=0x%08x, " - "lastGestureMode=%d, lastGestureIdBits=0x%08x", - toString(*outFinishPreviousGesture), toString(*outCancelPreviousGesture), - mPointerGesture.currentGestureMode, mPointerGesture.currentGestureIdBits.value, - mPointerGesture.lastGestureMode, mPointerGesture.lastGestureIdBits.value); - for (BitSet32 idBits = mPointerGesture.currentGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.currentGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.currentGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.currentGestureCoords[index]; - ALOGD(" currentGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } - for (BitSet32 idBits = mPointerGesture.lastGestureIdBits; !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = mPointerGesture.lastGestureIdToIndex[id]; - const PointerProperties& properties = mPointerGesture.lastGestureProperties[index]; - const PointerCoords& coords = mPointerGesture.lastGestureCoords[index]; - ALOGD(" lastGesture[%d]: index=%d, toolType=%d, " - "x=%0.3f, y=%0.3f, pressure=%0.3f", - id, index, properties.toolType, - coords.getAxisValue(AMOTION_EVENT_AXIS_X), - coords.getAxisValue(AMOTION_EVENT_AXIS_Y), - coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - return true; -} - -void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); - mPointerController->setPosition(x, y); - - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); - down = !hovering; - - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; - } else { - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerStylus(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); -} - -void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) - * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) - * mPointerYMovementScale; - - rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); - mPointerVelocityControl.move(when, &deltaX, &deltaY); - - mPointerController->move(deltaX, deltaY); - } else { - mPointerVelocityControl.reset(); - } - - down = isPointerDown(mCurrentButtonState); - hovering = !down; - - float x, y; - mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); - mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, - hovering ? 0.0f : 1.0f); - mPointerSimple.currentProperties.id = 0; - mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; - } else { - mPointerVelocityControl.reset(); - - down = false; - hovering = false; - } - - dispatchPointerSimple(when, policyFlags, down, hovering); -} - -void TouchInputMapper::abortPointerMouse(nsecs_t when, uint32_t policyFlags) { - abortPointerSimple(when, policyFlags); - - mPointerVelocityControl.reset(); -} - -void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering) { - int32_t metaState = getContext()->getGlobalMetaState(); - - if (mPointerController != NULL) { - if (down || hovering) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); - mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); - } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } - } - - if (mPointerSimple.down && !down) { - mPointerSimple.down = false; - - // Send up. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (mPointerSimple.hovering && !hovering) { - mPointerSimple.hovering = false; - - // Send hover exit. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (down) { - if (!mPointerSimple.down) { - mPointerSimple.down = true; - mPointerSimple.downTime = when; - - // Send down. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Send move. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (hovering) { - if (!mPointerSimple.hovering) { - mPointerSimple.hovering = true; - - // Send hover enter. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Send hover move. - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; - mWheelYVelocityControl.move(when, NULL, &vscroll); - mWheelXVelocityControl.move(when, &hscroll, NULL); - - // Send scroll. - PointerCoords pointerCoords; - pointerCoords.copyFrom(mPointerSimple.currentCoords); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll); - pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); - - NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, - mViewport.displayId, - 1, &mPointerSimple.currentProperties, &pointerCoords, - mOrientedXPrecision, mOrientedYPrecision, - mPointerSimple.downTime); - getListener()->notifyMotion(&args); - } - - // Save state. - if (down || hovering) { - mPointerSimple.lastCoords.copyFrom(mPointerSimple.currentCoords); - mPointerSimple.lastProperties.copyFrom(mPointerSimple.currentProperties); - } else { - mPointerSimple.reset(); - } -} - -void TouchInputMapper::abortPointerSimple(nsecs_t when, uint32_t policyFlags) { - mPointerSimple.currentCoords.clear(); - mPointerSimple.currentProperties.clear(); - - dispatchPointerSimple(when, policyFlags, false, false); -} - -void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime) { - PointerCoords pointerCoords[MAX_POINTERS]; - PointerProperties pointerProperties[MAX_POINTERS]; - uint32_t pointerCount = 0; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t index = idToIndex[id]; - pointerProperties[pointerCount].copyFrom(properties[index]); - pointerCoords[pointerCount].copyFrom(coords[index]); - - if (changedId >= 0 && id == uint32_t(changedId)) { - action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - } - - pointerCount += 1; - } - - ALOG_ASSERT(pointerCount != 0); - - if (changedId >= 0 && pointerCount == 1) { - // Replace initial down and final up action. - // We can compare the action without masking off the changed pointer index - // because we know the index is 0. - if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) { - action = AMOTION_EVENT_ACTION_DOWN; - } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) { - action = AMOTION_EVENT_ACTION_UP; - } else { - // Can't happen. - ALOG_ASSERT(false); - } - } - - NotifyMotionArgs args(when, getDeviceId(), source, policyFlags, - action, flags, metaState, buttonState, edgeFlags, - mViewport.displayId, pointerCount, pointerProperties, pointerCoords, - xPrecision, yPrecision, downTime); - getListener()->notifyMotion(&args); -} - -bool TouchInputMapper::updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, const uint32_t* outIdToIndex, - BitSet32 idBits) const { - bool changed = false; - while (!idBits.isEmpty()) { - uint32_t id = idBits.clearFirstMarkedBit(); - uint32_t inIndex = inIdToIndex[id]; - uint32_t outIndex = outIdToIndex[id]; - - const PointerProperties& curInProperties = inProperties[inIndex]; - const PointerCoords& curInCoords = inCoords[inIndex]; - PointerProperties& curOutProperties = outProperties[outIndex]; - PointerCoords& curOutCoords = outCoords[outIndex]; - - if (curInProperties != curOutProperties) { - curOutProperties.copyFrom(curInProperties); - changed = true; - } - - if (curInCoords != curOutCoords) { - curOutCoords.copyFrom(curInCoords); - changed = true; - } - } - return changed; -} - -void TouchInputMapper::fadePointer() { - if (mPointerController != NULL) { - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - } -} - -bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { - return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue - && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; -} - -const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( - int32_t x, int32_t y) { - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - -#if DEBUG_VIRTUAL_KEYS - ALOGD("VirtualKeys: Hit test (%d, %d): keyCode=%d, scanCode=%d, " - "left=%d, top=%d, right=%d, bottom=%d", - x, y, - virtualKey.keyCode, virtualKey.scanCode, - virtualKey.hitLeft, virtualKey.hitTop, - virtualKey.hitRight, virtualKey.hitBottom); -#endif - - if (virtualKey.isHit(x, y)) { - return & virtualKey; - } - } - - return NULL; -} - -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; - - mCurrentRawPointerData.clearIdBits(); - - if (currentPointerCount == 0) { - // No pointers to assign. - return; - } - - if (lastPointerCount == 0) { - // All pointers are new. - for (uint32_t i = 0; i < currentPointerCount; i++) { - uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); - } - return; - } - - if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { - // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); - return; - } - - // General case. - // We build a heap of squared euclidean distances between current and last pointers - // associated with the current and last pointer indices. Then, we find the best - // match (by distance) for each current pointer. - // The pointers must have the same tool type but it is possible for them to - // transition from hovering to touching or vice-versa while retaining the same id. - PointerDistanceHeapElement heap[MAX_POINTERS * MAX_POINTERS]; - - uint32_t heapSize = 0; - for (uint32_t currentPointerIndex = 0; currentPointerIndex < currentPointerCount; - currentPointerIndex++) { - for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; - lastPointerIndex++) { - const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; - const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; - if (currentPointer.toolType == lastPointer.toolType) { - int64_t deltaX = currentPointer.x - lastPointer.x; - int64_t deltaY = currentPointer.y - lastPointer.y; - - uint64_t distance = uint64_t(deltaX * deltaX + deltaY * deltaY); - - // Insert new element into the heap (sift up). - heap[heapSize].currentPointerIndex = currentPointerIndex; - heap[heapSize].lastPointerIndex = lastPointerIndex; - heap[heapSize].distance = distance; - heapSize += 1; - } - } - } - - // Heapify - for (uint32_t startIndex = heapSize / 2; startIndex != 0; ) { - startIndex -= 1; - for (uint32_t parentIndex = startIndex; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - initial distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - - // Pull matches out by increasing order of distance. - // To avoid reassigning pointers that have already been matched, the loop keeps track - // of which last and current pointers have been matched using the matchedXXXBits variables. - // It also tracks the used pointer id bits. - BitSet32 matchedLastBits(0); - BitSet32 matchedCurrentBits(0); - BitSet32 usedIdBits(0); - bool first = true; - for (uint32_t i = min(currentPointerCount, lastPointerCount); heapSize > 0 && i > 0; i--) { - while (heapSize > 0) { - if (first) { - // The first time through the loop, we just consume the root element of - // the heap (the one with smallest distance). - first = false; - } else { - // Previous iterations consumed the root element of the heap. - // Pop root element off of the heap (sift down). - heap[0] = heap[heapSize]; - for (uint32_t parentIndex = 0; ;) { - uint32_t childIndex = parentIndex * 2 + 1; - if (childIndex >= heapSize) { - break; - } - - if (childIndex + 1 < heapSize - && heap[childIndex + 1].distance < heap[childIndex].distance) { - childIndex += 1; - } - - if (heap[parentIndex].distance <= heap[childIndex].distance) { - break; - } - - swap(heap[parentIndex], heap[childIndex]); - parentIndex = childIndex; - } - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - reduced distance min-heap: size=%d", heapSize); - for (size_t i = 0; i < heapSize; i++) { - ALOGD(" heap[%d]: cur=%d, last=%d, distance=%lld", - i, heap[i].currentPointerIndex, heap[i].lastPointerIndex, - heap[i].distance); - } -#endif - } - - heapSize -= 1; - - uint32_t currentPointerIndex = heap[0].currentPointerIndex; - if (matchedCurrentBits.hasBit(currentPointerIndex)) continue; // already matched - - uint32_t lastPointerIndex = heap[0].lastPointerIndex; - if (matchedLastBits.hasBit(lastPointerIndex)) continue; // already matched - - matchedCurrentBits.markBit(currentPointerIndex); - matchedLastBits.markBit(lastPointerIndex); - - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); - usedIdBits.markBit(id); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - matched: cur=%d, last=%d, id=%d, distance=%lld", - lastPointerIndex, currentPointerIndex, id, heap[0].distance); -#endif - break; - } - } - - // Assign fresh ids to pointers that were not matched in the process. - for (uint32_t i = currentPointerCount - matchedCurrentBits.count(); i != 0; i--) { - uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); - uint32_t id = usedIdBits.markFirstUnmarkedBit(); - - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); - -#if DEBUG_POINTER_ASSIGNMENT - ALOGD("assignPointerIds - assigned: cur=%d, id=%d", - currentPointerIndex, id); -#endif - } -} - -int32_t TouchInputMapper::getKeyCodeState(uint32_t sourceMask, int32_t keyCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.keyCode == keyCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - if (virtualKey.keyCode == keyCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -int32_t TouchInputMapper::getScanCodeState(uint32_t sourceMask, int32_t scanCode) { - if (mCurrentVirtualKey.down && mCurrentVirtualKey.scanCode == scanCode) { - return AKEY_STATE_VIRTUAL; - } - - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - if (virtualKey.scanCode == scanCode) { - return AKEY_STATE_UP; - } - } - - return AKEY_STATE_UNKNOWN; -} - -bool TouchInputMapper::markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags) { - size_t numVirtualKeys = mVirtualKeys.size(); - for (size_t i = 0; i < numVirtualKeys; i++) { - const VirtualKey& virtualKey = mVirtualKeys[i]; - - for (size_t i = 0; i < numCodes; i++) { - if (virtualKey.keyCode == keyCodes[i]) { - outFlags[i] = 1; - } - } - } - - return true; -} - - -// --- SingleTouchInputMapper --- - -SingleTouchInputMapper::SingleTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -SingleTouchInputMapper::~SingleTouchInputMapper() { -} - -void SingleTouchInputMapper::reset(nsecs_t when) { - mSingleTouchMotionAccumulator.reset(getDevice()); - - TouchInputMapper::reset(when); -} - -void SingleTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mSingleTouchMotionAccumulator.process(rawEvent); -} - -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { - if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid - && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); - - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; - outPointer.id = 0; - outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); - outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); - outPointer.pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); - outPointer.touchMajor = 0; - outPointer.touchMinor = 0; - outPointer.toolMajor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.toolMinor = mSingleTouchMotionAccumulator.getAbsoluteToolWidth(); - outPointer.orientation = 0; - outPointer.distance = mSingleTouchMotionAccumulator.getAbsoluteDistance(); - outPointer.tiltX = mSingleTouchMotionAccumulator.getAbsoluteTiltX(); - outPointer.tiltY = mSingleTouchMotionAccumulator.getAbsoluteTiltY(); - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - outPointer.isHovering = isHovering; - } -} - -void SingleTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_TOOL_WIDTH, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_TILT_X, &mRawPointerAxes.tiltX); - getAbsoluteAxisInfo(ABS_TILT_Y, &mRawPointerAxes.tiltY); -} - -bool SingleTouchInputMapper::hasStylus() const { - return mTouchButtonAccumulator.hasStylus(); -} - - -// --- MultiTouchInputMapper --- - -MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : - TouchInputMapper(device) { -} - -MultiTouchInputMapper::~MultiTouchInputMapper() { -} - -void MultiTouchInputMapper::reset(nsecs_t when) { - mMultiTouchMotionAccumulator.reset(getDevice()); - - mPointerIdBits.clear(); - - TouchInputMapper::reset(when); -} - -void MultiTouchInputMapper::process(const RawEvent* rawEvent) { - TouchInputMapper::process(rawEvent); - - mMultiTouchMotionAccumulator.process(rawEvent); -} - -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { - size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); - size_t outCount = 0; - BitSet32 newPointerIdBits; - - for (size_t inIndex = 0; inIndex < inCount; inIndex++) { - const MultiTouchMotionAccumulator::Slot* inSlot = - mMultiTouchMotionAccumulator.getSlot(inIndex); - if (!inSlot->isInUse()) { - continue; - } - - if (outCount >= MAX_POINTERS) { -#if DEBUG_POINTERS - ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; " - "ignoring the rest.", - getDeviceName().string(), MAX_POINTERS); -#endif - break; // too many fingers! - } - - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; - outPointer.x = inSlot->getX(); - outPointer.y = inSlot->getY(); - outPointer.pressure = inSlot->getPressure(); - outPointer.touchMajor = inSlot->getTouchMajor(); - outPointer.touchMinor = inSlot->getTouchMinor(); - outPointer.toolMajor = inSlot->getToolMajor(); - outPointer.toolMinor = inSlot->getToolMinor(); - outPointer.orientation = inSlot->getOrientation(); - outPointer.distance = inSlot->getDistance(); - outPointer.tiltX = 0; - outPointer.tiltY = 0; - - outPointer.toolType = inSlot->getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = mTouchButtonAccumulator.getToolType(); - if (outPointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - outPointer.toolType = AMOTION_EVENT_TOOL_TYPE_FINGER; - } - } - - bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE - && (mTouchButtonAccumulator.isHovering() - || (mRawPointerAxes.pressure.valid && inSlot->getPressure() <= 0)); - outPointer.isHovering = isHovering; - - // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; - } - } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); - } - } - - outCount += 1; - } - - mCurrentRawPointerData.pointerCount = outCount; - mPointerIdBits = newPointerIdBits; - - mMultiTouchMotionAccumulator.finishSync(); -} - -void MultiTouchInputMapper::configureRawPointerAxes() { - TouchInputMapper::configureRawPointerAxes(); - - getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x); - getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor); - getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor); - getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor); - getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation); - getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure); - getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance); - getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId); - getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot); - - if (mRawPointerAxes.trackingId.valid - && mRawPointerAxes.slot.valid - && mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) { - size_t slotCount = mRawPointerAxes.slot.maxValue + 1; - if (slotCount > MAX_SLOTS) { - ALOGW("MultiTouch Device %s reported %d slots but the framework " - "only supports a maximum of %d slots at this time.", - getDeviceName().string(), slotCount, MAX_SLOTS); - slotCount = MAX_SLOTS; - } - mMultiTouchMotionAccumulator.configure(getDevice(), - slotCount, true /*usingSlotsProtocol*/); - } else { - mMultiTouchMotionAccumulator.configure(getDevice(), - MAX_POINTERS, false /*usingSlotsProtocol*/); - } -} - -bool MultiTouchInputMapper::hasStylus() const { - return mMultiTouchMotionAccumulator.hasStylus() - || mTouchButtonAccumulator.hasStylus(); -} - - -// --- JoystickInputMapper --- - -JoystickInputMapper::JoystickInputMapper(InputDevice* device) : - InputMapper(device) { -} - -JoystickInputMapper::~JoystickInputMapper() { -} - -uint32_t JoystickInputMapper::getSources() { - return AINPUT_SOURCE_JOYSTICK; -} - -void JoystickInputMapper::populateDeviceInfo(InputDeviceInfo* info) { - InputMapper::populateDeviceInfo(info); - - for (size_t i = 0; i < mAxes.size(); i++) { - const Axis& axis = mAxes.valueAt(i); - addMotionRange(axis.axisInfo.axis, axis, info); - - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - addMotionRange(axis.axisInfo.highAxis, axis, info); - - } - } -} - -void JoystickInputMapper::addMotionRange(int32_t axisId, const Axis& axis, - InputDeviceInfo* info) { - info->addMotionRange(axisId, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to register - * the old axes as duplicates of their corresponding new ones. */ - int32_t compatAxis = getCompatAxis(axisId); - if (compatAxis >= 0) { - info->addMotionRange(compatAxis, AINPUT_SOURCE_JOYSTICK, - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - } -} - -/* A mapping from axes the joystick actually has to the axes that should be - * artificially created for compatibility purposes. - * Returns -1 if no compatibility axis is needed. */ -int32_t JoystickInputMapper::getCompatAxis(int32_t axis) { - switch(axis) { - case AMOTION_EVENT_AXIS_LTRIGGER: - return AMOTION_EVENT_AXIS_BRAKE; - case AMOTION_EVENT_AXIS_RTRIGGER: - return AMOTION_EVENT_AXIS_GAS; - } - return -1; -} - -void JoystickInputMapper::dump(String8& dump) { - dump.append(INDENT2 "Joystick Input Mapper:\n"); - - dump.append(INDENT3 "Axes:\n"); - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - const char* label = getAxisLabel(axis.axisInfo.axis); - if (label) { - dump.appendFormat(INDENT4 "%s", label); - } else { - dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis); - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - label = getAxisLabel(axis.axisInfo.highAxis); - if (label) { - dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue); - } else { - dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis, - axis.axisInfo.splitValue); - } - } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) { - dump.append(" (invert)"); - } - - dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n", - axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution); - dump.appendFormat(INDENT4 " scale=%0.5f, offset=%0.5f, " - "highScale=%0.5f, highOffset=%0.5f\n", - axis.scale, axis.offset, axis.highScale, axis.highOffset); - dump.appendFormat(INDENT4 " rawAxis=%d, rawMin=%d, rawMax=%d, " - "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n", - mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue, - axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution); - } -} - -void JoystickInputMapper::configure(nsecs_t when, - const InputReaderConfiguration* config, uint32_t changes) { - InputMapper::configure(when, config, changes); - - if (!changes) { // first time only - // Collect all axes. - for (int32_t abs = 0; abs <= ABS_MAX; abs++) { - if (!(getAbsAxisUsage(abs, getDevice()->getClasses()) - & INPUT_DEVICE_CLASS_JOYSTICK)) { - continue; // axis must be claimed by a different device - } - - RawAbsoluteAxisInfo rawAxisInfo; - getAbsoluteAxisInfo(abs, &rawAxisInfo); - if (rawAxisInfo.valid) { - // Map axis. - AxisInfo axisInfo; - bool explicitlyMapped = !getEventHub()->mapAxis(getDeviceId(), abs, &axisInfo); - if (!explicitlyMapped) { - // Axis is not explicitly mapped, will choose a generic axis later. - axisInfo.mode = AxisInfo::MODE_NORMAL; - axisInfo.axis = -1; - } - - // Apply flat override. - int32_t rawFlat = axisInfo.flatOverride < 0 - ? rawAxisInfo.flat : axisInfo.flatOverride; - - // Calculate scaling factors and limits. - Axis axis; - if (axisInfo.mode == AxisInfo::MODE_SPLIT) { - float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue); - float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, highScale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else if (isCenteredAxis(axisInfo.axis)) { - float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale; - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, offset, scale, offset, - -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } else { - float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue); - axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, - scale, 0.0f, scale, 0.0f, - 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale, - rawAxisInfo.resolution * scale); - } - - // To eliminate noise while the joystick is at rest, filter out small variations - // in axis values up front. - axis.filter = axis.flat * 0.25f; - - mAxes.add(abs, axis); - } - } - - // If there are too many axes, start dropping them. - // Prefer to keep explicitly mapped axes. - if (mAxes.size() > PointerCoords::MAX_AXES) { - ALOGI("Joystick '%s' has %d axes but the framework only supports a maximum of %d.", - getDeviceName().string(), mAxes.size(), PointerCoords::MAX_AXES); - pruneAxes(true); - pruneAxes(false); - } - - // Assign generic axis ids to remaining axes. - int32_t nextGenericAxisId = AMOTION_EVENT_AXIS_GENERIC_1; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (axis.axisInfo.axis < 0) { - while (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16 - && haveAxis(nextGenericAxisId)) { - nextGenericAxisId += 1; - } - - if (nextGenericAxisId <= AMOTION_EVENT_AXIS_GENERIC_16) { - axis.axisInfo.axis = nextGenericAxisId; - nextGenericAxisId += 1; - } else { - ALOGI("Ignoring joystick '%s' axis %d because all of the generic axis ids " - "have already been assigned to other axes.", - getDeviceName().string(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i--); - numAxes -= 1; - } - } - } - } -} - -bool JoystickInputMapper::haveAxis(int32_t axisId) { - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - if (axis.axisInfo.axis == axisId - || (axis.axisInfo.mode == AxisInfo::MODE_SPLIT - && axis.axisInfo.highAxis == axisId)) { - return true; - } - } - return false; -} - -void JoystickInputMapper::pruneAxes(bool ignoreExplicitlyMappedAxes) { - size_t i = mAxes.size(); - while (mAxes.size() > PointerCoords::MAX_AXES && i-- > 0) { - if (ignoreExplicitlyMappedAxes && mAxes.valueAt(i).explicitlyMapped) { - continue; - } - ALOGI("Discarding joystick '%s' axis %d because there are too many axes.", - getDeviceName().string(), mAxes.keyAt(i)); - mAxes.removeItemsAt(i); - } -} - -bool JoystickInputMapper::isCenteredAxis(int32_t axis) { - switch (axis) { - case AMOTION_EVENT_AXIS_X: - case AMOTION_EVENT_AXIS_Y: - case AMOTION_EVENT_AXIS_Z: - case AMOTION_EVENT_AXIS_RX: - case AMOTION_EVENT_AXIS_RY: - case AMOTION_EVENT_AXIS_RZ: - case AMOTION_EVENT_AXIS_HAT_X: - case AMOTION_EVENT_AXIS_HAT_Y: - case AMOTION_EVENT_AXIS_ORIENTATION: - case AMOTION_EVENT_AXIS_RUDDER: - case AMOTION_EVENT_AXIS_WHEEL: - return true; - default: - return false; - } -} - -void JoystickInputMapper::reset(nsecs_t when) { - // Recenter all axes. - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - axis.resetValue(); - } - - InputMapper::reset(when); -} - -void JoystickInputMapper::process(const RawEvent* rawEvent) { - switch (rawEvent->type) { - case EV_ABS: { - ssize_t index = mAxes.indexOfKey(rawEvent->code); - if (index >= 0) { - Axis& axis = mAxes.editValueAt(index); - float newValue, highNewValue; - switch (axis.axisInfo.mode) { - case AxisInfo::MODE_INVERT: - newValue = (axis.rawAxisInfo.maxValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - case AxisInfo::MODE_SPLIT: - if (rawEvent->value < axis.axisInfo.splitValue) { - newValue = (axis.axisInfo.splitValue - rawEvent->value) - * axis.scale + axis.offset; - highNewValue = 0.0f; - } else if (rawEvent->value > axis.axisInfo.splitValue) { - newValue = 0.0f; - highNewValue = (rawEvent->value - axis.axisInfo.splitValue) - * axis.highScale + axis.highOffset; - } else { - newValue = 0.0f; - highNewValue = 0.0f; - } - break; - default: - newValue = rawEvent->value * axis.scale + axis.offset; - highNewValue = 0.0f; - break; - } - axis.newValue = newValue; - axis.highNewValue = highNewValue; - } - break; - } - - case EV_SYN: - switch (rawEvent->code) { - case SYN_REPORT: - sync(rawEvent->when, false /*force*/); - break; - } - break; - } -} - -void JoystickInputMapper::sync(nsecs_t when, bool force) { - if (!filterAxes(force)) { - return; - } - - int32_t metaState = mContext->getGlobalMetaState(); - int32_t buttonState = 0; - - PointerProperties pointerProperties; - pointerProperties.clear(); - pointerProperties.id = 0; - pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; - - PointerCoords pointerCoords; - pointerCoords.clear(); - - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - const Axis& axis = mAxes.valueAt(i); - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.axis, axis.currentValue); - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - setPointerCoordsAxisValue(&pointerCoords, axis.axisInfo.highAxis, - axis.highCurrentValue); - } - } - - // Moving a joystick axis should not wake the device because joysticks can - // be fairly noisy even when not in use. On the other hand, pushing a gamepad - // button will likely wake the device. - // TODO: Use the input device configuration to control this behavior more finely. - uint32_t policyFlags = 0; - - NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - ADISPLAY_ID_NONE, 1, &pointerProperties, &pointerCoords, 0, 0, 0); - getListener()->notifyMotion(&args); -} - -void JoystickInputMapper::setPointerCoordsAxisValue(PointerCoords* pointerCoords, - int32_t axis, float value) { - pointerCoords->setAxisValue(axis, value); - /* In order to ease the transition for developers from using the old axes - * to the newer, more semantically correct axes, we'll continue to produce - * values for the old axes as mirrors of the value of their corresponding - * new axes. */ - int32_t compatAxis = getCompatAxis(axis); - if (compatAxis >= 0) { - pointerCoords->setAxisValue(compatAxis, value); - } -} - -bool JoystickInputMapper::filterAxes(bool force) { - bool atLeastOneSignificantChange = force; - size_t numAxes = mAxes.size(); - for (size_t i = 0; i < numAxes; i++) { - Axis& axis = mAxes.editValueAt(i); - if (force || hasValueChangedSignificantly(axis.filter, - axis.newValue, axis.currentValue, axis.min, axis.max)) { - axis.currentValue = axis.newValue; - atLeastOneSignificantChange = true; - } - if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) { - if (force || hasValueChangedSignificantly(axis.filter, - axis.highNewValue, axis.highCurrentValue, axis.min, axis.max)) { - axis.highCurrentValue = axis.highNewValue; - atLeastOneSignificantChange = true; - } - } - } - return atLeastOneSignificantChange; -} - -bool JoystickInputMapper::hasValueChangedSignificantly( - float filter, float newValue, float currentValue, float min, float max) { - if (newValue != currentValue) { - // Filter out small changes in value unless the value is converging on the axis - // bounds or center point. This is intended to reduce the amount of information - // sent to applications by particularly noisy joysticks (such as PS3). - if (fabs(newValue - currentValue) > filter - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, min) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, max) - || hasMovedNearerToValueWithinFilteredRange(filter, newValue, currentValue, 0)) { - return true; - } - } - return false; -} - -bool JoystickInputMapper::hasMovedNearerToValueWithinFilteredRange( - float filter, float newValue, float currentValue, float thresholdValue) { - float newDistance = fabs(newValue - thresholdValue); - if (newDistance < filter) { - float oldDistance = fabs(currentValue - thresholdValue); - if (newDistance < oldDistance) { - return true; - } - } - return false; -} - -} // namespace android diff --git a/widget/gonk/libui/InputReader.h b/widget/gonk/libui/InputReader.h deleted file mode 100644 index 5c790fdb8..000000000 --- a/widget/gonk/libui/InputReader.h +++ /dev/null @@ -1,1811 +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. - */ - -#ifndef _UI_INPUT_READER_H -#define _UI_INPUT_READER_H - -#include "EventHub.h" -#include "PointerController.h" -#include "InputListener.h" - -#include "Input.h" -#include "VelocityControl.h" -#include "VelocityTracker.h" -#include -#include -#include -#include -#include -#include - -#include -#include - -// Maximum supported size of a vibration pattern. -// Must be at least 2. -#define MAX_VIBRATE_PATTERN_SIZE 100 - -// Maximum allowable delay value in a vibration pattern before -// which the delay will be truncated. -#define MAX_VIBRATE_PATTERN_DELAY_NSECS (1000000 * 1000000000LL) - -namespace android { - -class InputDevice; -class InputMapper; - -/* - * Describes how coordinates are mapped on a physical display. - * See com.android.server.display.DisplayViewport. - */ -struct DisplayViewport { - int32_t displayId; // -1 if invalid - int32_t orientation; - int32_t logicalLeft; - int32_t logicalTop; - int32_t logicalRight; - int32_t logicalBottom; - int32_t physicalLeft; - int32_t physicalTop; - int32_t physicalRight; - int32_t physicalBottom; - int32_t deviceWidth; - int32_t deviceHeight; - - DisplayViewport() : - displayId(ADISPLAY_ID_NONE), orientation(DISPLAY_ORIENTATION_0), - logicalLeft(0), logicalTop(0), logicalRight(0), logicalBottom(0), - physicalLeft(0), physicalTop(0), physicalRight(0), physicalBottom(0), - deviceWidth(0), deviceHeight(0) { - } - - bool operator==(const DisplayViewport& other) const { - return displayId == other.displayId - && orientation == other.orientation - && logicalLeft == other.logicalLeft - && logicalTop == other.logicalTop - && logicalRight == other.logicalRight - && logicalBottom == other.logicalBottom - && physicalLeft == other.physicalLeft - && physicalTop == other.physicalTop - && physicalRight == other.physicalRight - && physicalBottom == other.physicalBottom - && deviceWidth == other.deviceWidth - && deviceHeight == other.deviceHeight; - } - - bool operator!=(const DisplayViewport& other) const { - return !(*this == other); - } - - inline bool isValid() const { - return displayId >= 0; - } - - void setNonDisplayViewport(int32_t width, int32_t height) { - displayId = ADISPLAY_ID_NONE; - orientation = DISPLAY_ORIENTATION_0; - logicalLeft = 0; - logicalTop = 0; - logicalRight = width; - logicalBottom = height; - physicalLeft = 0; - physicalTop = 0; - physicalRight = width; - physicalBottom = height; - deviceWidth = width; - deviceHeight = height; - } -}; - -/* - * Input reader configuration. - * - * Specifies various options that modify the behavior of the input reader. - */ -struct InputReaderConfiguration { - // Describes changes that have occurred. - enum { - // The pointer speed changed. - CHANGE_POINTER_SPEED = 1 << 0, - - // The pointer gesture control changed. - CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1, - - // The display size or orientation changed. - CHANGE_DISPLAY_INFO = 1 << 2, - - // The visible touches option changed. - CHANGE_SHOW_TOUCHES = 1 << 3, - - // The keyboard layouts must be reloaded. - CHANGE_KEYBOARD_LAYOUTS = 1 << 4, - - // The device name alias supplied by the may have changed for some devices. - CHANGE_DEVICE_ALIAS = 1 << 5, - - // All devices must be reopened. - CHANGE_MUST_REOPEN = 1 << 31, - }; - - // Gets the amount of time to disable virtual keys after the screen is touched - // in order to filter out accidental virtual key presses due to swiping gestures - // or taps near the edge of the display. May be 0 to disable the feature. - nsecs_t virtualKeyQuietTime; - - // The excluded device names for the platform. - // Devices with these names will be ignored. - Vector excludedDeviceNames; - - // Velocity control parameters for mouse pointer movements. - VelocityControlParameters pointerVelocityControlParameters; - - // Velocity control parameters for mouse wheel movements. - VelocityControlParameters wheelVelocityControlParameters; - - // True if pointer gestures are enabled. - bool pointerGesturesEnabled; - - // Quiet time between certain pointer gesture transitions. - // Time to allow for all fingers or buttons to settle into a stable state before - // starting a new gesture. - nsecs_t pointerGestureQuietInterval; - - // The minimum speed that a pointer must travel for us to consider switching the active - // touch pointer to it during a drag. This threshold is set to avoid switching due - // to noise from a finger resting on the touch pad (perhaps just pressing it down). - float pointerGestureDragMinSwitchSpeed; // in pixels per second - - // Tap gesture delay time. - // The time between down and up must be less than this to be considered a tap. - nsecs_t pointerGestureTapInterval; - - // Tap drag gesture delay time. - // The time between the previous tap's up and the next down must be less than - // this to be considered a drag. Otherwise, the previous tap is finished and a - // new tap begins. - // - // Note that the previous tap will be held down for this entire duration so this - // interval must be shorter than the long press timeout. - nsecs_t pointerGestureTapDragInterval; - - // The distance in pixels that the pointer is allowed to move from initial down - // to up and still be called a tap. - float pointerGestureTapSlop; // in pixels - - // Time after the first touch points go down to settle on an initial centroid. - // This is intended to be enough time to handle cases where the user puts down two - // fingers at almost but not quite exactly the same time. - nsecs_t pointerGestureMultitouchSettleInterval; - - // The transition from PRESS to SWIPE or FREEFORM gesture mode is made when - // at least two pointers have moved at least this far from their starting place. - float pointerGestureMultitouchMinDistance; // in pixels - - // The transition from PRESS to SWIPE gesture mode can only occur when the - // cosine of the angle between the two vectors is greater than or equal to than this value - // which indicates that the vectors are oriented in the same direction. - // When the vectors are oriented in the exactly same direction, the cosine is 1.0. - // (In exactly opposite directions, the cosine is -1.0.) - float pointerGestureSwipeTransitionAngleCosine; - - // The transition from PRESS to SWIPE gesture mode can only occur when the - // fingers are no more than this far apart relative to the diagonal size of - // the touch pad. For example, a ratio of 0.5 means that the fingers must be - // no more than half the diagonal size of the touch pad apart. - float pointerGestureSwipeMaxWidthRatio; - - // The gesture movement speed factor relative to the size of the display. - // Movement speed applies when the fingers are moving in the same direction. - // Without acceleration, a full swipe of the touch pad diagonal in movement mode - // will cover this portion of the display diagonal. - float pointerGestureMovementSpeedRatio; - - // The gesture zoom speed factor relative to the size of the display. - // Zoom speed applies when the fingers are mostly moving relative to each other - // to execute a scale gesture or similar. - // Without acceleration, a full swipe of the touch pad diagonal in zoom mode - // will cover this portion of the display diagonal. - float pointerGestureZoomSpeedRatio; - - // True to show the location of touches on the touch screen as spots. - bool showTouches; - - InputReaderConfiguration() : - virtualKeyQuietTime(0), - pointerVelocityControlParameters(1.0f, 500.0f, 3000.0f, 3.0f), - wheelVelocityControlParameters(1.0f, 15.0f, 50.0f, 4.0f), - pointerGesturesEnabled(true), - pointerGestureQuietInterval(100 * 1000000LL), // 100 ms - pointerGestureDragMinSwitchSpeed(50), // 50 pixels per second - pointerGestureTapInterval(150 * 1000000LL), // 150 ms - pointerGestureTapDragInterval(150 * 1000000LL), // 150 ms - pointerGestureTapSlop(10.0f), // 10 pixels - pointerGestureMultitouchSettleInterval(100 * 1000000LL), // 100 ms - pointerGestureMultitouchMinDistance(15), // 15 pixels - pointerGestureSwipeTransitionAngleCosine(0.2588f), // cosine of 75 degrees - pointerGestureSwipeMaxWidthRatio(0.25f), - pointerGestureMovementSpeedRatio(0.8f), - pointerGestureZoomSpeedRatio(0.3f), - showTouches(false) { } - - bool getDisplayInfo(bool external, DisplayViewport* outViewport) const; - void setDisplayInfo(bool external, const DisplayViewport& viewport); - -private: - DisplayViewport mInternalDisplay; - DisplayViewport mExternalDisplay; -}; - - -/* - * Input reader policy interface. - * - * The input reader policy is used by the input reader to interact with the Window Manager - * and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - * - * These methods must NOT re-enter the input reader since they may be called while - * holding the input reader lock. - */ -class InputReaderPolicyInterface : public virtual RefBase { -protected: - InputReaderPolicyInterface() { } - virtual ~InputReaderPolicyInterface() { } - -public: - /* Gets the input reader configuration. */ - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0; - - /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */ - virtual sp obtainPointerController(int32_t deviceId) = 0; - - /* Notifies the input reader policy that some input devices have changed - * and provides information about all current input devices. - */ - virtual void notifyInputDevicesChanged(const Vector& inputDevices) = 0; - - /* Gets the keyboard layout for a particular input device. */ - virtual sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) = 0; - - /* Gets a user-supplied alias for a particular input device, or an empty string if none. */ - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) = 0; -}; - - -/* Processes raw input events and sends cooked event data to an input listener. */ -class InputReaderInterface : public virtual RefBase { -protected: - InputReaderInterface() { } - virtual ~InputReaderInterface() { } - -public: - /* Dumps the state of the input reader. - * - * This method may be called on any thread (usually by the input manager). */ - virtual void dump(String8& dump) = 0; - - /* Called by the heatbeat to ensures that the reader has not deadlocked. */ - virtual void monitor() = 0; - - /* Runs a single iteration of the processing loop. - * Nominally reads and processes one incoming message from the EventHub. - * - * This method should be called on the input reader thread. - */ - virtual void loopOnce() = 0; - - /* Gets information about all input devices. - * - * This method may be called on any thread (usually by the input manager). - */ - virtual void getInputDevices(Vector& outInputDevices) = 0; - - /* Query current input state. */ - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode) = 0; - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode) = 0; - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw) = 0; - - /* Determine whether physical keys exist for the given framework-domain key codes. */ - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags) = 0; - - /* Requests that a reconfiguration of all input devices. - * The changes flag is a bitfield that indicates what has changed and whether - * the input devices must all be reopened. */ - virtual void requestRefreshConfiguration(uint32_t changes) = 0; - - /* Controls the vibrator of a particular input device. */ - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token) = 0; - virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; -}; - - -/* Internal interface used by individual input devices to access global input device state - * and parameters maintained by the input reader. - */ -class InputReaderContext { -public: - InputReaderContext() { } - virtual ~InputReaderContext() { } - - virtual void updateGlobalMetaState() = 0; - virtual int32_t getGlobalMetaState() = 0; - - virtual void disableVirtualKeysUntil(nsecs_t time) = 0; - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode) = 0; - - virtual void fadePointer() = 0; - - virtual void requestTimeoutAtTime(nsecs_t when) = 0; - virtual int32_t bumpGeneration() = 0; - - virtual InputReaderPolicyInterface* getPolicy() = 0; - virtual InputListenerInterface* getListener() = 0; - virtual EventHubInterface* getEventHub() = 0; -}; - - -/* The input reader reads raw event data from the event hub and processes it into input events - * that it sends to the input listener. Some functions of the input reader, such as early - * event filtering in low power states, are controlled by a separate policy object. - * - * The InputReader owns a collection of InputMappers. Most of the work it does happens - * on the input reader thread but the InputReader can receive queries from other system - * components running on arbitrary threads. To keep things manageable, the InputReader - * uses a single Mutex to guard its state. The Mutex may be held while calling into the - * EventHub or the InputReaderPolicy but it is never held while calling into the - * InputListener. - */ -class InputReader : public InputReaderInterface { -public: - InputReader(const sp& eventHub, - const sp& policy, - const sp& listener); - virtual ~InputReader(); - - virtual void dump(String8& dump); - virtual void monitor(); - - virtual void loopOnce(); - - virtual void getInputDevices(Vector& outInputDevices); - - virtual int32_t getScanCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t scanCode); - virtual int32_t getKeyCodeState(int32_t deviceId, uint32_t sourceMask, - int32_t keyCode); - virtual int32_t getSwitchState(int32_t deviceId, uint32_t sourceMask, - int32_t sw); - - virtual bool hasKeys(int32_t deviceId, uint32_t sourceMask, - size_t numCodes, const int32_t* keyCodes, uint8_t* outFlags); - - virtual void requestRefreshConfiguration(uint32_t changes); - - virtual void vibrate(int32_t deviceId, const nsecs_t* pattern, size_t patternSize, - ssize_t repeat, int32_t token); - virtual void cancelVibrate(int32_t deviceId, int32_t token); - -protected: - // These members are protected so they can be instrumented by test cases. - virtual InputDevice* createDeviceLocked(int32_t deviceId, - const InputDeviceIdentifier& identifier, uint32_t classes); - - class ContextImpl : public InputReaderContext { - InputReader* mReader; - - public: - ContextImpl(InputReader* reader); - - virtual void updateGlobalMetaState(); - virtual int32_t getGlobalMetaState(); - virtual void disableVirtualKeysUntil(nsecs_t time); - virtual bool shouldDropVirtualKey(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - virtual void fadePointer(); - virtual void requestTimeoutAtTime(nsecs_t when); - virtual int32_t bumpGeneration(); - virtual InputReaderPolicyInterface* getPolicy(); - virtual InputListenerInterface* getListener(); - virtual EventHubInterface* getEventHub(); - } mContext; - - friend class ContextImpl; - -private: - Mutex mLock; - - Condition mReaderIsAliveCondition; - - sp mEventHub; - sp mPolicy; - sp mQueuedListener; - - InputReaderConfiguration mConfig; - - // The event queue. - static const int EVENT_BUFFER_SIZE = 256; - RawEvent mEventBuffer[EVENT_BUFFER_SIZE]; - - KeyedVector mDevices; - - // low-level input event decoding and device management - void processEventsLocked(const RawEvent* rawEvents, size_t count); - - void addDeviceLocked(nsecs_t when, int32_t deviceId); - void removeDeviceLocked(nsecs_t when, int32_t deviceId); - void processEventsForDeviceLocked(int32_t deviceId, const RawEvent* rawEvents, size_t count); - void timeoutExpiredLocked(nsecs_t when); - - void handleConfigurationChangedLocked(nsecs_t when); - - int32_t mGlobalMetaState; - void updateGlobalMetaStateLocked(); - int32_t getGlobalMetaStateLocked(); - - void fadePointerLocked(); - - int32_t mGeneration; - int32_t bumpGenerationLocked(); - - void getInputDevicesLocked(Vector& outInputDevices); - - nsecs_t mDisableVirtualKeysTimeout; - void disableVirtualKeysUntilLocked(nsecs_t time); - bool shouldDropVirtualKeyLocked(nsecs_t now, - InputDevice* device, int32_t keyCode, int32_t scanCode); - - nsecs_t mNextTimeout; - void requestTimeoutAtTimeLocked(nsecs_t when); - - uint32_t mConfigurationChangesToRefresh; - void refreshConfigurationLocked(uint32_t changes); - - // state queries - typedef int32_t (InputDevice::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getStateLocked(int32_t deviceId, uint32_t sourceMask, int32_t code, - GetStateFunc getStateFunc); - bool markSupportedKeyCodesLocked(int32_t deviceId, uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); -}; - - -/* Reads raw events from the event hub and processes them, endlessly. */ -class InputReaderThread : public Thread { -public: - InputReaderThread(const sp& reader); - virtual ~InputReaderThread(); - -private: - uint32_t mFoo; - sp mReader; - - virtual bool threadLoop(); -}; - - -/* Represents the state of a single input device. */ -class InputDevice { -public: - InputDevice(InputReaderContext* context, int32_t id, int32_t generation, - const InputDeviceIdentifier& identifier, uint32_t classes); - ~InputDevice(); - - inline InputReaderContext* getContext() { return mContext; } - inline int32_t getId() { return mId; } - inline int32_t getGeneration() { return mGeneration; } - inline const String8& getName() { return mIdentifier.name; } - inline uint32_t getClasses() { return mClasses; } - inline uint32_t getSources() { return mSources; } - - inline bool isExternal() { return mIsExternal; } - inline void setExternal(bool external) { mIsExternal = external; } - - inline bool isIgnored() { return mMappers.isEmpty(); } - - void dump(String8& dump); - void addMapper(InputMapper* mapper); - void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - void reset(nsecs_t when); - void process(const RawEvent* rawEvents, size_t count); - void timeoutExpired(nsecs_t when); - - void getDeviceInfo(InputDeviceInfo* outDeviceInfo); - int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); - void cancelVibrate(int32_t token); - - int32_t getMetaState(); - - void fadePointer(); - - void bumpGeneration(); - - void notifyReset(nsecs_t when); - - inline const PropertyMap& getConfiguration() { return mConfiguration; } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - bool hasKey(int32_t code) { - return getEventHub()->hasScanCode(mId, code); - } - - bool hasAbsoluteAxis(int32_t code) { - RawAbsoluteAxisInfo info; - getEventHub()->getAbsoluteAxisInfo(mId, code, &info); - return info.valid; - } - - bool isKeyPressed(int32_t code) { - return getEventHub()->getScanCodeState(mId, code) == AKEY_STATE_DOWN; - } - - int32_t getAbsoluteAxisValue(int32_t code) { - int32_t value; - getEventHub()->getAbsoluteAxisValue(mId, code, &value); - return value; - } - -private: - InputReaderContext* mContext; - int32_t mId; - int32_t mGeneration; - InputDeviceIdentifier mIdentifier; - String8 mAlias; - uint32_t mClasses; - - Vector mMappers; - - uint32_t mSources; - bool mIsExternal; - bool mDropUntilNextSync; - - typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); - int32_t getState(uint32_t sourceMask, int32_t code, GetStateFunc getStateFunc); - - PropertyMap mConfiguration; -}; - - -/* Keeps track of the state of mouse or touch pad buttons. */ -class CursorButtonAccumulator { -public: - CursorButtonAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - -private: - bool mBtnLeft; - bool mBtnRight; - bool mBtnMiddle; - bool mBtnBack; - bool mBtnSide; - bool mBtnForward; - bool mBtnExtra; - bool mBtnTask; - - void clearButtons(); -}; - - -/* Keeps track of cursor movements. */ - -class CursorMotionAccumulator { -public: - CursorMotionAccumulator(); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - -private: - int32_t mRelX; - int32_t mRelY; - - void clearRelativeAxes(); -}; - - -/* Keeps track of cursor scrolling motions. */ - -class CursorScrollAccumulator { -public: - CursorScrollAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - void finishSync(); - - inline bool haveRelativeVWheel() const { return mHaveRelWheel; } - inline bool haveRelativeHWheel() const { return mHaveRelHWheel; } - - inline int32_t getRelativeX() const { return mRelX; } - inline int32_t getRelativeY() const { return mRelY; } - inline int32_t getRelativeVWheel() const { return mRelWheel; } - inline int32_t getRelativeHWheel() const { return mRelHWheel; } - -private: - bool mHaveRelWheel; - bool mHaveRelHWheel; - - int32_t mRelX; - int32_t mRelY; - int32_t mRelWheel; - int32_t mRelHWheel; - - void clearRelativeAxes(); -}; - - -/* Keeps track of the state of touch, stylus and tool buttons. */ -class TouchButtonAccumulator { -public: - TouchButtonAccumulator(); - void configure(InputDevice* device); - void reset(InputDevice* device); - - void process(const RawEvent* rawEvent); - - uint32_t getButtonState() const; - int32_t getToolType() const; - bool isToolActive() const; - bool isHovering() const; - bool hasStylus() const; - -private: - bool mHaveBtnTouch; - bool mHaveStylus; - - bool mBtnTouch; - bool mBtnStylus; - bool mBtnStylus2; - bool mBtnToolFinger; - bool mBtnToolPen; - bool mBtnToolRubber; - bool mBtnToolBrush; - bool mBtnToolPencil; - bool mBtnToolAirbrush; - bool mBtnToolMouse; - bool mBtnToolLens; - bool mBtnToolDoubleTap; - bool mBtnToolTripleTap; - bool mBtnToolQuadTap; - - void clearButtons(); -}; - - -/* Raw axis information from the driver. */ -struct RawPointerAxes { - RawAbsoluteAxisInfo x; - RawAbsoluteAxisInfo y; - RawAbsoluteAxisInfo pressure; - RawAbsoluteAxisInfo touchMajor; - RawAbsoluteAxisInfo touchMinor; - RawAbsoluteAxisInfo toolMajor; - RawAbsoluteAxisInfo toolMinor; - RawAbsoluteAxisInfo orientation; - RawAbsoluteAxisInfo distance; - RawAbsoluteAxisInfo tiltX; - RawAbsoluteAxisInfo tiltY; - RawAbsoluteAxisInfo trackingId; - RawAbsoluteAxisInfo slot; - - RawPointerAxes(); - void clear(); -}; - - -/* Raw data for a collection of pointers including a pointer id mapping table. */ -struct RawPointerData { - struct Pointer { - uint32_t id; - int32_t x; - int32_t y; - int32_t pressure; - int32_t touchMajor; - int32_t touchMinor; - int32_t toolMajor; - int32_t toolMinor; - int32_t orientation; - int32_t distance; - int32_t tiltX; - int32_t tiltY; - int32_t toolType; // a fully decoded AMOTION_EVENT_TOOL_TYPE constant - bool isHovering; - }; - - uint32_t pointerCount; - Pointer pointers[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - RawPointerData(); - void clear(); - void copyFrom(const RawPointerData& other); - void getCentroidOfTouchingPointers(float* outX, float* outY) const; - - inline void markIdBit(uint32_t id, bool isHovering) { - if (isHovering) { - hoveringIdBits.markBit(id); - } else { - touchingIdBits.markBit(id); - } - } - - inline void clearIdBits() { - hoveringIdBits.clear(); - touchingIdBits.clear(); - } - - inline const Pointer& pointerForId(uint32_t id) const { - return pointers[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return pointers[pointerIndex].isHovering; - } -}; - - -/* Cooked data for a collection of pointers including a pointer id mapping table. */ -struct CookedPointerData { - uint32_t pointerCount; - PointerProperties pointerProperties[MAX_POINTERS]; - PointerCoords pointerCoords[MAX_POINTERS]; - BitSet32 hoveringIdBits, touchingIdBits; - uint32_t idToIndex[MAX_POINTER_ID + 1]; - - CookedPointerData(); - void clear(); - void copyFrom(const CookedPointerData& other); - - inline const PointerCoords& pointerCoordsForId(uint32_t id) const { - return pointerCoords[idToIndex[id]]; - } - - inline bool isHovering(uint32_t pointerIndex) { - return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); - } -}; - - -/* Keeps track of the state of single-touch protocol. */ -class SingleTouchMotionAccumulator { -public: - SingleTouchMotionAccumulator(); - - void process(const RawEvent* rawEvent); - void reset(InputDevice* device); - - inline int32_t getAbsoluteX() const { return mAbsX; } - inline int32_t getAbsoluteY() const { return mAbsY; } - inline int32_t getAbsolutePressure() const { return mAbsPressure; } - inline int32_t getAbsoluteToolWidth() const { return mAbsToolWidth; } - inline int32_t getAbsoluteDistance() const { return mAbsDistance; } - inline int32_t getAbsoluteTiltX() const { return mAbsTiltX; } - inline int32_t getAbsoluteTiltY() const { return mAbsTiltY; } - -private: - int32_t mAbsX; - int32_t mAbsY; - int32_t mAbsPressure; - int32_t mAbsToolWidth; - int32_t mAbsDistance; - int32_t mAbsTiltX; - int32_t mAbsTiltY; - - void clearAbsoluteAxes(); -}; - - -/* Keeps track of the state of multi-touch protocol. */ -class MultiTouchMotionAccumulator { -public: - class Slot { - public: - inline bool isInUse() const { return mInUse; } - inline int32_t getX() const { return mAbsMTPositionX; } - inline int32_t getY() const { return mAbsMTPositionY; } - inline int32_t getTouchMajor() const { return mAbsMTTouchMajor; } - inline int32_t getTouchMinor() const { - return mHaveAbsMTTouchMinor ? mAbsMTTouchMinor : mAbsMTTouchMajor; } - inline int32_t getToolMajor() const { return mAbsMTWidthMajor; } - inline int32_t getToolMinor() const { - return mHaveAbsMTWidthMinor ? mAbsMTWidthMinor : mAbsMTWidthMajor; } - inline int32_t getOrientation() const { return mAbsMTOrientation; } - inline int32_t getTrackingId() const { return mAbsMTTrackingId; } - inline int32_t getPressure() const { return mAbsMTPressure; } - inline int32_t getDistance() const { return mAbsMTDistance; } - inline int32_t getToolType() const; - - private: - friend class MultiTouchMotionAccumulator; - - bool mInUse; - bool mHaveAbsMTTouchMinor; - bool mHaveAbsMTWidthMinor; - bool mHaveAbsMTToolType; - - int32_t mAbsMTPositionX; - int32_t mAbsMTPositionY; - int32_t mAbsMTTouchMajor; - int32_t mAbsMTTouchMinor; - int32_t mAbsMTWidthMajor; - int32_t mAbsMTWidthMinor; - int32_t mAbsMTOrientation; - int32_t mAbsMTTrackingId; - int32_t mAbsMTPressure; - int32_t mAbsMTDistance; - int32_t mAbsMTToolType; - - Slot(); - void clear(); - }; - - MultiTouchMotionAccumulator(); - ~MultiTouchMotionAccumulator(); - - void configure(InputDevice* device, size_t slotCount, bool usingSlotsProtocol); - void reset(InputDevice* device); - void process(const RawEvent* rawEvent); - void finishSync(); - bool hasStylus() const; - - inline size_t getSlotCount() const { return mSlotCount; } - inline const Slot* getSlot(size_t index) const { return &mSlots[index]; } - -private: - int32_t mCurrentSlot; - Slot* mSlots; - size_t mSlotCount; - bool mUsingSlotsProtocol; - bool mHaveStylus; - - void clearSlots(int32_t initialSlot); -}; - - -/* An input mapper transforms raw input events into cooked event data. - * A single input device can have multiple associated input mappers in order to interpret - * different classes of events. - * - * InputMapper lifecycle: - * - create - * - configure with 0 changes - * - reset - * - process, process, process (may occasionally reconfigure with non-zero changes or reset) - * - reset - * - destroy - */ -class InputMapper { -public: - InputMapper(InputDevice* device); - virtual ~InputMapper(); - - inline InputDevice* getDevice() { return mDevice; } - inline int32_t getDeviceId() { return mDevice->getId(); } - inline const String8 getDeviceName() { return mDevice->getName(); } - inline InputReaderContext* getContext() { return mContext; } - inline InputReaderPolicyInterface* getPolicy() { return mContext->getPolicy(); } - inline InputListenerInterface* getListener() { return mContext->getListener(); } - inline EventHubInterface* getEventHub() { return mContext->getEventHub(); } - - virtual uint32_t getSources() = 0; - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent) = 0; - virtual void timeoutExpired(nsecs_t when); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - - virtual int32_t getMetaState(); - - virtual void fadePointer(); - -protected: - InputDevice* mDevice; - InputReaderContext* mContext; - - status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo); - void bumpGeneration(); - - static void dumpRawAbsoluteAxisInfo(String8& dump, - const RawAbsoluteAxisInfo& axis, const char* name); -}; - - -class SwitchInputMapper : public InputMapper { -public: - SwitchInputMapper(InputDevice* device); - virtual ~SwitchInputMapper(); - - virtual uint32_t getSources(); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode); - -private: - uint32_t mUpdatedSwitchValues; - uint32_t mUpdatedSwitchMask; - - void processSwitch(int32_t switchCode, int32_t switchValue); - void sync(nsecs_t when); -}; - - -class VibratorInputMapper : public InputMapper { -public: - VibratorInputMapper(InputDevice* device); - virtual ~VibratorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void process(const RawEvent* rawEvent); - - virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, - int32_t token); - virtual void cancelVibrate(int32_t token); - virtual void timeoutExpired(nsecs_t when); - virtual void dump(String8& dump); - -private: - bool mVibrating; - nsecs_t mPattern[MAX_VIBRATE_PATTERN_SIZE]; - size_t mPatternSize; - ssize_t mRepeat; - int32_t mToken; - ssize_t mIndex; - nsecs_t mNextStepTime; - - void nextStep(); - void stopVibrating(); -}; - - -class KeyboardInputMapper : public InputMapper { -public: - KeyboardInputMapper(InputDevice* device, uint32_t source, int32_t keyboardType); - virtual ~KeyboardInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual int32_t getMetaState(); - -private: - struct KeyDown { - int32_t keyCode; - int32_t scanCode; - }; - - uint32_t mSource; - int32_t mKeyboardType; - - int32_t mOrientation; // orientation for dpad keys - - Vector mKeyDowns; // keys that are down - int32_t mMetaState; - nsecs_t mDownTime; // time of most recent key down - - int32_t mCurrentHidUsage; // most recent HID usage seen this packet, or 0 if none - - struct LedState { - bool avail; // led is available - bool on; // we think the led is currently on - }; - LedState mCapsLockLedState; - LedState mNumLockLedState; - LedState mScrollLockLedState; - - // Immutable configuration parameters. - struct Parameters { - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - void configureParameters(); - void dumpParameters(String8& dump); - - bool isKeyboardOrGamepadKey(int32_t scanCode); - - void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode, - uint32_t policyFlags); - - ssize_t findKeyDown(int32_t scanCode); - - void resetLedState(); - void initializeLedState(LedState& ledState, int32_t led); - void updateLedState(bool reset); - void updateLedStateForModifier(LedState& ledState, int32_t led, - int32_t modifier, bool reset); -}; - - -class CursorInputMapper : public InputMapper { -public: - CursorInputMapper(InputDevice* device); - virtual ~CursorInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - - virtual void fadePointer(); - -private: - // Amount that trackball needs to move in order to generate a key event. - static const int32_t TRACKBALL_MOVEMENT_THRESHOLD = 6; - - // Immutable configuration parameters. - struct Parameters { - enum Mode { - MODE_POINTER, - MODE_NAVIGATION, - }; - - Mode mode; - bool hasAssociatedDisplay; - bool orientationAware; - } mParameters; - - CursorButtonAccumulator mCursorButtonAccumulator; - CursorMotionAccumulator mCursorMotionAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - - int32_t mSource; - float mXScale; - float mYScale; - float mXPrecision; - float mYPrecision; - - float mVWheelScale; - float mHWheelScale; - - // Velocity controls for mouse pointer and wheel movements. - // The controls for X and Y wheel movements are separate to keep them decoupled. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - int32_t mOrientation; - - sp mPointerController; - - int32_t mButtonState; - nsecs_t mDownTime; - - void configureParameters(); - void dumpParameters(String8& dump); - - void sync(nsecs_t when); -}; - - -class TouchInputMapper : public InputMapper { -public: - TouchInputMapper(InputDevice* device); - virtual ~TouchInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - - virtual int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); - virtual int32_t getScanCodeState(uint32_t sourceMask, int32_t scanCode); - virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, - const int32_t* keyCodes, uint8_t* outFlags); - - virtual void fadePointer(); - virtual void timeoutExpired(nsecs_t when); - -protected: - CursorButtonAccumulator mCursorButtonAccumulator; - CursorScrollAccumulator mCursorScrollAccumulator; - TouchButtonAccumulator mTouchButtonAccumulator; - - struct VirtualKey { - int32_t keyCode; - int32_t scanCode; - uint32_t flags; - - // computed hit box, specified in touch screen coords based on known display size - int32_t hitLeft; - int32_t hitTop; - int32_t hitRight; - int32_t hitBottom; - - inline bool isHit(int32_t x, int32_t y) const { - return x >= hitLeft && x <= hitRight && y >= hitTop && y <= hitBottom; - } - }; - - // Input sources and device mode. - uint32_t mSource; - - enum DeviceMode { - DEVICE_MODE_DISABLED, // input is disabled - DEVICE_MODE_DIRECT, // direct mapping (touchscreen) - DEVICE_MODE_UNSCALED, // unscaled mapping (touchpad) - DEVICE_MODE_NAVIGATION, // unscaled mapping with assist gesture (touch navigation) - DEVICE_MODE_POINTER, // pointer mapping (pointer) - }; - DeviceMode mDeviceMode; - - // The reader's configuration. - InputReaderConfiguration mConfig; - - // Immutable configuration parameters. - struct Parameters { - enum DeviceType { - DEVICE_TYPE_TOUCH_SCREEN, - DEVICE_TYPE_TOUCH_PAD, - DEVICE_TYPE_TOUCH_NAVIGATION, - DEVICE_TYPE_POINTER, - }; - - DeviceType deviceType; - bool hasAssociatedDisplay; - bool associatedDisplayIsExternal; - bool orientationAware; - - enum GestureMode { - GESTURE_MODE_POINTER, - GESTURE_MODE_SPOTS, - }; - GestureMode gestureMode; - } mParameters; - - // Immutable calibration parameters in parsed form. - struct Calibration { - // Size - enum SizeCalibration { - SIZE_CALIBRATION_DEFAULT, - SIZE_CALIBRATION_NONE, - SIZE_CALIBRATION_GEOMETRIC, - SIZE_CALIBRATION_DIAMETER, - SIZE_CALIBRATION_BOX, - SIZE_CALIBRATION_AREA, - }; - - SizeCalibration sizeCalibration; - - bool haveSizeScale; - float sizeScale; - bool haveSizeBias; - float sizeBias; - bool haveSizeIsSummed; - bool sizeIsSummed; - - // Pressure - enum PressureCalibration { - PRESSURE_CALIBRATION_DEFAULT, - PRESSURE_CALIBRATION_NONE, - PRESSURE_CALIBRATION_PHYSICAL, - PRESSURE_CALIBRATION_AMPLITUDE, - }; - - PressureCalibration pressureCalibration; - bool havePressureScale; - float pressureScale; - - // Orientation - enum OrientationCalibration { - ORIENTATION_CALIBRATION_DEFAULT, - ORIENTATION_CALIBRATION_NONE, - ORIENTATION_CALIBRATION_INTERPOLATED, - ORIENTATION_CALIBRATION_VECTOR, - }; - - OrientationCalibration orientationCalibration; - - // Distance - enum DistanceCalibration { - DISTANCE_CALIBRATION_DEFAULT, - DISTANCE_CALIBRATION_NONE, - DISTANCE_CALIBRATION_SCALED, - }; - - DistanceCalibration distanceCalibration; - bool haveDistanceScale; - float distanceScale; - - enum CoverageCalibration { - COVERAGE_CALIBRATION_DEFAULT, - COVERAGE_CALIBRATION_NONE, - COVERAGE_CALIBRATION_BOX, - }; - - CoverageCalibration coverageCalibration; - - inline void applySizeScaleAndBias(float* outSize) const { - if (haveSizeScale) { - *outSize *= sizeScale; - } - if (haveSizeBias) { - *outSize += sizeBias; - } - } - } mCalibration; - - // Raw pointer axis information from the driver. - RawPointerAxes mRawPointerAxes; - - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; - - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; - - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; - - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; - - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; - - // True if we sent a HOVER_ENTER event. - bool mSentHoverEnter; - - // The time the primary pointer last went down. - nsecs_t mDownTime; - - // The pointer controller, or null if the device is not a pointer. - sp mPointerController; - - Vector mVirtualKeys; - - virtual void configureParameters(); - virtual void dumpParameters(String8& dump); - virtual void configureRawPointerAxes(); - virtual void dumpRawPointerAxes(String8& dump); - virtual void configureSurface(nsecs_t when, bool* outResetNeeded); - virtual void dumpSurface(String8& dump); - virtual void configureVirtualKeys(); - virtual void dumpVirtualKeys(String8& dump); - virtual void parseCalibration(); - virtual void resolveCalibration(); - virtual void dumpCalibration(String8& dump); - virtual bool hasStylus() const = 0; - - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; - -private: - // The current viewport. - // The components of the viewport are specified in the display's rotated orientation. - DisplayViewport mViewport; - - // The surface orientation, width and height set by configureSurface(). - // The width and height are derived from the viewport but are specified - // in the natural orientation. - // The surface origin specifies how the surface coordinates should be translated - // to align with the logical display coordinate space. - // The orientation may be different from the viewport orientation as it specifies - // the rotation of the surface coordinates required to produce the viewport's - // requested orientation, so it will depend on whether the device is orientation aware. - int32_t mSurfaceWidth; - int32_t mSurfaceHeight; - int32_t mSurfaceLeft; - int32_t mSurfaceTop; - int32_t mSurfaceOrientation; - - // Translation and scaling factors, orientation-independent. - float mXTranslate; - float mXScale; - float mXPrecision; - - float mYTranslate; - float mYScale; - float mYPrecision; - - float mGeometricScale; - - float mPressureScale; - - float mSizeScale; - - float mOrientationScale; - - float mDistanceScale; - - bool mHaveTilt; - float mTiltXCenter; - float mTiltXScale; - float mTiltYCenter; - float mTiltYScale; - - // Oriented motion ranges for input device info. - struct OrientedRanges { - InputDeviceInfo::MotionRange x; - InputDeviceInfo::MotionRange y; - InputDeviceInfo::MotionRange pressure; - - bool haveSize; - InputDeviceInfo::MotionRange size; - - bool haveTouchSize; - InputDeviceInfo::MotionRange touchMajor; - InputDeviceInfo::MotionRange touchMinor; - - bool haveToolSize; - InputDeviceInfo::MotionRange toolMajor; - InputDeviceInfo::MotionRange toolMinor; - - bool haveOrientation; - InputDeviceInfo::MotionRange orientation; - - bool haveDistance; - InputDeviceInfo::MotionRange distance; - - bool haveTilt; - InputDeviceInfo::MotionRange tilt; - - OrientedRanges() { - clear(); - } - - void clear() { - haveSize = false; - haveTouchSize = false; - haveToolSize = false; - haveOrientation = false; - haveDistance = false; - haveTilt = false; - } - } mOrientedRanges; - - // Oriented dimensions and precision. - float mOrientedXPrecision; - float mOrientedYPrecision; - - struct CurrentVirtualKeyState { - bool down; - bool ignored; - nsecs_t downTime; - int32_t keyCode; - int32_t scanCode; - } mCurrentVirtualKey; - - // Scale factor for gesture or mouse based pointer movements. - float mPointerXMovementScale; - float mPointerYMovementScale; - - // Scale factor for gesture based zooming and other freeform motions. - float mPointerXZoomScale; - float mPointerYZoomScale; - - // The maximum swipe width. - float mPointerGestureMaxSwipeWidth; - - struct PointerDistanceHeapElement { - uint32_t currentPointerIndex : 8; - uint32_t lastPointerIndex : 8; - uint64_t distance : 48; // squared distance - }; - - enum PointerUsage { - POINTER_USAGE_NONE, - POINTER_USAGE_GESTURES, - POINTER_USAGE_STYLUS, - POINTER_USAGE_MOUSE, - }; - PointerUsage mPointerUsage; - - struct PointerGesture { - enum Mode { - // No fingers, button is not pressed. - // Nothing happening. - NEUTRAL, - - // No fingers, button is not pressed. - // Tap detected. - // Emits DOWN and UP events at the pointer location. - TAP, - - // Exactly one finger dragging following a tap. - // Pointer follows the active finger. - // Emits DOWN, MOVE and UP events at the pointer location. - // - // Detect double-taps when the finger goes up while in TAP_DRAG mode. - TAP_DRAG, - - // Button is pressed. - // Pointer follows the active finger if there is one. Other fingers are ignored. - // Emits DOWN, MOVE and UP events at the pointer location. - BUTTON_CLICK_OR_DRAG, - - // Exactly one finger, button is not pressed. - // Pointer follows the active finger. - // Emits HOVER_MOVE events at the pointer location. - // - // Detect taps when the finger goes up while in HOVER mode. - HOVER, - - // Exactly two fingers but neither have moved enough to clearly indicate - // whether a swipe or freeform gesture was intended. We consider the - // pointer to be pressed so this enables clicking or long-pressing on buttons. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single stationary pointer coordinate. - PRESS, - - // Exactly two fingers moving in the same direction, button is not pressed. - // Pointer does not move. - // Emits DOWN, MOVE and UP events with a single pointer coordinate that - // follows the midpoint between both fingers. - SWIPE, - - // Two or more fingers moving in arbitrary directions, button is not pressed. - // Pointer does not move. - // Emits DOWN, POINTER_DOWN, MOVE, POINTER_UP and UP events that follow - // each finger individually relative to the initial centroid of the finger. - FREEFORM, - - // Waiting for quiet time to end before starting the next gesture. - QUIET, - }; - - // Time the first finger went down. - nsecs_t firstTouchTime; - - // The active pointer id from the raw touch data. - int32_t activeTouchId; // -1 if none - - // The active pointer id from the gesture last delivered to the application. - int32_t activeGestureId; // -1 if none - - // Pointer coords and ids for the current and previous pointer gesture. - Mode currentGestureMode; - BitSet32 currentGestureIdBits; - uint32_t currentGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties currentGestureProperties[MAX_POINTERS]; - PointerCoords currentGestureCoords[MAX_POINTERS]; - - Mode lastGestureMode; - BitSet32 lastGestureIdBits; - uint32_t lastGestureIdToIndex[MAX_POINTER_ID + 1]; - PointerProperties lastGestureProperties[MAX_POINTERS]; - PointerCoords lastGestureCoords[MAX_POINTERS]; - - // Time the pointer gesture last went down. - nsecs_t downTime; - - // Time when the pointer went down for a TAP. - nsecs_t tapDownTime; - - // Time when the pointer went up for a TAP. - nsecs_t tapUpTime; - - // Location of initial tap. - float tapX, tapY; - - // Time we started waiting for quiescence. - nsecs_t quietTime; - - // Reference points for multitouch gestures. - float referenceTouchX; // reference touch X/Y coordinates in surface units - float referenceTouchY; - float referenceGestureX; // reference gesture X/Y coordinates in pixels - float referenceGestureY; - - // Distance that each pointer has traveled which has not yet been - // subsumed into the reference gesture position. - BitSet32 referenceIdBits; - struct Delta { - float dx, dy; - }; - Delta referenceDeltas[MAX_POINTER_ID + 1]; - - // Describes how touch ids are mapped to gesture ids for freeform gestures. - uint32_t freeformTouchToGestureIdMap[MAX_POINTER_ID + 1]; - - // A velocity tracker for determining whether to switch active pointers during drags. - VelocityTracker velocityTracker; - - void reset() { - firstTouchTime = LLONG_MIN; - activeTouchId = -1; - activeGestureId = -1; - currentGestureMode = NEUTRAL; - currentGestureIdBits.clear(); - lastGestureMode = NEUTRAL; - lastGestureIdBits.clear(); - downTime = 0; - velocityTracker.clear(); - resetTap(); - resetQuietTime(); - } - - void resetTap() { - tapDownTime = LLONG_MIN; - tapUpTime = LLONG_MIN; - } - - void resetQuietTime() { - quietTime = LLONG_MIN; - } - } mPointerGesture; - - struct PointerSimple { - PointerCoords currentCoords; - PointerProperties currentProperties; - PointerCoords lastCoords; - PointerProperties lastProperties; - - // True if the pointer is down. - bool down; - - // True if the pointer is hovering. - bool hovering; - - // Time the pointer last went down. - nsecs_t downTime; - - void reset() { - currentCoords.clear(); - currentProperties.clear(); - lastCoords.clear(); - lastProperties.clear(); - down = false; - hovering = false; - downTime = 0; - } - } mPointerSimple; - - // The pointer and scroll velocity controls. - VelocityControl mPointerVelocityControl; - VelocityControl mWheelXVelocityControl; - VelocityControl mWheelYVelocityControl; - - void sync(nsecs_t when); - - bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); - void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, - int32_t keyEventAction, int32_t keyEventFlags); - - void dispatchTouches(nsecs_t when, uint32_t policyFlags); - void dispatchHoverExit(nsecs_t when, uint32_t policyFlags); - void dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags); - void cookPointerData(); - - void dispatchPointerUsage(nsecs_t when, uint32_t policyFlags, PointerUsage pointerUsage); - void abortPointerUsage(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerGestures(nsecs_t when, uint32_t policyFlags, bool isTimeout); - void abortPointerGestures(nsecs_t when, uint32_t policyFlags); - bool preparePointerGestures(nsecs_t when, - bool* outCancelPreviousGesture, bool* outFinishPreviousGesture, - bool isTimeout); - - void dispatchPointerStylus(nsecs_t when, uint32_t policyFlags); - void abortPointerStylus(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerMouse(nsecs_t when, uint32_t policyFlags); - void abortPointerMouse(nsecs_t when, uint32_t policyFlags); - - void dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, - bool down, bool hovering); - void abortPointerSimple(nsecs_t when, uint32_t policyFlags); - - // Dispatches a motion event. - // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the - // method will take care of setting the index and transmuting the action to DOWN or UP - // it is the first / last pointer to go down / up. - void dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source, - int32_t action, int32_t flags, int32_t metaState, int32_t buttonState, - int32_t edgeFlags, - const PointerProperties* properties, const PointerCoords* coords, - const uint32_t* idToIndex, BitSet32 idBits, - int32_t changedId, float xPrecision, float yPrecision, nsecs_t downTime); - - // Updates pointer coords and properties for pointers with specified ids that have moved. - // Returns true if any of them changed. - bool updateMovedPointers(const PointerProperties* inProperties, - const PointerCoords* inCoords, const uint32_t* inIdToIndex, - PointerProperties* outProperties, PointerCoords* outCoords, - const uint32_t* outIdToIndex, BitSet32 idBits) const; - - bool isPointInsideSurface(int32_t x, int32_t y); - const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - - void assignPointerIds(); -}; - - -class SingleTouchInputMapper : public TouchInputMapper { -public: - SingleTouchInputMapper(InputDevice* device); - virtual ~SingleTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; -}; - - -class MultiTouchInputMapper : public TouchInputMapper { -public: - MultiTouchInputMapper(InputDevice* device); - virtual ~MultiTouchInputMapper(); - - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); - virtual void configureRawPointerAxes(); - virtual bool hasStylus() const; - -private: - MultiTouchMotionAccumulator mMultiTouchMotionAccumulator; - - // Specifies the pointer id bits that are in use, and their associated tracking id. - BitSet32 mPointerIdBits; - int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; -}; - - -class JoystickInputMapper : public InputMapper { -public: - JoystickInputMapper(InputDevice* device); - virtual ~JoystickInputMapper(); - - virtual uint32_t getSources(); - virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); - virtual void dump(String8& dump); - virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); - virtual void reset(nsecs_t when); - virtual void process(const RawEvent* rawEvent); - -private: - struct Axis { - RawAbsoluteAxisInfo rawAxisInfo; - AxisInfo axisInfo; - - bool explicitlyMapped; // true if the axis was explicitly assigned an axis id - - float scale; // scale factor from raw to normalized values - float offset; // offset to add after scaling for normalization - float highScale; // scale factor from raw to normalized values of high split - float highOffset; // offset to add after scaling for normalization of high split - - float min; // normalized inclusive minimum - float max; // normalized inclusive maximum - float flat; // normalized flat region size - float fuzz; // normalized error tolerance - float resolution; // normalized resolution in units/mm - - float filter; // filter out small variations of this size - float currentValue; // current value - float newValue; // most recent value - float highCurrentValue; // current value of high split - float highNewValue; // most recent value of high split - - void initialize(const RawAbsoluteAxisInfo& rawAxisInfo, const AxisInfo& axisInfo, - bool explicitlyMapped, float scale, float offset, - float highScale, float highOffset, - float min, float max, float flat, float fuzz, float resolution) { - this->rawAxisInfo = rawAxisInfo; - this->axisInfo = axisInfo; - this->explicitlyMapped = explicitlyMapped; - this->scale = scale; - this->offset = offset; - this->highScale = highScale; - this->highOffset = highOffset; - this->min = min; - this->max = max; - this->flat = flat; - this->fuzz = fuzz; - this->resolution = resolution; - this->filter = 0; - resetValue(); - } - - void resetValue() { - this->currentValue = 0; - this->newValue = 0; - this->highCurrentValue = 0; - this->highNewValue = 0; - } - }; - - // Axes indexed by raw ABS_* axis index. - KeyedVector mAxes; - - void sync(nsecs_t when, bool force); - - bool haveAxis(int32_t axisId); - void pruneAxes(bool ignoreExplicitlyMappedAxes); - bool filterAxes(bool force); - - static bool hasValueChangedSignificantly(float filter, - float newValue, float currentValue, float min, float max); - static bool hasMovedNearerToValueWithinFilteredRange(float filter, - float newValue, float currentValue, float thresholdValue); - - static bool isCenteredAxis(int32_t axis); - static int32_t getCompatAxis(int32_t axis); - - static void addMotionRange(int32_t axisId, const Axis& axis, InputDeviceInfo* info); - static void setPointerCoordsAxisValue(PointerCoords* pointerCoords, int32_t axis, - float value); -}; - -} // namespace android - -#endif // _UI_INPUT_READER_H diff --git a/widget/gonk/libui/InputTransport.cpp b/widget/gonk/libui/InputTransport.cpp deleted file mode 100644 index 3f0fcb047..000000000 --- a/widget/gonk/libui/InputTransport.cpp +++ /dev/null @@ -1,957 +0,0 @@ -// -// Copyright 2010 The Android Open Source Project -// -// Provides a shared memory transport for input events. -// -#define LOG_TAG "InputTransport" - -//#define LOG_NDEBUG 0 - -// Log debug messages about channel messages (send message, receive message) -#define DEBUG_CHANNEL_MESSAGES 0 - -// Log debug messages whenever InputChannel objects are created/destroyed -#define DEBUG_CHANNEL_LIFECYCLE 0 - -// Log debug messages about transport actions -#define DEBUG_TRANSPORT_ACTIONS 0 - -// Log debug messages about touch event resampling -#define DEBUG_RESAMPLING 0 - - -#include "cutils_log.h" -#include -#include -#include -#include "InputTransport.h" -#include -#include -#include -#include - - -namespace android { - -// Socket buffer size. The default is typically about 128KB, which is much larger than -// we really need. So we make it smaller. It just needs to be big enough to hold -// a few dozen large multi-finger motion events in the case where an application gets -// behind processing touches. -static const size_t SOCKET_BUFFER_SIZE = 32 * 1024; - -// Nanoseconds per milliseconds. -static const nsecs_t NANOS_PER_MS = 1000000; - -// Latency added during resampling. A few milliseconds doesn't hurt much but -// reduces the impact of mispredicted touch positions. -static const nsecs_t RESAMPLE_LATENCY = 5 * NANOS_PER_MS; - -// Minimum time difference between consecutive samples before attempting to resample. -static const nsecs_t RESAMPLE_MIN_DELTA = 2 * NANOS_PER_MS; - -// Maximum time to predict forward from the last known state, to avoid predicting too -// far into the future. This time is further bounded by 50% of the last time delta. -static const nsecs_t RESAMPLE_MAX_PREDICTION = 8 * NANOS_PER_MS; - -template -inline static T min(const T& a, const T& b) { - return a < b ? a : b; -} - -inline static float lerp(float a, float b, float alpha) { - return a + alpha * (b - a); -} - -// --- InputMessage --- - -bool InputMessage::isValid(size_t actualSize) const { - if (size() == actualSize) { - switch (header.type) { - case TYPE_KEY: - return true; - case TYPE_MOTION: - return body.motion.pointerCount > 0 - && body.motion.pointerCount <= MAX_POINTERS; - case TYPE_FINISHED: - return true; - } - } - return false; -} - -size_t InputMessage::size() const { - switch (header.type) { - case TYPE_KEY: - return sizeof(Header) + body.key.size(); - case TYPE_MOTION: - return sizeof(Header) + body.motion.size(); - case TYPE_FINISHED: - return sizeof(Header) + body.finished.size(); - } - return sizeof(Header); -} - - -// --- InputChannel --- - -InputChannel::InputChannel(const String8& name, int fd) : - mName(name), mFd(fd) { -#if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel constructed: name='%s', fd=%d", - mName.string(), fd); -#endif - - int result = fcntl(mFd, F_SETFL, O_NONBLOCK); - LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket " - "non-blocking. errno=%d", mName.string(), errno); -} - -InputChannel::~InputChannel() { -#if DEBUG_CHANNEL_LIFECYCLE - ALOGD("Input channel destroyed: name='%s', fd=%d", - mName.string(), mFd); -#endif - - ::close(mFd); -} - -status_t InputChannel::openInputChannelPair(const String8& name, - sp& outServerChannel, sp& outClientChannel) { - int sockets[2]; - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) { - status_t result = -errno; - ALOGE("channel '%s' ~ Could not create socket pair. errno=%d", - name.string(), errno); - outServerChannel.clear(); - outClientChannel.clear(); - return result; - } - - int bufferSize = SOCKET_BUFFER_SIZE; - setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); - setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)); - setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)); - - String8 serverChannelName = name; - serverChannelName.append(" (server)"); - outServerChannel = new InputChannel(serverChannelName, sockets[0]); - - String8 clientChannelName = name; - clientChannelName.append(" (client)"); - outClientChannel = new InputChannel(clientChannelName, sockets[1]); - return OK; -} - -status_t InputChannel::sendMessage(const InputMessage* msg) { - size_t msgLength = msg->size(); - ssize_t nWrite; - do { - nWrite = ::send(mFd, msg, msgLength, MSG_DONTWAIT | MSG_NOSIGNAL); - } while (nWrite == -1 && errno == EINTR); - - if (nWrite < 0) { - int error = errno; -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(), - msg->header.type, error); -#endif - if (error == EAGAIN || error == EWOULDBLOCK) { - return WOULD_BLOCK; - } - if (error == EPIPE || error == ENOTCONN) { - return DEAD_OBJECT; - } - return -error; - } - - if (size_t(nWrite) != msgLength) { -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ error sending message type %d, send was incomplete", - mName.string(), msg->header.type); -#endif - return DEAD_OBJECT; - } - -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type); -#endif - return OK; -} - -status_t InputChannel::receiveMessage(InputMessage* msg) { - ssize_t nRead; - do { - nRead = ::recv(mFd, msg, sizeof(InputMessage), MSG_DONTWAIT); - } while (nRead == -1 && errno == EINTR); - - if (nRead < 0) { - int error = errno; -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno); -#endif - if (error == EAGAIN || error == EWOULDBLOCK) { - return WOULD_BLOCK; - } - if (error == EPIPE || error == ENOTCONN) { - return DEAD_OBJECT; - } - return -error; - } - - if (nRead == 0) { // check for EOF -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string()); -#endif - return DEAD_OBJECT; - } - - if (!msg->isValid(nRead)) { -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received invalid message", mName.string()); -#endif - return BAD_VALUE; - } - -#if DEBUG_CHANNEL_MESSAGES - ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type); -#endif - return OK; -} - -sp InputChannel::dup() const { - int fd = ::dup(getFd()); - return fd >= 0 ? new InputChannel(getName(), fd) : NULL; -} - - -// --- InputPublisher --- - -InputPublisher::InputPublisher(const sp& channel) : - mChannel(channel) { -} - -InputPublisher::~InputPublisher() { -} - -status_t InputPublisher::publishKeyEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d," - "downTime=%lld, eventTime=%lld", - mChannel->getName().string(), seq, - deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount, - downTime, eventTime); -#endif - - if (!seq) { - ALOGE("Attempted to publish a key event with sequence number 0."); - return BAD_VALUE; - } - - InputMessage msg; - msg.header.type = InputMessage::TYPE_KEY; - msg.body.key.seq = seq; - msg.body.key.deviceId = deviceId; - msg.body.key.source = source; - msg.body.key.action = action; - msg.body.key.flags = flags; - msg.body.key.keyCode = keyCode; - msg.body.key.scanCode = scanCode; - msg.body.key.metaState = metaState; - msg.body.key.repeatCount = repeatCount; - msg.body.key.downTime = downTime; - msg.body.key.eventTime = eventTime; - return mChannel->sendMessage(&msg); -} - -status_t InputPublisher::publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, " - "action=0x%x, flags=0x%x, edgeFlags=0x%x, metaState=0x%x, buttonState=0x%x, " - "xOffset=%f, yOffset=%f, " - "xPrecision=%f, yPrecision=%f, downTime=%lld, eventTime=%lld, " - "pointerCount=%d", - mChannel->getName().string(), seq, - deviceId, source, action, flags, edgeFlags, metaState, buttonState, - xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount); -#endif - - if (!seq) { - ALOGE("Attempted to publish a motion event with sequence number 0."); - return BAD_VALUE; - } - - if (pointerCount > MAX_POINTERS || pointerCount < 1) { - ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %d.", - mChannel->getName().string(), pointerCount); - return BAD_VALUE; - } - - InputMessage msg; - msg.header.type = InputMessage::TYPE_MOTION; - msg.body.motion.seq = seq; - msg.body.motion.deviceId = deviceId; - msg.body.motion.source = source; - msg.body.motion.action = action; - msg.body.motion.flags = flags; - msg.body.motion.edgeFlags = edgeFlags; - msg.body.motion.metaState = metaState; - msg.body.motion.buttonState = buttonState; - msg.body.motion.xOffset = xOffset; - msg.body.motion.yOffset = yOffset; - msg.body.motion.xPrecision = xPrecision; - msg.body.motion.yPrecision = yPrecision; - msg.body.motion.downTime = downTime; - msg.body.motion.eventTime = eventTime; - msg.body.motion.pointerCount = pointerCount; - for (size_t i = 0; i < pointerCount; i++) { - msg.body.motion.pointers[i].properties.copyFrom(pointerProperties[i]); - msg.body.motion.pointers[i].coords.copyFrom(pointerCoords[i]); - } - return mChannel->sendMessage(&msg); -} - -status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' publisher ~ receiveFinishedSignal", - mChannel->getName().string()); -#endif - - InputMessage msg; - status_t result = mChannel->receiveMessage(&msg); - if (result) { - *outSeq = 0; - *outHandled = false; - return result; - } - if (msg.header.type != InputMessage::TYPE_FINISHED) { - ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer", - mChannel->getName().string(), msg.header.type); - return UNKNOWN_ERROR; - } - *outSeq = msg.body.finished.seq; - *outHandled = msg.body.finished.handled; - return OK; -} - -// --- InputConsumer --- - -InputConsumer::InputConsumer(const sp& channel) : - mResampleTouch(isTouchResamplingEnabled()), - mChannel(channel), mMsgDeferred(false) { -} - -InputConsumer::~InputConsumer() { -} - -bool InputConsumer::isTouchResamplingEnabled() { - char value[PROPERTY_VALUE_MAX]; - int length = property_get("debug.inputconsumer.resample", value, NULL); - if (length > 0) { - if (!strcmp("0", value)) { - return false; - } - if (strcmp("1", value)) { - ALOGD("Unrecognized property value for 'debug.inputconsumer.resample'. " - "Use '1' or '0'."); - } - } - return true; -} - -status_t InputConsumer::consume(InputEventFactoryInterface* factory, - bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%lld", - mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime); -#endif - - *outSeq = 0; - *outEvent = NULL; - - // Fetch the next input message. - // Loop until an event can be returned or no additional events are received. - while (!*outEvent) { - if (mMsgDeferred) { - // mMsg contains a valid input message from the previous call to consume - // that has not yet been processed. - mMsgDeferred = false; - } else { - // Receive a fresh message. - status_t result = mChannel->receiveMessage(&mMsg); - if (result) { - // Consume the next batched event unless batches are being held for later. - if (consumeBatches || result != WOULD_BLOCK) { - result = consumeBatch(factory, frameTime, outSeq, outEvent); - if (*outEvent) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - } - return result; - } - } - - switch (mMsg.header.type) { - case InputMessage::TYPE_KEY: { - KeyEvent* keyEvent = factory->createKeyEvent(); - if (!keyEvent) return NO_MEMORY; - - initializeKeyEvent(keyEvent, &mMsg); - *outSeq = mMsg.body.key.seq; - *outEvent = keyEvent; -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed key event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - - case AINPUT_EVENT_TYPE_MOTION: { - ssize_t batchIndex = findBatch(mMsg.body.motion.deviceId, mMsg.body.motion.source); - if (batchIndex >= 0) { - Batch& batch = mBatches.editItemAt(batchIndex); - if (canAddSample(batch, &mMsg)) { - batch.samples.push(mMsg); -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ appended to batch event", - mChannel->getName().string()); -#endif - break; - } else { - // We cannot append to the batch in progress, so we need to consume - // the previous batch right now and defer the new message until later. - mMsgDeferred = true; - status_t result = consumeSamples(factory, - batch, batch.samples.size(), outSeq, outEvent); - mBatches.removeAt(batchIndex); - if (result) { - return result; - } -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed batch event and " - "deferred current event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - } - - // Start a new batch if needed. - if (mMsg.body.motion.action == AMOTION_EVENT_ACTION_MOVE - || mMsg.body.motion.action == AMOTION_EVENT_ACTION_HOVER_MOVE) { - mBatches.push(); - Batch& batch = mBatches.editTop(); - batch.samples.push(mMsg); -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ started batch event", - mChannel->getName().string()); -#endif - break; - } - - MotionEvent* motionEvent = factory->createMotionEvent(); - if (! motionEvent) return NO_MEMORY; - - updateTouchState(&mMsg); - initializeMotionEvent(motionEvent, &mMsg); - *outSeq = mMsg.body.motion.seq; - *outEvent = motionEvent; -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u", - mChannel->getName().string(), *outSeq); -#endif - break; - } - - default: - ALOGE("channel '%s' consumer ~ Received unexpected message of type %d", - mChannel->getName().string(), mMsg.header.type); - return UNKNOWN_ERROR; - } - } - return OK; -} - -status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory, - nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) { - status_t result; - for (size_t i = mBatches.size(); i-- > 0; ) { - Batch& batch = mBatches.editItemAt(i); - if (frameTime < 0) { - result = consumeSamples(factory, batch, batch.samples.size(), - outSeq, outEvent); - mBatches.removeAt(i); - return result; - } - - nsecs_t sampleTime = frameTime - RESAMPLE_LATENCY; - ssize_t split = findSampleNoLaterThan(batch, sampleTime); - if (split < 0) { - continue; - } - - result = consumeSamples(factory, batch, split + 1, outSeq, outEvent); - const InputMessage* next; - if (batch.samples.isEmpty()) { - mBatches.removeAt(i); - next = NULL; - } else { - next = &batch.samples.itemAt(0); - } - if (!result) { - resampleTouchState(sampleTime, static_cast(*outEvent), next); - } - return result; - } - - return WOULD_BLOCK; -} - -status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory, - Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) { - MotionEvent* motionEvent = factory->createMotionEvent(); - if (! motionEvent) return NO_MEMORY; - - uint32_t chain = 0; - for (size_t i = 0; i < count; i++) { - InputMessage& msg = batch.samples.editItemAt(i); - updateTouchState(&msg); - if (i) { - SeqChain seqChain; - seqChain.seq = msg.body.motion.seq; - seqChain.chain = chain; - mSeqChains.push(seqChain); - addSample(motionEvent, &msg); - } else { - initializeMotionEvent(motionEvent, &msg); - } - chain = msg.body.motion.seq; - } - batch.samples.removeItemsAt(0, count); - - *outSeq = chain; - *outEvent = motionEvent; - return OK; -} - -void InputConsumer::updateTouchState(InputMessage* msg) { - if (!mResampleTouch || - !(msg->body.motion.source & AINPUT_SOURCE_CLASS_POINTER)) { - return; - } - - int32_t deviceId = msg->body.motion.deviceId; - int32_t source = msg->body.motion.source; - nsecs_t eventTime = msg->body.motion.eventTime; - - // Update the touch state history to incorporate the new input message. - // If the message is in the past relative to the most recently produced resampled - // touch, then use the resampled time and coordinates instead. - switch (msg->body.motion.action & AMOTION_EVENT_ACTION_MASK) { - case AMOTION_EVENT_ACTION_DOWN: { - ssize_t index = findTouchState(deviceId, source); - if (index < 0) { - mTouchStates.push(); - index = mTouchStates.size() - 1; - } - TouchState& touchState = mTouchStates.editItemAt(index); - touchState.initialize(deviceId, source); - touchState.addHistory(msg); - break; - } - - case AMOTION_EVENT_ACTION_MOVE: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - TouchState& touchState = mTouchStates.editItemAt(index); - touchState.addHistory(msg); - if (eventTime < touchState.lastResample.eventTime) { - rewriteMessage(touchState, msg); - } else { - touchState.lastResample.idBits.clear(); - } - } - break; - } - - case AMOTION_EVENT_ACTION_POINTER_DOWN: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - TouchState& touchState = mTouchStates.editItemAt(index); - touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId()); - rewriteMessage(touchState, msg); - } - break; - } - - case AMOTION_EVENT_ACTION_POINTER_UP: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - TouchState& touchState = mTouchStates.editItemAt(index); - rewriteMessage(touchState, msg); - touchState.lastResample.idBits.clearBit(msg->body.motion.getActionId()); - } - break; - } - - case AMOTION_EVENT_ACTION_SCROLL: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - const TouchState& touchState = mTouchStates.itemAt(index); - rewriteMessage(touchState, msg); - } - break; - } - - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_CANCEL: { - ssize_t index = findTouchState(deviceId, source); - if (index >= 0) { - const TouchState& touchState = mTouchStates.itemAt(index); - rewriteMessage(touchState, msg); - mTouchStates.removeAt(index); - } - break; - } - } -} - -void InputConsumer::rewriteMessage(const TouchState& state, InputMessage* msg) { - for (size_t i = 0; i < msg->body.motion.pointerCount; i++) { - uint32_t id = msg->body.motion.pointers[i].properties.id; - if (state.lastResample.idBits.hasBit(id)) { - PointerCoords& msgCoords = msg->body.motion.pointers[i].coords; - const PointerCoords& resampleCoords = state.lastResample.getPointerById(id); -#if DEBUG_RESAMPLING - ALOGD("[%d] - rewrite (%0.3f, %0.3f), old (%0.3f, %0.3f)", id, - resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_X), - resampleCoords.getAxisValue(AMOTION_EVENT_AXIS_Y), - msgCoords.getAxisValue(AMOTION_EVENT_AXIS_X), - msgCoords.getAxisValue(AMOTION_EVENT_AXIS_Y)); -#endif - msgCoords.setAxisValue(AMOTION_EVENT_AXIS_X, resampleCoords.getX()); - msgCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, resampleCoords.getY()); - } - } -} - -void InputConsumer::resampleTouchState(nsecs_t sampleTime, MotionEvent* event, - const InputMessage* next) { - if (!mResampleTouch - || !(event->getSource() & AINPUT_SOURCE_CLASS_POINTER) - || event->getAction() != AMOTION_EVENT_ACTION_MOVE) { - return; - } - - ssize_t index = findTouchState(event->getDeviceId(), event->getSource()); - if (index < 0) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, no touch state for device."); -#endif - return; - } - - TouchState& touchState = mTouchStates.editItemAt(index); - if (touchState.historySize < 1) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, no history for device."); -#endif - return; - } - - // Ensure that the current sample has all of the pointers that need to be reported. - const History* current = touchState.getHistory(0); - size_t pointerCount = event->getPointerCount(); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t id = event->getPointerId(i); - if (!current->idBits.hasBit(id)) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, missing id %d", id); -#endif - return; - } - } - - // Find the data to use for resampling. - const History* other; - History future; - float alpha; - if (next) { - // Interpolate between current sample and future sample. - // So current->eventTime <= sampleTime <= future.eventTime. - future.initializeFrom(next); - other = &future; - nsecs_t delta = future.eventTime - current->eventTime; - if (delta < RESAMPLE_MIN_DELTA) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, delta time is %lld ns.", delta); -#endif - return; - } - alpha = float(sampleTime - current->eventTime) / delta; - } else if (touchState.historySize >= 2) { - // Extrapolate future sample using current sample and past sample. - // So other->eventTime <= current->eventTime <= sampleTime. - other = touchState.getHistory(1); - nsecs_t delta = current->eventTime - other->eventTime; - if (delta < RESAMPLE_MIN_DELTA) { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, delta time is %lld ns.", delta); -#endif - return; - } - nsecs_t maxPredict = current->eventTime + min(delta / 2, RESAMPLE_MAX_PREDICTION); - if (sampleTime > maxPredict) { -#if DEBUG_RESAMPLING - ALOGD("Sample time is too far in the future, adjusting prediction " - "from %lld to %lld ns.", - sampleTime - current->eventTime, maxPredict - current->eventTime); -#endif - sampleTime = maxPredict; - } - alpha = float(current->eventTime - sampleTime) / delta; - } else { -#if DEBUG_RESAMPLING - ALOGD("Not resampled, insufficient data."); -#endif - return; - } - - // Resample touch coordinates. - touchState.lastResample.eventTime = sampleTime; - touchState.lastResample.idBits.clear(); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t id = event->getPointerId(i); - touchState.lastResample.idToIndex[id] = i; - touchState.lastResample.idBits.markBit(id); - PointerCoords& resampledCoords = touchState.lastResample.pointers[i]; - const PointerCoords& currentCoords = current->getPointerById(id); - if (other->idBits.hasBit(id) - && shouldResampleTool(event->getToolType(i))) { - const PointerCoords& otherCoords = other->getPointerById(id); - resampledCoords.copyFrom(currentCoords); - resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_X, - lerp(currentCoords.getX(), otherCoords.getX(), alpha)); - resampledCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, - lerp(currentCoords.getY(), otherCoords.getY(), alpha)); -#if DEBUG_RESAMPLING - ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f), " - "other (%0.3f, %0.3f), alpha %0.3f", - id, resampledCoords.getX(), resampledCoords.getY(), - currentCoords.getX(), currentCoords.getY(), - otherCoords.getX(), otherCoords.getY(), - alpha); -#endif - } else { - resampledCoords.copyFrom(currentCoords); -#if DEBUG_RESAMPLING - ALOGD("[%d] - out (%0.3f, %0.3f), cur (%0.3f, %0.3f)", - id, resampledCoords.getX(), resampledCoords.getY(), - currentCoords.getX(), currentCoords.getY()); -#endif - } - } - - event->addSample(sampleTime, touchState.lastResample.pointers); -} - -bool InputConsumer::shouldResampleTool(int32_t toolType) { - return toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN; -} - -status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) { -#if DEBUG_TRANSPORT_ACTIONS - ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s", - mChannel->getName().string(), seq, handled ? "true" : "false"); -#endif - - if (!seq) { - ALOGE("Attempted to send a finished signal with sequence number 0."); - return BAD_VALUE; - } - - // Send finished signals for the batch sequence chain first. - size_t seqChainCount = mSeqChains.size(); - if (seqChainCount) { - uint32_t currentSeq = seq; - uint32_t chainSeqs[seqChainCount]; - size_t chainIndex = 0; - for (size_t i = seqChainCount; i-- > 0; ) { - const SeqChain& seqChain = mSeqChains.itemAt(i); - if (seqChain.seq == currentSeq) { - currentSeq = seqChain.chain; - chainSeqs[chainIndex++] = currentSeq; - mSeqChains.removeAt(i); - } - } - status_t status = OK; - while (!status && chainIndex-- > 0) { - status = sendUnchainedFinishedSignal(chainSeqs[chainIndex], handled); - } - if (status) { - // An error occurred so at least one signal was not sent, reconstruct the chain. - do { - SeqChain seqChain; - seqChain.seq = chainIndex != 0 ? chainSeqs[chainIndex - 1] : seq; - seqChain.chain = chainSeqs[chainIndex]; - mSeqChains.push(seqChain); - } while (chainIndex-- > 0); - return status; - } - } - - // Send finished signal for the last message in the batch. - return sendUnchainedFinishedSignal(seq, handled); -} - -status_t InputConsumer::sendUnchainedFinishedSignal(uint32_t seq, bool handled) { - InputMessage msg; - msg.header.type = InputMessage::TYPE_FINISHED; - msg.body.finished.seq = seq; - msg.body.finished.handled = handled; - return mChannel->sendMessage(&msg); -} - -bool InputConsumer::hasDeferredEvent() const { - return mMsgDeferred; -} - -bool InputConsumer::hasPendingBatch() const { - return !mBatches.isEmpty(); -} - -ssize_t InputConsumer::findBatch(int32_t deviceId, int32_t source) const { - for (size_t i = 0; i < mBatches.size(); i++) { - const Batch& batch = mBatches.itemAt(i); - const InputMessage& head = batch.samples.itemAt(0); - if (head.body.motion.deviceId == deviceId && head.body.motion.source == source) { - return i; - } - } - return -1; -} - -ssize_t InputConsumer::findTouchState(int32_t deviceId, int32_t source) const { - for (size_t i = 0; i < mTouchStates.size(); i++) { - const TouchState& touchState = mTouchStates.itemAt(i); - if (touchState.deviceId == deviceId && touchState.source == source) { - return i; - } - } - return -1; -} - -void InputConsumer::initializeKeyEvent(KeyEvent* event, const InputMessage* msg) { - event->initialize( - msg->body.key.deviceId, - msg->body.key.source, - msg->body.key.action, - msg->body.key.flags, - msg->body.key.keyCode, - msg->body.key.scanCode, - msg->body.key.metaState, - msg->body.key.repeatCount, - msg->body.key.downTime, - msg->body.key.eventTime); -} - -void InputConsumer::initializeMotionEvent(MotionEvent* event, const InputMessage* msg) { - size_t pointerCount = msg->body.motion.pointerCount; - PointerProperties pointerProperties[pointerCount]; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerProperties[i].copyFrom(msg->body.motion.pointers[i].properties); - pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); - } - - event->initialize( - msg->body.motion.deviceId, - msg->body.motion.source, - msg->body.motion.action, - msg->body.motion.flags, - msg->body.motion.edgeFlags, - msg->body.motion.metaState, - msg->body.motion.buttonState, - msg->body.motion.xOffset, - msg->body.motion.yOffset, - msg->body.motion.xPrecision, - msg->body.motion.yPrecision, - msg->body.motion.downTime, - msg->body.motion.eventTime, - pointerCount, - pointerProperties, - pointerCoords); -} - -void InputConsumer::addSample(MotionEvent* event, const InputMessage* msg) { - size_t pointerCount = msg->body.motion.pointerCount; - PointerCoords pointerCoords[pointerCount]; - for (size_t i = 0; i < pointerCount; i++) { - pointerCoords[i].copyFrom(msg->body.motion.pointers[i].coords); - } - - event->setMetaState(event->getMetaState() | msg->body.motion.metaState); - event->addSample(msg->body.motion.eventTime, pointerCoords); -} - -bool InputConsumer::canAddSample(const Batch& batch, const InputMessage *msg) { - const InputMessage& head = batch.samples.itemAt(0); - size_t pointerCount = msg->body.motion.pointerCount; - if (head.body.motion.pointerCount != pointerCount - || head.body.motion.action != msg->body.motion.action) { - return false; - } - for (size_t i = 0; i < pointerCount; i++) { - if (head.body.motion.pointers[i].properties - != msg->body.motion.pointers[i].properties) { - return false; - } - } - return true; -} - -ssize_t InputConsumer::findSampleNoLaterThan(const Batch& batch, nsecs_t time) { - size_t numSamples = batch.samples.size(); - size_t index = 0; - while (index < numSamples - && batch.samples.itemAt(index).body.motion.eventTime <= time) { - index += 1; - } - return ssize_t(index) - 1; -} - -} // namespace android diff --git a/widget/gonk/libui/InputTransport.h b/widget/gonk/libui/InputTransport.h deleted file mode 100644 index 66ef2850a..000000000 --- a/widget/gonk/libui/InputTransport.h +++ /dev/null @@ -1,443 +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. - */ - -#ifndef _ANDROIDFW_INPUT_TRANSPORT_H -#define _ANDROIDFW_INPUT_TRANSPORT_H - -/** - * Native input transport. - * - * The InputChannel provides a mechanism for exchanging InputMessage structures across processes. - * - * The InputPublisher and InputConsumer each handle one end-point of an input channel. - * The InputPublisher is used by the input dispatcher to send events to the application. - * The InputConsumer is used by the application to receive events from the input dispatcher. - */ - -#include "Input.h" -#include -#include -#include -#include -#include -#include - -namespace android { - -/* - * Intermediate representation used to send input events and related signals. - */ -struct InputMessage { - enum { - TYPE_KEY = 1, - TYPE_MOTION = 2, - TYPE_FINISHED = 3, - }; - - struct Header { - uint32_t type; - uint32_t padding; // 8 byte alignment for the body that follows - } header; - - union Body { - struct Key { - uint32_t seq; - nsecs_t eventTime; - int32_t deviceId; - int32_t source; - int32_t action; - int32_t flags; - int32_t keyCode; - int32_t scanCode; - int32_t metaState; - int32_t repeatCount; - nsecs_t downTime; - - inline size_t size() const { - return sizeof(Key); - } - } key; - - struct Motion { - uint32_t seq; - nsecs_t eventTime; - int32_t deviceId; - int32_t source; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t buttonState; - int32_t edgeFlags; - nsecs_t downTime; - float xOffset; - float yOffset; - float xPrecision; - float yPrecision; - size_t pointerCount; - struct Pointer { - PointerProperties properties; - PointerCoords coords; - } pointers[MAX_POINTERS]; - - int32_t getActionId() const { - uint32_t index = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) - >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - return pointers[index].properties.id; - } - - inline size_t size() const { - return sizeof(Motion) - sizeof(Pointer) * MAX_POINTERS - + sizeof(Pointer) * pointerCount; - } - } motion; - - struct Finished { - uint32_t seq; - bool handled; - - inline size_t size() const { - return sizeof(Finished); - } - } finished; - } body; - - bool isValid(size_t actualSize) const; - size_t size() const; -}; - -/* - * An input channel consists of a local unix domain socket used to send and receive - * input messages across processes. Each channel has a descriptive name for debugging purposes. - * - * Each endpoint has its own InputChannel object that specifies its file descriptor. - * - * The input channel is closed when all references to it are released. - */ -class InputChannel : public RefBase { -protected: - virtual ~InputChannel(); - -public: - InputChannel(const String8& name, int fd); - - /* Creates a pair of input channels. - * - * Returns OK on success. - */ - static status_t openInputChannelPair(const String8& name, - sp& outServerChannel, sp& outClientChannel); - - inline String8 getName() const { return mName; } - inline int getFd() const { return mFd; } - - /* Sends a message to the other endpoint. - * - * If the channel is full then the message is guaranteed not to have been sent at all. - * Try again after the consumer has sent a finished signal indicating that it has - * consumed some of the pending messages from the channel. - * - * Returns OK on success. - * Returns WOULD_BLOCK if the channel is full. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t sendMessage(const InputMessage* msg); - - /* Receives a message sent by the other endpoint. - * - * If there is no message present, try again after poll() indicates that the fd - * is readable. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no message present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t receiveMessage(InputMessage* msg); - - /* Returns a new object that has a duplicate of this channel's fd. */ - sp dup() const; - -private: - String8 mName; - int mFd; -}; - -/* - * Publishes input events to an input channel. - */ -class InputPublisher { -public: - /* Creates a publisher associated with an input channel. */ - explicit InputPublisher(const sp& channel); - - /* Destroys the publisher and releases its input channel. */ - ~InputPublisher(); - - /* Gets the underlying input channel. */ - inline sp getChannel() { return mChannel; } - - /* Publishes a key event to the input channel. - * - * Returns OK on success. - * Returns WOULD_BLOCK if the channel is full. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns BAD_VALUE if seq is 0. - * Other errors probably indicate that the channel is broken. - */ - status_t publishKeyEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t keyCode, - int32_t scanCode, - int32_t metaState, - int32_t repeatCount, - nsecs_t downTime, - nsecs_t eventTime); - - /* Publishes a motion event to the input channel. - * - * Returns OK on success. - * Returns WOULD_BLOCK if the channel is full. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns BAD_VALUE if seq is 0 or if pointerCount is less than 1 or greater than MAX_POINTERS. - * Other errors probably indicate that the channel is broken. - */ - status_t publishMotionEvent( - uint32_t seq, - int32_t deviceId, - int32_t source, - int32_t action, - int32_t flags, - int32_t edgeFlags, - int32_t metaState, - int32_t buttonState, - float xOffset, - float yOffset, - float xPrecision, - float yPrecision, - nsecs_t downTime, - nsecs_t eventTime, - size_t pointerCount, - const PointerProperties* pointerProperties, - const PointerCoords* pointerCoords); - - /* Receives the finished signal from the consumer in reply to the original dispatch signal. - * If a signal was received, returns the message sequence number, - * and whether the consumer handled the message. - * - * The returned sequence number is never 0 unless the operation failed. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no signal present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Other errors probably indicate that the channel is broken. - */ - status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled); - -private: - sp mChannel; -}; - -/* - * Consumes input events from an input channel. - */ -class InputConsumer { -public: - /* Creates a consumer associated with an input channel. */ - explicit InputConsumer(const sp& channel); - - /* Destroys the consumer and releases its input channel. */ - ~InputConsumer(); - - /* Gets the underlying input channel. */ - inline sp getChannel() { return mChannel; } - - /* Consumes an input event from the input channel and copies its contents into - * an InputEvent object created using the specified factory. - * - * Tries to combine a series of move events into larger batches whenever possible. - * - * If consumeBatches is false, then defers consuming pending batched events if it - * is possible for additional samples to be added to them later. Call hasPendingBatch() - * to determine whether a pending batch is available to be consumed. - * - * If consumeBatches is true, then events are still batched but they are consumed - * immediately as soon as the input channel is exhausted. - * - * The frameTime parameter specifies the time when the current display frame started - * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown. - * - * The returned sequence number is never 0 unless the operation failed. - * - * Returns OK on success. - * Returns WOULD_BLOCK if there is no event present. - * Returns DEAD_OBJECT if the channel's peer has been closed. - * Returns NO_MEMORY if the event could not be created. - * Other errors probably indicate that the channel is broken. - */ - status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, - nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); - - /* Sends a finished signal to the publisher to inform it that the message - * with the specified sequence number has finished being process and whether - * the message was handled by the consumer. - * - * Returns OK on success. - * Returns BAD_VALUE if seq is 0. - * Other errors probably indicate that the channel is broken. - */ - status_t sendFinishedSignal(uint32_t seq, bool handled); - - /* Returns true if there is a deferred event waiting. - * - * Should be called after calling consume() to determine whether the consumer - * has a deferred event to be processed. Deferred events are somewhat special in - * that they have already been removed from the input channel. If the input channel - * becomes empty, the client may need to do extra work to ensure that it processes - * the deferred event despite the fact that the input channel's file descriptor - * is not readable. - * - * One option is simply to call consume() in a loop until it returns WOULD_BLOCK. - * This guarantees that all deferred events will be processed. - * - * Alternately, the caller can call hasDeferredEvent() to determine whether there is - * a deferred event waiting and then ensure that its event loop wakes up at least - * one more time to consume the deferred event. - */ - bool hasDeferredEvent() const; - - /* Returns true if there is a pending batch. - * - * Should be called after calling consume() with consumeBatches == false to determine - * whether consume() should be called again later on with consumeBatches == true. - */ - bool hasPendingBatch() const; - -private: - // True if touch resampling is enabled. - const bool mResampleTouch; - - // The input channel. - sp mChannel; - - // The current input message. - InputMessage mMsg; - - // True if mMsg contains a valid input message that was deferred from the previous - // call to consume and that still needs to be handled. - bool mMsgDeferred; - - // Batched motion events per device and source. - struct Batch { - Vector samples; - }; - Vector mBatches; - - // Touch state per device and source, only for sources of class pointer. - struct History { - nsecs_t eventTime; - BitSet32 idBits; - int32_t idToIndex[MAX_POINTER_ID + 1]; - PointerCoords pointers[MAX_POINTERS]; - - void initializeFrom(const InputMessage* msg) { - eventTime = msg->body.motion.eventTime; - idBits.clear(); - for (size_t i = 0; i < msg->body.motion.pointerCount; i++) { - uint32_t id = msg->body.motion.pointers[i].properties.id; - idBits.markBit(id); - idToIndex[id] = i; - pointers[i].copyFrom(msg->body.motion.pointers[i].coords); - } - } - - const PointerCoords& getPointerById(uint32_t id) const { - return pointers[idToIndex[id]]; - } - }; - struct TouchState { - int32_t deviceId; - int32_t source; - size_t historyCurrent; - size_t historySize; - History history[2]; - History lastResample; - - void initialize(int32_t deviceId, int32_t source) { - this->deviceId = deviceId; - this->source = source; - historyCurrent = 0; - historySize = 0; - lastResample.eventTime = 0; - lastResample.idBits.clear(); - } - - void addHistory(const InputMessage* msg) { - historyCurrent ^= 1; - if (historySize < 2) { - historySize += 1; - } - history[historyCurrent].initializeFrom(msg); - } - - const History* getHistory(size_t index) const { - return &history[(historyCurrent + index) & 1]; - } - }; - Vector mTouchStates; - - // Chain of batched sequence numbers. When multiple input messages are combined into - // a batch, we append a record here that associates the last sequence number in the - // batch with the previous one. When the finished signal is sent, we traverse the - // chain to individually finish all input messages that were part of the batch. - struct SeqChain { - uint32_t seq; // sequence number of batched input message - uint32_t chain; // sequence number of previous batched input message - }; - Vector mSeqChains; - - status_t consumeBatch(InputEventFactoryInterface* factory, - nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent); - status_t consumeSamples(InputEventFactoryInterface* factory, - Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent); - - void updateTouchState(InputMessage* msg); - void rewriteMessage(const TouchState& state, InputMessage* msg); - void resampleTouchState(nsecs_t frameTime, MotionEvent* event, - const InputMessage *next); - - ssize_t findBatch(int32_t deviceId, int32_t source) const; - ssize_t findTouchState(int32_t deviceId, int32_t source) const; - - status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled); - - static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg); - static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg); - static void addSample(MotionEvent* event, const InputMessage* msg); - static bool canAddSample(const Batch& batch, const InputMessage* msg); - static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time); - static bool shouldResampleTool(int32_t toolType); - - static bool isTouchResamplingEnabled(); -}; - -} // namespace android - -#endif // _ANDROIDFW_INPUT_TRANSPORT_H diff --git a/widget/gonk/libui/InputWindow.cpp b/widget/gonk/libui/InputWindow.cpp deleted file mode 100644 index 3aea445a0..000000000 --- a/widget/gonk/libui/InputWindow.cpp +++ /dev/null @@ -1,64 +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. - */ - -#define LOG_TAG "InputWindow" - -#include "InputWindow.h" - -#include "cutils_log.h" - -namespace android { - -// --- InputWindowInfo --- - -bool InputWindowInfo::touchableRegionContainsPoint(int32_t x, int32_t y) const { - return touchableRegion.contains(x, y); -} - -bool InputWindowInfo::frameContainsPoint(int32_t x, int32_t y) const { - return x >= frameLeft && x <= frameRight - && y >= frameTop && y <= frameBottom; -} - -bool InputWindowInfo::isTrustedOverlay() const { - return layoutParamsType == TYPE_INPUT_METHOD - || layoutParamsType == TYPE_INPUT_METHOD_DIALOG - || layoutParamsType == TYPE_SECURE_SYSTEM_OVERLAY; -} - -bool InputWindowInfo::supportsSplitTouch() const { - return layoutParamsFlags & FLAG_SPLIT_TOUCH; -} - - -// --- InputWindowHandle --- - -InputWindowHandle::InputWindowHandle(const sp& inputApplicationHandle) : - inputApplicationHandle(inputApplicationHandle), mInfo(NULL) { -} - -InputWindowHandle::~InputWindowHandle() { - delete mInfo; -} - -void InputWindowHandle::releaseInfo() { - if (mInfo) { - delete mInfo; - mInfo = NULL; - } -} - -} // namespace android diff --git a/widget/gonk/libui/InputWindow.h b/widget/gonk/libui/InputWindow.h deleted file mode 100644 index cce5fd4fe..000000000 --- a/widget/gonk/libui/InputWindow.h +++ /dev/null @@ -1,205 +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. - */ - -#ifndef _UI_INPUT_WINDOW_H -#define _UI_INPUT_WINDOW_H - -#include "Input.h" -#include "InputTransport.h" -#include -#include -#include - -#include - -#include "InputApplication.h" - -namespace android { - -/* - * Describes the properties of a window that can receive input. - */ -struct InputWindowInfo { - // Window flags from WindowManager.LayoutParams - enum { - FLAG_ALLOW_LOCK_WHILE_SCREEN_ON = 0x00000001, - FLAG_DIM_BEHIND = 0x00000002, - FLAG_BLUR_BEHIND = 0x00000004, - FLAG_NOT_FOCUSABLE = 0x00000008, - FLAG_NOT_TOUCHABLE = 0x00000010, - FLAG_NOT_TOUCH_MODAL = 0x00000020, - FLAG_TOUCHABLE_WHEN_WAKING = 0x00000040, - FLAG_KEEP_SCREEN_ON = 0x00000080, - FLAG_LAYOUT_IN_SCREEN = 0x00000100, - FLAG_LAYOUT_NO_LIMITS = 0x00000200, - FLAG_FULLSCREEN = 0x00000400, - FLAG_FORCE_NOT_FULLSCREEN = 0x00000800, - FLAG_DITHER = 0x00001000, - FLAG_SECURE = 0x00002000, - FLAG_SCALED = 0x00004000, - FLAG_IGNORE_CHEEK_PRESSES = 0x00008000, - FLAG_LAYOUT_INSET_DECOR = 0x00010000, - FLAG_ALT_FOCUSABLE_IM = 0x00020000, - FLAG_WATCH_OUTSIDE_TOUCH = 0x00040000, - FLAG_SHOW_WHEN_LOCKED = 0x00080000, - FLAG_SHOW_WALLPAPER = 0x00100000, - FLAG_TURN_SCREEN_ON = 0x00200000, - FLAG_DISMISS_KEYGUARD = 0x00400000, - FLAG_SPLIT_TOUCH = 0x00800000, - FLAG_HARDWARE_ACCELERATED = 0x01000000, - FLAG_HARDWARE_ACCELERATED_SYSTEM = 0x02000000, - FLAG_SLIPPERY = 0x04000000, - FLAG_NEEDS_MENU_KEY = 0x08000000, - FLAG_KEEP_SURFACE_WHILE_ANIMATING = 0x10000000, - FLAG_COMPATIBLE_WINDOW = 0x20000000, - FLAG_SYSTEM_ERROR = 0x40000000, - }; - - // Window types from WindowManager.LayoutParams - enum { - FIRST_APPLICATION_WINDOW = 1, - TYPE_BASE_APPLICATION = 1, - TYPE_APPLICATION = 2, - TYPE_APPLICATION_STARTING = 3, - LAST_APPLICATION_WINDOW = 99, - FIRST_SUB_WINDOW = 1000, - TYPE_APPLICATION_PANEL = FIRST_SUB_WINDOW, - TYPE_APPLICATION_MEDIA = FIRST_SUB_WINDOW+1, - TYPE_APPLICATION_SUB_PANEL = FIRST_SUB_WINDOW+2, - TYPE_APPLICATION_ATTACHED_DIALOG = FIRST_SUB_WINDOW+3, - TYPE_APPLICATION_MEDIA_OVERLAY = FIRST_SUB_WINDOW+4, - LAST_SUB_WINDOW = 1999, - FIRST_SYSTEM_WINDOW = 2000, - TYPE_STATUS_BAR = FIRST_SYSTEM_WINDOW, - TYPE_SEARCH_BAR = FIRST_SYSTEM_WINDOW+1, - TYPE_PHONE = FIRST_SYSTEM_WINDOW+2, - TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3, - TYPE_KEYGUARD = FIRST_SYSTEM_WINDOW+4, - TYPE_TOAST = FIRST_SYSTEM_WINDOW+5, - TYPE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+6, - TYPE_PRIORITY_PHONE = FIRST_SYSTEM_WINDOW+7, - TYPE_SYSTEM_DIALOG = FIRST_SYSTEM_WINDOW+8, - TYPE_KEYGUARD_DIALOG = FIRST_SYSTEM_WINDOW+9, - TYPE_SYSTEM_ERROR = FIRST_SYSTEM_WINDOW+10, - TYPE_INPUT_METHOD = FIRST_SYSTEM_WINDOW+11, - TYPE_INPUT_METHOD_DIALOG= FIRST_SYSTEM_WINDOW+12, - TYPE_WALLPAPER = FIRST_SYSTEM_WINDOW+13, - TYPE_STATUS_BAR_PANEL = FIRST_SYSTEM_WINDOW+14, - TYPE_SECURE_SYSTEM_OVERLAY = FIRST_SYSTEM_WINDOW+15, - TYPE_DRAG = FIRST_SYSTEM_WINDOW+16, - TYPE_STATUS_BAR_SUB_PANEL = FIRST_SYSTEM_WINDOW+17, - TYPE_POINTER = FIRST_SYSTEM_WINDOW+18, - TYPE_NAVIGATION_BAR = FIRST_SYSTEM_WINDOW+19, - TYPE_VOLUME_OVERLAY = FIRST_SYSTEM_WINDOW+20, - TYPE_BOOT_PROGRESS = FIRST_SYSTEM_WINDOW+21, - LAST_SYSTEM_WINDOW = 2999, - }; - - enum { - INPUT_FEATURE_DISABLE_TOUCH_PAD_GESTURES = 0x00000001, - INPUT_FEATURE_NO_INPUT_CHANNEL = 0x00000002, - INPUT_FEATURE_DISABLE_USER_ACTIVITY = 0x00000004, - }; - - sp inputChannel; - String8 name; - int32_t layoutParamsFlags; - int32_t layoutParamsType; - nsecs_t dispatchingTimeout; - int32_t frameLeft; - int32_t frameTop; - int32_t frameRight; - int32_t frameBottom; - float scaleFactor; - SkRegion touchableRegion; - bool visible; - bool canReceiveKeys; - bool hasFocus; - bool hasWallpaper; - bool paused; - int32_t layer; - int32_t ownerPid; - int32_t ownerUid; - int32_t inputFeatures; - int32_t displayId; - - bool touchableRegionContainsPoint(int32_t x, int32_t y) const; - bool frameContainsPoint(int32_t x, int32_t y) const; - - /* Returns true if the window is of a trusted type that is allowed to silently - * overlay other windows for the purpose of implementing the secure views feature. - * Trusted overlays, such as IME windows, can partly obscure other windows without causing - * motion events to be delivered to them with AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED. - */ - bool isTrustedOverlay() const; - - bool supportsSplitTouch() const; -}; - - -/* - * Handle for a window that can receive input. - * - * Used by the native input dispatcher to indirectly refer to the window manager objects - * that describe a window. - */ -class InputWindowHandle : public RefBase { -public: - const sp inputApplicationHandle; - - inline const InputWindowInfo* getInfo() const { - return mInfo; - } - - inline sp getInputChannel() const { - return mInfo ? mInfo->inputChannel : NULL; - } - - inline String8 getName() const { - return mInfo ? mInfo->name : String8(""); - } - - inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const { - return mInfo ? mInfo->dispatchingTimeout : defaultValue; - } - - /** - * Requests that the state of this object be updated to reflect - * the most current available information about the application. - * - * This method should only be called from within the input dispatcher's - * critical section. - * - * Returns true on success, or false if the handle is no longer valid. - */ - virtual bool updateInfo() = 0; - - /** - * Releases the storage used by the associated information when it is - * no longer needed. - */ - void releaseInfo(); - -protected: - InputWindowHandle(const sp& inputApplicationHandle); - virtual ~InputWindowHandle(); - - InputWindowInfo* mInfo; -}; - -} // namespace android - -#endif // _UI_INPUT_WINDOW_H diff --git a/widget/gonk/libui/KeyCharacterMap.cpp b/widget/gonk/libui/KeyCharacterMap.cpp deleted file mode 100644 index cec0666ce..000000000 --- a/widget/gonk/libui/KeyCharacterMap.cpp +++ /dev/null @@ -1,1153 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#define LOG_TAG "KeyCharacterMap" -#include "cutils_log.h" - -#include -#include -#include "android_keycodes.h" -#include "Keyboard.h" -#include "KeyCharacterMap.h" - -#if HAVE_ANDROID_OS -#include -#endif - -#include -#include "Tokenizer.h" -#include - -// Enables debug output for the parser. -#define DEBUG_PARSER 0 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - -// Enables debug output for mapping. -#define DEBUG_MAPPING 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; -static const char* WHITESPACE_OR_PROPERTY_DELIMITER = " \t\r,:"; - -struct Modifier { - const char* label; - int32_t metaState; -}; -static const Modifier modifiers[] = { - { "shift", AMETA_SHIFT_ON }, - { "lshift", AMETA_SHIFT_LEFT_ON }, - { "rshift", AMETA_SHIFT_RIGHT_ON }, - { "alt", AMETA_ALT_ON }, - { "lalt", AMETA_ALT_LEFT_ON }, - { "ralt", AMETA_ALT_RIGHT_ON }, - { "ctrl", AMETA_CTRL_ON }, - { "lctrl", AMETA_CTRL_LEFT_ON }, - { "rctrl", AMETA_CTRL_RIGHT_ON }, - { "meta", AMETA_META_ON }, - { "lmeta", AMETA_META_LEFT_ON }, - { "rmeta", AMETA_META_RIGHT_ON }, - { "sym", AMETA_SYM_ON }, - { "fn", AMETA_FUNCTION_ON }, - { "capslock", AMETA_CAPS_LOCK_ON }, - { "numlock", AMETA_NUM_LOCK_ON }, - { "scrolllock", AMETA_SCROLL_LOCK_ON }, -}; - -#if DEBUG_MAPPING -static String8 toString(const char16_t* chars, size_t numChars) { - String8 result; - for (size_t i = 0; i < numChars; i++) { - result.appendFormat(i == 0 ? "%d" : ", %d", chars[i]); - } - return result; -} -#endif - - -// --- KeyCharacterMap --- - -sp KeyCharacterMap::sEmpty = new KeyCharacterMap(); - -KeyCharacterMap::KeyCharacterMap() : - mType(KEYBOARD_TYPE_UNKNOWN) { -} - -KeyCharacterMap::KeyCharacterMap(const KeyCharacterMap& other) : - RefBase(), mType(other.mType), mKeysByScanCode(other.mKeysByScanCode), - mKeysByUsageCode(other.mKeysByUsageCode) { - for (size_t i = 0; i < other.mKeys.size(); i++) { - mKeys.add(other.mKeys.keyAt(i), new Key(*other.mKeys.valueAt(i))); - } -} - -KeyCharacterMap::~KeyCharacterMap() { - for (size_t i = 0; i < mKeys.size(); i++) { - Key* key = mKeys.editValueAt(i); - delete key; - } -} - -status_t KeyCharacterMap::load(const String8& filename, - Format format, sp* outMap) { - outMap->clear(); - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening key character map file %s.", status, filename.string()); - } else { - status = load(tokenizer, format, outMap); - delete tokenizer; - } - return status; -} - -status_t KeyCharacterMap::loadContents(const String8& filename, const char* contents, - Format format, sp* outMap) { - outMap->clear(); - - Tokenizer* tokenizer; - status_t status = Tokenizer::fromContents(filename, contents, &tokenizer); - if (status) { - ALOGE("Error %d opening key character map.", status); - } else { - status = load(tokenizer, format, outMap); - delete tokenizer; - } - return status; -} - -status_t KeyCharacterMap::load(Tokenizer* tokenizer, - Format format, sp* outMap) { - status_t status = OK; - sp map = new KeyCharacterMap(); - if (!map.get()) { - ALOGE("Error allocating key character map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map.get(), tokenizer, format); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (!status) { - *outMap = map; - } - } - return status; -} - -sp KeyCharacterMap::combine(const sp& base, - const sp& overlay) { - if (overlay == NULL) { - return base; - } - if (base == NULL) { - return overlay; - } - - sp map = new KeyCharacterMap(*base.get()); - for (size_t i = 0; i < overlay->mKeys.size(); i++) { - int32_t keyCode = overlay->mKeys.keyAt(i); - Key* key = overlay->mKeys.valueAt(i); - ssize_t oldIndex = map->mKeys.indexOfKey(keyCode); - if (oldIndex >= 0) { - delete map->mKeys.valueAt(oldIndex); - map->mKeys.editValueAt(oldIndex) = new Key(*key); - } else { - map->mKeys.add(keyCode, new Key(*key)); - } - } - - for (size_t i = 0; i < overlay->mKeysByScanCode.size(); i++) { - map->mKeysByScanCode.replaceValueFor(overlay->mKeysByScanCode.keyAt(i), - overlay->mKeysByScanCode.valueAt(i)); - } - - for (size_t i = 0; i < overlay->mKeysByUsageCode.size(); i++) { - map->mKeysByUsageCode.replaceValueFor(overlay->mKeysByUsageCode.keyAt(i), - overlay->mKeysByUsageCode.valueAt(i)); - } - return map; -} - -sp KeyCharacterMap::empty() { - return sEmpty; -} - -int32_t KeyCharacterMap::getKeyboardType() const { - return mType; -} - -char16_t KeyCharacterMap::getDisplayLabel(int32_t keyCode) const { - char16_t result = 0; - const Key* key; - if (getKey(keyCode, &key)) { - result = key->label; - } -#if DEBUG_MAPPING - ALOGD("getDisplayLabel: keyCode=%d ~ Result %d.", keyCode, result); -#endif - return result; -} - -char16_t KeyCharacterMap::getNumber(int32_t keyCode) const { - char16_t result = 0; - const Key* key; - if (getKey(keyCode, &key)) { - result = key->number; - } -#if DEBUG_MAPPING - ALOGD("getNumber: keyCode=%d ~ Result %d.", keyCode, result); -#endif - return result; -} - -char16_t KeyCharacterMap::getCharacter(int32_t keyCode, int32_t metaState) const { - char16_t result = 0; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { - result = behavior->character; - } -#if DEBUG_MAPPING - ALOGD("getCharacter: keyCode=%d, metaState=0x%08x ~ Result %d.", keyCode, metaState, result); -#endif - return result; -} - -bool KeyCharacterMap::getFallbackAction(int32_t keyCode, int32_t metaState, - FallbackAction* outFallbackAction) const { - outFallbackAction->keyCode = 0; - outFallbackAction->metaState = 0; - - bool result = false; - const Key* key; - const Behavior* behavior; - if (getKeyBehavior(keyCode, metaState, &key, &behavior)) { - if (behavior->fallbackKeyCode) { - outFallbackAction->keyCode = behavior->fallbackKeyCode; - outFallbackAction->metaState = metaState & ~behavior->metaState; - result = true; - } - } -#if DEBUG_MAPPING - ALOGD("getFallbackKeyCode: keyCode=%d, metaState=0x%08x ~ Result %s, " - "fallback keyCode=%d, fallback metaState=0x%08x.", - keyCode, metaState, result ? "true" : "false", - outFallbackAction->keyCode, outFallbackAction->metaState); -#endif - return result; -} - -char16_t KeyCharacterMap::getMatch(int32_t keyCode, const char16_t* chars, size_t numChars, - int32_t metaState) const { - char16_t result = 0; - const Key* key; - if (getKey(keyCode, &key)) { - // Try to find the most general behavior that maps to this character. - // For example, the base key behavior will usually be last in the list. - // However, if we find a perfect meta state match for one behavior then use that one. - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if (behavior->character) { - for (size_t i = 0; i < numChars; i++) { - if (behavior->character == chars[i]) { - result = behavior->character; - if ((behavior->metaState & metaState) == behavior->metaState) { - goto ExactMatch; - } - break; - } - } - } - } - ExactMatch: ; - } -#if DEBUG_MAPPING - ALOGD("getMatch: keyCode=%d, chars=[%s], metaState=0x%08x ~ Result %d.", - keyCode, toString(chars, numChars).string(), metaState, result); -#endif - return result; -} - -bool KeyCharacterMap::getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, - Vector& outEvents) const { - nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); - - for (size_t i = 0; i < numChars; i++) { - int32_t keyCode, metaState; - char16_t ch = chars[i]; - if (!findKey(ch, &keyCode, &metaState)) { -#if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Failed to find mapping for character %d.", - deviceId, toString(chars, numChars).string(), ch); -#endif - return false; - } - - int32_t currentMetaState = 0; - addMetaKeys(outEvents, deviceId, metaState, true, now, ¤tMetaState); - addKey(outEvents, deviceId, keyCode, currentMetaState, true, now); - addKey(outEvents, deviceId, keyCode, currentMetaState, false, now); - addMetaKeys(outEvents, deviceId, metaState, false, now, ¤tMetaState); - } -#if DEBUG_MAPPING - ALOGD("getEvents: deviceId=%d, chars=[%s] ~ Generated %d events.", - deviceId, toString(chars, numChars).string(), int32_t(outEvents.size())); - for (size_t i = 0; i < outEvents.size(); i++) { - ALOGD(" Key: keyCode=%d, metaState=0x%08x, %s.", - outEvents[i].getKeyCode(), outEvents[i].getMetaState(), - outEvents[i].getAction() == AKEY_EVENT_ACTION_DOWN ? "down" : "up"); - } -#endif - return true; -} - -status_t KeyCharacterMap::mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const { - if (usageCode) { - ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); - if (index >= 0) { -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", - scanCode, usageCode, *outKeyCode); -#endif - *outKeyCode = mKeysByUsageCode.valueAt(index); - return OK; - } - } - if (scanCode) { - ssize_t index = mKeysByScanCode.indexOfKey(scanCode); - if (index >= 0) { -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.", - scanCode, usageCode, *outKeyCode); -#endif - *outKeyCode = mKeysByScanCode.valueAt(index); - return OK; - } - } - -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); -#endif - *outKeyCode = AKEYCODE_UNKNOWN; - return NAME_NOT_FOUND; -} - -bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const { - ssize_t index = mKeys.indexOfKey(keyCode); - if (index >= 0) { - *outKey = mKeys.valueAt(index); - return true; - } - return false; -} - -bool KeyCharacterMap::getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const { - const Key* key; - if (getKey(keyCode, &key)) { - const Behavior* behavior = key->firstBehavior; - while (behavior) { - if (matchesMetaState(metaState, behavior->metaState)) { - *outKey = key; - *outBehavior = behavior; - return true; - } - behavior = behavior->next; - } - } - return false; -} - -bool KeyCharacterMap::matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState) { - // Behavior must have at least the set of meta states specified. - // And if the key event has CTRL, ALT or META then the behavior must exactly - // match those, taking into account that a behavior can specify that it handles - // one, both or either of a left/right modifier pair. - if ((eventMetaState & behaviorMetaState) == behaviorMetaState) { - const int32_t EXACT_META_STATES = - AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON - | AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON - | AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON; - int32_t unmatchedMetaState = eventMetaState & ~behaviorMetaState & EXACT_META_STATES; - if (behaviorMetaState & AMETA_CTRL_ON) { - unmatchedMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON); - } else if (behaviorMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { - unmatchedMetaState &= ~AMETA_CTRL_ON; - } - if (behaviorMetaState & AMETA_ALT_ON) { - unmatchedMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON); - } else if (behaviorMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { - unmatchedMetaState &= ~AMETA_ALT_ON; - } - if (behaviorMetaState & AMETA_META_ON) { - unmatchedMetaState &= ~(AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); - } else if (behaviorMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { - unmatchedMetaState &= ~AMETA_META_ON; - } - return !unmatchedMetaState; - } - return false; -} - -bool KeyCharacterMap::findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const { - if (!ch) { - return false; - } - - for (size_t i = 0; i < mKeys.size(); i++) { - const Key* key = mKeys.valueAt(i); - - // Try to find the most general behavior that maps to this character. - // For example, the base key behavior will usually be last in the list. - const Behavior* found = NULL; - for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) { - if (behavior->character == ch) { - found = behavior; - } - } - if (found) { - *outKeyCode = mKeys.keyAt(i); - *outMetaState = found->metaState; - return true; - } - } - return false; -} - -void KeyCharacterMap::addKey(Vector& outEvents, - int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) { - outEvents.push(); - KeyEvent& event = outEvents.editTop(); - event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, - down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP, - 0, keyCode, 0, metaState, 0, time, time); -} - -void KeyCharacterMap::addMetaKeys(Vector& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t* currentMetaState) { - // Add and remove meta keys symmetrically. - if (down) { - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); - - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, - AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, - AMETA_SHIFT_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, - AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, - AMETA_ALT_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, - AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, - AMETA_CTRL_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, - AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, - AMETA_META_ON, currentMetaState); - - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, true, time, - AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); - } else { - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_FUNCTION, AMETA_FUNCTION_ON, currentMetaState); - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_SYM, AMETA_SYM_ON, currentMetaState); - - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_META_LEFT, AMETA_META_LEFT_ON, - AKEYCODE_META_RIGHT, AMETA_META_RIGHT_ON, - AMETA_META_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_CTRL_LEFT, AMETA_CTRL_LEFT_ON, - AKEYCODE_CTRL_RIGHT, AMETA_CTRL_RIGHT_ON, - AMETA_CTRL_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_ALT_LEFT, AMETA_ALT_LEFT_ON, - AKEYCODE_ALT_RIGHT, AMETA_ALT_RIGHT_ON, - AMETA_ALT_ON, currentMetaState); - addDoubleEphemeralMetaKey(outEvents, deviceId, metaState, false, time, - AKEYCODE_SHIFT_LEFT, AMETA_SHIFT_LEFT_ON, - AKEYCODE_SHIFT_RIGHT, AMETA_SHIFT_RIGHT_ON, - AMETA_SHIFT_ON, currentMetaState); - - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_SCROLL_LOCK, AMETA_SCROLL_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_NUM_LOCK, AMETA_NUM_LOCK_ON, currentMetaState); - addLockedMetaKey(outEvents, deviceId, metaState, time, - AKEYCODE_CAPS_LOCK, AMETA_CAPS_LOCK_ON, currentMetaState); - } -} - -bool KeyCharacterMap::addSingleEphemeralMetaKey(Vector& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState) { - if ((metaState & keyMetaState) == keyMetaState) { - *currentMetaState = updateMetaState(keyCode, down, *currentMetaState); - addKey(outEvents, deviceId, keyCode, *currentMetaState, down, time); - return true; - } - return false; -} - -void KeyCharacterMap::addDoubleEphemeralMetaKey(Vector& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t leftKeyCode, int32_t leftKeyMetaState, - int32_t rightKeyCode, int32_t rightKeyMetaState, - int32_t eitherKeyMetaState, - int32_t* currentMetaState) { - bool specific = false; - specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, - leftKeyCode, leftKeyMetaState, currentMetaState); - specific |= addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, - rightKeyCode, rightKeyMetaState, currentMetaState); - - if (!specific) { - addSingleEphemeralMetaKey(outEvents, deviceId, metaState, down, time, - leftKeyCode, eitherKeyMetaState, currentMetaState); - } -} - -void KeyCharacterMap::addLockedMetaKey(Vector& outEvents, - int32_t deviceId, int32_t metaState, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState) { - if ((metaState & keyMetaState) == keyMetaState) { - *currentMetaState = updateMetaState(keyCode, true, *currentMetaState); - addKey(outEvents, deviceId, keyCode, *currentMetaState, true, time); - *currentMetaState = updateMetaState(keyCode, false, *currentMetaState); - addKey(outEvents, deviceId, keyCode, *currentMetaState, false, time); - } -} - -#if HAVE_ANDROID_OS -sp KeyCharacterMap::readFromParcel(Parcel* parcel) { - sp map = new KeyCharacterMap(); - map->mType = parcel->readInt32(); - size_t numKeys = parcel->readInt32(); - if (parcel->errorCheck()) { - return NULL; - } - - for (size_t i = 0; i < numKeys; i++) { - int32_t keyCode = parcel->readInt32(); - char16_t label = parcel->readInt32(); - char16_t number = parcel->readInt32(); - if (parcel->errorCheck()) { - return NULL; - } - - Key* key = new Key(); - key->label = label; - key->number = number; - map->mKeys.add(keyCode, key); - - Behavior* lastBehavior = NULL; - while (parcel->readInt32()) { - int32_t metaState = parcel->readInt32(); - char16_t character = parcel->readInt32(); - int32_t fallbackKeyCode = parcel->readInt32(); - if (parcel->errorCheck()) { - return NULL; - } - - Behavior* behavior = new Behavior(); - behavior->metaState = metaState; - behavior->character = character; - behavior->fallbackKeyCode = fallbackKeyCode; - if (lastBehavior) { - lastBehavior->next = behavior; - } else { - key->firstBehavior = behavior; - } - lastBehavior = behavior; - } - - if (parcel->errorCheck()) { - return NULL; - } - } - return map; -} - -void KeyCharacterMap::writeToParcel(Parcel* parcel) const { - parcel->writeInt32(mType); - - size_t numKeys = mKeys.size(); - parcel->writeInt32(numKeys); - for (size_t i = 0; i < numKeys; i++) { - int32_t keyCode = mKeys.keyAt(i); - const Key* key = mKeys.valueAt(i); - parcel->writeInt32(keyCode); - parcel->writeInt32(key->label); - parcel->writeInt32(key->number); - for (const Behavior* behavior = key->firstBehavior; behavior != NULL; - behavior = behavior->next) { - parcel->writeInt32(1); - parcel->writeInt32(behavior->metaState); - parcel->writeInt32(behavior->character); - parcel->writeInt32(behavior->fallbackKeyCode); - } - parcel->writeInt32(0); - } -} -#endif - - -// --- KeyCharacterMap::Key --- - -KeyCharacterMap::Key::Key() : - label(0), number(0), firstBehavior(NULL) { -} - -KeyCharacterMap::Key::Key(const Key& other) : - label(other.label), number(other.number), - firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) { -} - -KeyCharacterMap::Key::~Key() { - Behavior* behavior = firstBehavior; - while (behavior) { - Behavior* next = behavior->next; - delete behavior; - behavior = next; - } -} - - -// --- KeyCharacterMap::Behavior --- - -KeyCharacterMap::Behavior::Behavior() : - next(NULL), metaState(0), character(0), fallbackKeyCode(0) { -} - -KeyCharacterMap::Behavior::Behavior(const Behavior& other) : - next(other.next ? new Behavior(*other.next) : NULL), - metaState(other.metaState), character(other.character), - fallbackKeyCode(other.fallbackKeyCode) { -} - - -// --- KeyCharacterMap::Parser --- - -KeyCharacterMap::Parser::Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format) : - mMap(map), mTokenizer(tokenizer), mFormat(format), mState(STATE_TOP) { -} - -KeyCharacterMap::Parser::~Parser() { -} - -status_t KeyCharacterMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - switch (mState) { - case STATE_TOP: { - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "type") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseType(); - if (status) return status; - } else if (keywordToken == "map") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseMap(); - if (status) return status; - } else if (keywordToken == "key") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseKey(); - if (status) return status; - } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); - return BAD_VALUE; - } - break; - } - - case STATE_KEY: { - status_t status = parseKeyProperty(); - if (status) return status; - break; - } - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - } - - mTokenizer->nextLine(); - } - - if (mState != STATE_TOP) { - ALOGE("%s: Unterminated key description at end of file.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - if (mMap->mType == KEYBOARD_TYPE_UNKNOWN) { - ALOGE("%s: Keyboard layout missing required keyboard 'type' declaration.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - if (mFormat == FORMAT_BASE) { - if (mMap->mType == KEYBOARD_TYPE_OVERLAY) { - ALOGE("%s: Base keyboard layout must specify a keyboard 'type' other than 'OVERLAY'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } else if (mFormat == FORMAT_OVERLAY) { - if (mMap->mType != KEYBOARD_TYPE_OVERLAY) { - ALOGE("%s: Overlay keyboard layout missing required keyboard " - "'type OVERLAY' declaration.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } - - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseType() { - if (mMap->mType != KEYBOARD_TYPE_UNKNOWN) { - ALOGE("%s: Duplicate keyboard 'type' declaration.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - KeyboardType type; - String8 typeToken = mTokenizer->nextToken(WHITESPACE); - if (typeToken == "NUMERIC") { - type = KEYBOARD_TYPE_NUMERIC; - } else if (typeToken == "PREDICTIVE") { - type = KEYBOARD_TYPE_PREDICTIVE; - } else if (typeToken == "ALPHA") { - type = KEYBOARD_TYPE_ALPHA; - } else if (typeToken == "FULL") { - type = KEYBOARD_TYPE_FULL; - } else if (typeToken == "SPECIAL_FUNCTION") { - type = KEYBOARD_TYPE_SPECIAL_FUNCTION; - } else if (typeToken == "OVERLAY") { - type = KEYBOARD_TYPE_OVERLAY; - } else { - ALOGE("%s: Expected keyboard type label, got '%s'.", mTokenizer->getLocation().string(), - typeToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed type: type=%d.", type); -#endif - mMap->mType = type; - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseMap() { - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "key") { - mTokenizer->skipDelimiters(WHITESPACE); - return parseMapKey(); - } - ALOGE("%s: Expected keyword after 'map', got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); - return BAD_VALUE; -} - -status_t KeyCharacterMap::Parser::parseMapKey() { - String8 codeToken = mTokenizer->nextToken(WHITESPACE); - bool mapUsage = false; - if (codeToken == "usage") { - mapUsage = true; - mTokenizer->skipDelimiters(WHITESPACE); - codeToken = mTokenizer->nextToken(WHITESPACE); - } - - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - KeyedVector& map = - mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; - if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); - if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed map key %s: code=%d, keyCode=%d.", - mapUsage ? "usage" : "scan code", code, keyCode); -#endif - map.add(code, keyCode); - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseKey() { - String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); - if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - if (mMap->mKeys.indexOfKey(keyCode) >= 0) { - ALOGE("%s: Duplicate entry for key code '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 openBraceToken = mTokenizer->nextToken(WHITESPACE); - if (openBraceToken != "{") { - ALOGE("%s: Expected '{' after key code label, got '%s'.", - mTokenizer->getLocation().string(), openBraceToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed beginning of key: keyCode=%d.", keyCode); -#endif - mKeyCode = keyCode; - mMap->mKeys.add(keyCode, new Key()); - mState = STATE_KEY; - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseKeyProperty() { - Key* key = mMap->mKeys.valueFor(mKeyCode); - String8 token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); - if (token == "}") { - mState = STATE_TOP; - return finishKey(key); - } - - Vector properties; - - // Parse all comma-delimited property names up to the first colon. - for (;;) { - if (token == "label") { - properties.add(Property(PROPERTY_LABEL)); - } else if (token == "number") { - properties.add(Property(PROPERTY_NUMBER)); - } else { - int32_t metaState; - status_t status = parseModifier(token, &metaState); - if (status) { - ALOGE("%s: Expected a property name or modifier, got '%s'.", - mTokenizer->getLocation().string(), token.string()); - return status; - } - properties.add(Property(PROPERTY_META, metaState)); - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol()) { - char ch = mTokenizer->nextChar(); - if (ch == ':') { - break; - } else if (ch == ',') { - mTokenizer->skipDelimiters(WHITESPACE); - token = mTokenizer->nextToken(WHITESPACE_OR_PROPERTY_DELIMITER); - continue; - } - } - - ALOGE("%s: Expected ',' or ':' after property name.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - // Parse behavior after the colon. - mTokenizer->skipDelimiters(WHITESPACE); - - Behavior behavior; - bool haveCharacter = false; - bool haveFallback = false; - - do { - char ch = mTokenizer->peekChar(); - if (ch == '\'') { - char16_t character; - status_t status = parseCharacterLiteral(&character); - if (status || !character) { - ALOGE("%s: Invalid character literal for key.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - if (haveCharacter) { - ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - behavior.character = character; - haveCharacter = true; - } else { - token = mTokenizer->nextToken(WHITESPACE); - if (token == "none") { - if (haveCharacter) { - ALOGE("%s: Cannot combine multiple character literals or 'none'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - haveCharacter = true; - } else if (token == "fallback") { - mTokenizer->skipDelimiters(WHITESPACE); - token = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(token.string()); - if (!keyCode) { - ALOGE("%s: Invalid key code label for fallback behavior, got '%s'.", - mTokenizer->getLocation().string(), - token.string()); - return BAD_VALUE; - } - if (haveFallback) { - ALOGE("%s: Cannot combine multiple fallback key codes.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - behavior.fallbackKeyCode = keyCode; - haveFallback = true; - } else { - ALOGE("%s: Expected a key behavior after ':'.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } - - mTokenizer->skipDelimiters(WHITESPACE); - } while (!mTokenizer->isEol() && mTokenizer->peekChar() != '#'); - - // Add the behavior. - for (size_t i = 0; i < properties.size(); i++) { - const Property& property = properties.itemAt(i); - switch (property.property) { - case PROPERTY_LABEL: - if (key->label) { - ALOGE("%s: Duplicate label for key.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - key->label = behavior.character; -#if DEBUG_PARSER - ALOGD("Parsed key label: keyCode=%d, label=%d.", mKeyCode, key->label); -#endif - break; - case PROPERTY_NUMBER: - if (key->number) { - ALOGE("%s: Duplicate number for key.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - key->number = behavior.character; -#if DEBUG_PARSER - ALOGD("Parsed key number: keyCode=%d, number=%d.", mKeyCode, key->number); -#endif - break; - case PROPERTY_META: { - for (Behavior* b = key->firstBehavior; b; b = b->next) { - if (b->metaState == property.metaState) { - ALOGE("%s: Duplicate key behavior for modifier.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - } - Behavior* newBehavior = new Behavior(behavior); - newBehavior->metaState = property.metaState; - newBehavior->next = key->firstBehavior; - key->firstBehavior = newBehavior; -#if DEBUG_PARSER - ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode, - newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode); -#endif - break; - } - } - } - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::finishKey(Key* key) { - // Fill in default number property. - if (!key->number) { - char16_t digit = 0; - char16_t symbol = 0; - for (Behavior* b = key->firstBehavior; b; b = b->next) { - char16_t ch = b->character; - if (ch) { - if (ch >= '0' && ch <= '9') { - digit = ch; - } else if (ch == '(' || ch == ')' || ch == '#' || ch == '*' - || ch == '-' || ch == '+' || ch == ',' || ch == '.' - || ch == '\'' || ch == ':' || ch == ';' || ch == '/') { - symbol = ch; - } - } - } - key->number = digit ? digit : symbol; - } - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseModifier(const String8& token, int32_t* outMetaState) { - if (token == "base") { - *outMetaState = 0; - return NO_ERROR; - } - - int32_t combinedMeta = 0; - - const char* str = token.string(); - const char* start = str; - for (const char* cur = str; ; cur++) { - char ch = *cur; - if (ch == '+' || ch == '\0') { - size_t len = cur - start; - int32_t metaState = 0; - for (size_t i = 0; i < sizeof(modifiers) / sizeof(Modifier); i++) { - if (strlen(modifiers[i].label) == len - && strncmp(modifiers[i].label, start, len) == 0) { - metaState = modifiers[i].metaState; - break; - } - } - if (!metaState) { - return BAD_VALUE; - } - if (combinedMeta & metaState) { - ALOGE("%s: Duplicate modifier combination '%s'.", - mTokenizer->getLocation().string(), token.string()); - return BAD_VALUE; - } - - combinedMeta |= metaState; - start = cur + 1; - - if (ch == '\0') { - break; - } - } - } - *outMetaState = combinedMeta; - return NO_ERROR; -} - -status_t KeyCharacterMap::Parser::parseCharacterLiteral(char16_t* outCharacter) { - char ch = mTokenizer->nextChar(); - if (ch != '\'') { - goto Error; - } - - ch = mTokenizer->nextChar(); - if (ch == '\\') { - // Escape sequence. - ch = mTokenizer->nextChar(); - if (ch == 'n') { - *outCharacter = '\n'; - } else if (ch == 't') { - *outCharacter = '\t'; - } else if (ch == '\\') { - *outCharacter = '\\'; - } else if (ch == '\'') { - *outCharacter = '\''; - } else if (ch == '"') { - *outCharacter = '"'; - } else if (ch == 'u') { - *outCharacter = 0; - for (int i = 0; i < 4; i++) { - ch = mTokenizer->nextChar(); - int digit; - if (ch >= '0' && ch <= '9') { - digit = ch - '0'; - } else if (ch >= 'A' && ch <= 'F') { - digit = ch - 'A' + 10; - } else if (ch >= 'a' && ch <= 'f') { - digit = ch - 'a' + 10; - } else { - goto Error; - } - *outCharacter = (*outCharacter << 4) | digit; - } - } else { - goto Error; - } - } else if (ch >= 32 && ch <= 126 && ch != '\'') { - // ASCII literal character. - *outCharacter = ch; - } else { - goto Error; - } - - ch = mTokenizer->nextChar(); - if (ch != '\'') { - goto Error; - } - - // Ensure that we consumed the entire token. - if (mTokenizer->nextToken(WHITESPACE).isEmpty()) { - return NO_ERROR; - } - -Error: - ALOGE("%s: Malformed character literal.", mTokenizer->getLocation().string()); - return BAD_VALUE; -} - -} // namespace android diff --git a/widget/gonk/libui/KeyCharacterMap.h b/widget/gonk/libui/KeyCharacterMap.h deleted file mode 100644 index c7a684105..000000000 --- a/widget/gonk/libui/KeyCharacterMap.h +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef _ANDROIDFW_KEY_CHARACTER_MAP_H -#define _ANDROIDFW_KEY_CHARACTER_MAP_H - -#include - -#if HAVE_ANDROID_OS -#include -#endif - -#include "Input.h" -#include -#include -#include "Tokenizer.h" -#include -#include -#include - -namespace android { - -/** - * Describes a mapping from Android key codes to characters. - * Also specifies other functions of the keyboard such as the keyboard type - * and key modifier semantics. - * - * This object is immutable after it has been loaded. - */ -class KeyCharacterMap : public RefBase { -public: - enum KeyboardType { - KEYBOARD_TYPE_UNKNOWN = 0, - KEYBOARD_TYPE_NUMERIC = 1, - KEYBOARD_TYPE_PREDICTIVE = 2, - KEYBOARD_TYPE_ALPHA = 3, - KEYBOARD_TYPE_FULL = 4, - KEYBOARD_TYPE_SPECIAL_FUNCTION = 5, - KEYBOARD_TYPE_OVERLAY = 6, - }; - - enum Format { - // Base keyboard layout, may contain device-specific options, such as "type" declaration. - FORMAT_BASE = 0, - // Overlay keyboard layout, more restrictive, may be published by applications, - // cannot override device-specific options. - FORMAT_OVERLAY = 1, - // Either base or overlay layout ok. - FORMAT_ANY = 2, - }; - - // Substitute key code and meta state for fallback action. - struct FallbackAction { - int32_t keyCode; - int32_t metaState; - }; - - /* Loads a key character map from a file. */ - static status_t load(const String8& filename, Format format, sp* outMap); - - /* Loads a key character map from its string contents. */ - static status_t loadContents(const String8& filename, - const char* contents, Format format, sp* outMap); - - /* Combines a base key character map and an overlay. */ - static sp combine(const sp& base, - const sp& overlay); - - /* Returns an empty key character map. */ - static sp empty(); - - /* Gets the keyboard type. */ - int32_t getKeyboardType() const; - - /* Gets the primary character for this key as in the label physically printed on it. - * Returns 0 if none (eg. for non-printing keys). */ - char16_t getDisplayLabel(int32_t keyCode) const; - - /* Gets the Unicode character for the number or symbol generated by the key - * when the keyboard is used as a dialing pad. - * Returns 0 if no number or symbol is generated. - */ - char16_t getNumber(int32_t keyCode) const; - - /* Gets the Unicode character generated by the key and meta key modifiers. - * Returns 0 if no character is generated. - */ - char16_t getCharacter(int32_t keyCode, int32_t metaState) const; - - /* Gets the fallback action to use by default if the application does not - * handle the specified key. - * Returns true if an action was available, false if none. - */ - bool getFallbackAction(int32_t keyCode, int32_t metaState, - FallbackAction* outFallbackAction) const; - - /* Gets the first matching Unicode character that can be generated by the key, - * preferring the one with the specified meta key modifiers. - * Returns 0 if no matching character is generated. - */ - char16_t getMatch(int32_t keyCode, const char16_t* chars, - size_t numChars, int32_t metaState) const; - - /* Gets a sequence of key events that could plausibly generate the specified - * character sequence. Returns false if some of the characters cannot be generated. - */ - bool getEvents(int32_t deviceId, const char16_t* chars, size_t numChars, - Vector& outEvents) const; - - /* Maps a scan code and usage code to a key code, in case this key map overrides - * the mapping in some way. */ - status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const; - -#if HAVE_ANDROID_OS - /* Reads a key map from a parcel. */ - static sp readFromParcel(Parcel* parcel); - - /* Writes a key map to a parcel. */ - void writeToParcel(Parcel* parcel) const; -#endif - -protected: - virtual ~KeyCharacterMap(); - -private: - struct Behavior { - Behavior(); - Behavior(const Behavior& other); - - /* The next behavior in the list, or NULL if none. */ - Behavior* next; - - /* The meta key modifiers for this behavior. */ - int32_t metaState; - - /* The character to insert. */ - char16_t character; - - /* The fallback keycode if the key is not handled. */ - int32_t fallbackKeyCode; - }; - - struct Key { - Key(); - Key(const Key& other); - ~Key(); - - /* The single character label printed on the key, or 0 if none. */ - char16_t label; - - /* The number or symbol character generated by the key, or 0 if none. */ - char16_t number; - - /* The list of key behaviors sorted from most specific to least specific - * meta key binding. */ - Behavior* firstBehavior; - }; - - class Parser { - enum State { - STATE_TOP = 0, - STATE_KEY = 1, - }; - - enum { - PROPERTY_LABEL = 1, - PROPERTY_NUMBER = 2, - PROPERTY_META = 3, - }; - - struct Property { - inline Property(int32_t property = 0, int32_t metaState = 0) : - property(property), metaState(metaState) { } - - int32_t property; - int32_t metaState; - }; - - KeyCharacterMap* mMap; - Tokenizer* mTokenizer; - Format mFormat; - State mState; - int32_t mKeyCode; - - public: - Parser(KeyCharacterMap* map, Tokenizer* tokenizer, Format format); - ~Parser(); - status_t parse(); - - private: - status_t parseType(); - status_t parseMap(); - status_t parseMapKey(); - status_t parseKey(); - status_t parseKeyProperty(); - status_t finishKey(Key* key); - status_t parseModifier(const String8& token, int32_t* outMetaState); - status_t parseCharacterLiteral(char16_t* outCharacter); - }; - - static sp sEmpty; - - KeyedVector mKeys; - int mType; - - KeyedVector mKeysByScanCode; - KeyedVector mKeysByUsageCode; - - KeyCharacterMap(); - KeyCharacterMap(const KeyCharacterMap& other); - - bool getKey(int32_t keyCode, const Key** outKey) const; - bool getKeyBehavior(int32_t keyCode, int32_t metaState, - const Key** outKey, const Behavior** outBehavior) const; - static bool matchesMetaState(int32_t eventMetaState, int32_t behaviorMetaState); - - bool findKey(char16_t ch, int32_t* outKeyCode, int32_t* outMetaState) const; - - static status_t load(Tokenizer* tokenizer, Format format, sp* outMap); - - static void addKey(Vector& outEvents, - int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time); - static void addMetaKeys(Vector& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t* currentMetaState); - static bool addSingleEphemeralMetaKey(Vector& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState); - static void addDoubleEphemeralMetaKey(Vector& outEvents, - int32_t deviceId, int32_t metaState, bool down, nsecs_t time, - int32_t leftKeyCode, int32_t leftKeyMetaState, - int32_t rightKeyCode, int32_t rightKeyMetaState, - int32_t eitherKeyMetaState, - int32_t* currentMetaState); - static void addLockedMetaKey(Vector& outEvents, - int32_t deviceId, int32_t metaState, nsecs_t time, - int32_t keyCode, int32_t keyMetaState, - int32_t* currentMetaState); -}; - -} // namespace android - -#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H diff --git a/widget/gonk/libui/KeyLayoutMap.cpp b/widget/gonk/libui/KeyLayoutMap.cpp deleted file mode 100644 index 8af4b84e0..000000000 --- a/widget/gonk/libui/KeyLayoutMap.cpp +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#define LOG_TAG "KeyLayoutMap" -#include "cutils_log.h" - -#include -#include "android_keycodes.h" -#include "Keyboard.h" -#include "KeyLayoutMap.h" -#include -#include "Tokenizer.h" -#include - -// Enables debug output for the parser. -#define DEBUG_PARSER 0 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - -// Enables debug output for mapping. -#define DEBUG_MAPPING 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; - -// --- KeyLayoutMap --- - -KeyLayoutMap::KeyLayoutMap() { -} - -KeyLayoutMap::~KeyLayoutMap() { -} - -status_t KeyLayoutMap::load(const String8& filename, sp* outMap) { - outMap->clear(); - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening key layout map file %s.", status, filename.string()); - } else { - sp map = new KeyLayoutMap(); - if (!map.get()) { - ALOGE("Error allocating key layout map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map.get(), tokenizer); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (!status) { - *outMap = map; - } - } - delete tokenizer; - } - return status; -} - -status_t KeyLayoutMap::mapKey(int32_t scanCode, int32_t usageCode, - int32_t* outKeyCode, uint32_t* outFlags) const { - const Key* key = getKey(scanCode, usageCode); - if (!key) { -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode); -#endif - *outKeyCode = AKEYCODE_UNKNOWN; - *outFlags = 0; - return NAME_NOT_FOUND; - } - - *outKeyCode = key->keyCode; - *outFlags = key->flags; - -#if DEBUG_MAPPING - ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d, outFlags=0x%08x.", - scanCode, usageCode, *outKeyCode, *outFlags); -#endif - return NO_ERROR; -} - -const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const { - if (usageCode) { - ssize_t index = mKeysByUsageCode.indexOfKey(usageCode); - if (index >= 0) { - return &mKeysByUsageCode.valueAt(index); - } - } - if (scanCode) { - ssize_t index = mKeysByScanCode.indexOfKey(scanCode); - if (index >= 0) { - return &mKeysByScanCode.valueAt(index); - } - } - return NULL; -} - -status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector* outScanCodes) const { - const size_t N = mKeysByScanCode.size(); - for (size_t i=0; iadd(mKeysByScanCode.keyAt(i)); - } - } - return NO_ERROR; -} - -status_t KeyLayoutMap::mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const { - ssize_t index = mAxes.indexOfKey(scanCode); - if (index < 0) { -#if DEBUG_MAPPING - ALOGD("mapAxis: scanCode=%d ~ Failed.", scanCode); -#endif - return NAME_NOT_FOUND; - } - - *outAxisInfo = mAxes.valueAt(index); - -#if DEBUG_MAPPING - ALOGD("mapAxis: scanCode=%d ~ Result mode=%d, axis=%d, highAxis=%d, " - "splitValue=%d, flatOverride=%d.", - scanCode, - outAxisInfo->mode, outAxisInfo->axis, outAxisInfo->highAxis, - outAxisInfo->splitValue, outAxisInfo->flatOverride); -#endif - return NO_ERROR; -} - -status_t KeyLayoutMap::findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const { - const size_t N = mLedsByScanCode.size(); - for (size_t i = 0; i < N; i++) { - if (mLedsByScanCode.valueAt(i).ledCode == ledCode) { - *outScanCode = mLedsByScanCode.keyAt(i); -#if DEBUG_MAPPING - ALOGD("findScanCodeForLed: ledCode=%d, scanCode=%d.", ledCode, *outScanCode); -#endif - return NO_ERROR; - } - } -#if DEBUG_MAPPING - ALOGD("findScanCodeForLed: ledCode=%d ~ Not found.", ledCode); -#endif - return NAME_NOT_FOUND; -} - -status_t KeyLayoutMap::findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const { - const size_t N = mLedsByUsageCode.size(); - for (size_t i = 0; i < N; i++) { - if (mLedsByUsageCode.valueAt(i).ledCode == ledCode) { - *outUsageCode = mLedsByUsageCode.keyAt(i); -#if DEBUG_MAPPING - ALOGD("findUsageForLed: ledCode=%d, usage=%x.", ledCode, *outUsageCode); -#endif - return NO_ERROR; - } - } -#if DEBUG_MAPPING - ALOGD("findUsageForLed: ledCode=%d ~ Not found.", ledCode); -#endif - return NAME_NOT_FOUND; -} - - -// --- KeyLayoutMap::Parser --- - -KeyLayoutMap::Parser::Parser(KeyLayoutMap* map, Tokenizer* tokenizer) : - mMap(map), mTokenizer(tokenizer) { -} - -KeyLayoutMap::Parser::~Parser() { -} - -status_t KeyLayoutMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "key") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseKey(); - if (status) return status; - } else if (keywordToken == "axis") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseAxis(); - if (status) return status; - } else if (keywordToken == "led") { - mTokenizer->skipDelimiters(WHITESPACE); - status_t status = parseLed(); - if (status) return status; - } else { - ALOGE("%s: Expected keyword, got '%s'.", mTokenizer->getLocation().string(), - keywordToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - ALOGE("%s: Expected end of line or trailing comment, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - } - - mTokenizer->nextLine(); - } - return NO_ERROR; -} - -status_t KeyLayoutMap::Parser::parseKey() { - String8 codeToken = mTokenizer->nextToken(WHITESPACE); - bool mapUsage = false; - if (codeToken == "usage") { - mapUsage = true; - mTokenizer->skipDelimiters(WHITESPACE); - codeToken = mTokenizer->nextToken(WHITESPACE); - } - - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected key %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - KeyedVector& map = - mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode; - if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for key %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 keyCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t keyCode = getKeyCodeByLabel(keyCodeToken.string()); - if (!keyCode) { - ALOGE("%s: Expected key code label, got '%s'.", mTokenizer->getLocation().string(), - keyCodeToken.string()); - return BAD_VALUE; - } - - uint32_t flags = 0; - for (;;) { - mTokenizer->skipDelimiters(WHITESPACE); - if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') break; - - String8 flagToken = mTokenizer->nextToken(WHITESPACE); - uint32_t flag = getKeyFlagByLabel(flagToken.string()); - if (!flag) { - ALOGE("%s: Expected key flag label, got '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); - return BAD_VALUE; - } - if (flags & flag) { - ALOGE("%s: Duplicate key flag '%s'.", mTokenizer->getLocation().string(), - flagToken.string()); - return BAD_VALUE; - } - flags |= flag; - } - -#if DEBUG_PARSER - ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.", - mapUsage ? "usage" : "scan code", code, keyCode, flags); -#endif - Key key; - key.keyCode = keyCode; - key.flags = flags; - map.add(code, key); - return NO_ERROR; -} - -status_t KeyLayoutMap::Parser::parseAxis() { - String8 scanCodeToken = mTokenizer->nextToken(WHITESPACE); - char* end; - int32_t scanCode = int32_t(strtol(scanCodeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected axis scan code number, got '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); - return BAD_VALUE; - } - if (mMap->mAxes.indexOfKey(scanCode) >= 0) { - ALOGE("%s: Duplicate entry for axis scan code '%s'.", mTokenizer->getLocation().string(), - scanCodeToken.string()); - return BAD_VALUE; - } - - AxisInfo axisInfo; - - mTokenizer->skipDelimiters(WHITESPACE); - String8 token = mTokenizer->nextToken(WHITESPACE); - if (token == "invert") { - axisInfo.mode = AxisInfo::MODE_INVERT; - - mTokenizer->skipDelimiters(WHITESPACE); - String8 axisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = getAxisByLabel(axisToken.string()); - if (axisInfo.axis < 0) { - ALOGE("%s: Expected inverted axis label, got '%s'.", - mTokenizer->getLocation().string(), axisToken.string()); - return BAD_VALUE; - } - } else if (token == "split") { - axisInfo.mode = AxisInfo::MODE_SPLIT; - - mTokenizer->skipDelimiters(WHITESPACE); - String8 splitToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.splitValue = int32_t(strtol(splitToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected split value, got '%s'.", - mTokenizer->getLocation().string(), splitToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 lowAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.axis = getAxisByLabel(lowAxisToken.string()); - if (axisInfo.axis < 0) { - ALOGE("%s: Expected low axis label, got '%s'.", - mTokenizer->getLocation().string(), lowAxisToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 highAxisToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.highAxis = getAxisByLabel(highAxisToken.string()); - if (axisInfo.highAxis < 0) { - ALOGE("%s: Expected high axis label, got '%s'.", - mTokenizer->getLocation().string(), highAxisToken.string()); - return BAD_VALUE; - } - } else { - axisInfo.axis = getAxisByLabel(token.string()); - if (axisInfo.axis < 0) { - ALOGE("%s: Expected axis label, 'split' or 'invert', got '%s'.", - mTokenizer->getLocation().string(), token.string()); - return BAD_VALUE; - } - } - - for (;;) { - mTokenizer->skipDelimiters(WHITESPACE); - if (mTokenizer->isEol() || mTokenizer->peekChar() == '#') { - break; - } - String8 keywordToken = mTokenizer->nextToken(WHITESPACE); - if (keywordToken == "flat") { - mTokenizer->skipDelimiters(WHITESPACE); - String8 flatToken = mTokenizer->nextToken(WHITESPACE); - axisInfo.flatOverride = int32_t(strtol(flatToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected flat value, got '%s'.", - mTokenizer->getLocation().string(), flatToken.string()); - return BAD_VALUE; - } - } else { - ALOGE("%s: Expected keyword 'flat', got '%s'.", - mTokenizer->getLocation().string(), keywordToken.string()); - return BAD_VALUE; - } - } - -#if DEBUG_PARSER - ALOGD("Parsed axis: scanCode=%d, mode=%d, axis=%d, highAxis=%d, " - "splitValue=%d, flatOverride=%d.", - scanCode, - axisInfo.mode, axisInfo.axis, axisInfo.highAxis, - axisInfo.splitValue, axisInfo.flatOverride); -#endif - mMap->mAxes.add(scanCode, axisInfo); - return NO_ERROR; -} - -status_t KeyLayoutMap::Parser::parseLed() { - String8 codeToken = mTokenizer->nextToken(WHITESPACE); - bool mapUsage = false; - if (codeToken == "usage") { - mapUsage = true; - mTokenizer->skipDelimiters(WHITESPACE); - codeToken = mTokenizer->nextToken(WHITESPACE); - } - char* end; - int32_t code = int32_t(strtol(codeToken.string(), &end, 0)); - if (*end) { - ALOGE("%s: Expected led %s number, got '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - KeyedVector& map = mapUsage ? mMap->mLedsByUsageCode : mMap->mLedsByScanCode; - if (map.indexOfKey(code) >= 0) { - ALOGE("%s: Duplicate entry for led %s '%s'.", mTokenizer->getLocation().string(), - mapUsage ? "usage" : "scan code", codeToken.string()); - return BAD_VALUE; - } - - mTokenizer->skipDelimiters(WHITESPACE); - String8 ledCodeToken = mTokenizer->nextToken(WHITESPACE); - int32_t ledCode = getLedByLabel(ledCodeToken.string()); - if (ledCode < 0) { - ALOGE("%s: Expected LED code label, got '%s'.", mTokenizer->getLocation().string(), - ledCodeToken.string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed led %s: code=%d, ledCode=%d.", - mapUsage ? "usage" : "scan code", code, ledCode); -#endif - - Led led; - led.ledCode = ledCode; - map.add(code, led); - return NO_ERROR; -} -}; diff --git a/widget/gonk/libui/KeyLayoutMap.h b/widget/gonk/libui/KeyLayoutMap.h deleted file mode 100644 index 8a6113447..000000000 --- a/widget/gonk/libui/KeyLayoutMap.h +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef _ANDROIDFW_KEY_LAYOUT_MAP_H -#define _ANDROIDFW_KEY_LAYOUT_MAP_H - -#include -#include -#include -#include "Tokenizer.h" -#include - -namespace android { - -struct AxisInfo { - enum Mode { - // Axis value is reported directly. - MODE_NORMAL = 0, - // Axis value should be inverted before reporting. - MODE_INVERT = 1, - // Axis value should be split into two axes - MODE_SPLIT = 2, - }; - - // Axis mode. - Mode mode; - - // Axis id. - // When split, this is the axis used for values smaller than the split position. - int32_t axis; - - // When split, this is the axis used for values after higher than the split position. - int32_t highAxis; - - // The split value, or 0 if not split. - int32_t splitValue; - - // The flat value, or -1 if none. - int32_t flatOverride; - - AxisInfo() : mode(MODE_NORMAL), axis(-1), highAxis(-1), splitValue(0), flatOverride(-1) { - } -}; - -/** - * Describes a mapping from keyboard scan codes and joystick axes to Android key codes and axes. - * - * This object is immutable after it has been loaded. - */ -class KeyLayoutMap : public RefBase { -public: - static status_t load(const String8& filename, sp* outMap); - - status_t mapKey(int32_t scanCode, int32_t usageCode, - int32_t* outKeyCode, uint32_t* outFlags) const; - status_t findScanCodesForKey(int32_t keyCode, Vector* outScanCodes) const; - status_t findScanCodeForLed(int32_t ledCode, int32_t* outScanCode) const; - status_t findUsageCodeForLed(int32_t ledCode, int32_t* outUsageCode) const; - - status_t mapAxis(int32_t scanCode, AxisInfo* outAxisInfo) const; - -protected: - virtual ~KeyLayoutMap(); - -private: - struct Key { - int32_t keyCode; - uint32_t flags; - }; - - struct Led { - int32_t ledCode; - }; - - - KeyedVector mKeysByScanCode; - KeyedVector mKeysByUsageCode; - KeyedVector mAxes; - KeyedVector mLedsByScanCode; - KeyedVector mLedsByUsageCode; - - KeyLayoutMap(); - - const Key* getKey(int32_t scanCode, int32_t usageCode) const; - - class Parser { - KeyLayoutMap* mMap; - Tokenizer* mTokenizer; - - public: - Parser(KeyLayoutMap* map, Tokenizer* tokenizer); - ~Parser(); - status_t parse(); - - private: - status_t parseKey(); - status_t parseAxis(); - status_t parseLed(); - }; -}; - -} // namespace android - -#endif // _ANDROIDFW_KEY_LAYOUT_MAP_H diff --git a/widget/gonk/libui/Keyboard.cpp b/widget/gonk/libui/Keyboard.cpp deleted file mode 100644 index 62bb53b7b..000000000 --- a/widget/gonk/libui/Keyboard.cpp +++ /dev/null @@ -1,300 +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. - */ - -#define LOG_TAG "Keyboard" -#include "cutils_log.h" - -#include -#include -#include - -#include "Keyboard.h" -#include "KeycodeLabels.h" -#include "KeyLayoutMap.h" -#include "KeyCharacterMap.h" -#include "InputDevice.h" -#include -#include - -namespace android { - -// --- KeyMap --- - -KeyMap::KeyMap() { -} - -KeyMap::~KeyMap() { -} - -status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier, - const PropertyMap* deviceConfiguration) { - // Use the configured key layout if available. - if (deviceConfiguration) { - String8 keyLayoutName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"), - keyLayoutName)) { - status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName); - if (status == NAME_NOT_FOUND) { - ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but " - "it was not found.", - deviceIdenfifier.name.string(), keyLayoutName.string()); - } - } - - String8 keyCharacterMapName; - if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"), - keyCharacterMapName)) { - status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName); - if (status == NAME_NOT_FOUND) { - ALOGE("Configuration for keyboard device '%s' requested keyboard character " - "map '%s' but it was not found.", - deviceIdenfifier.name.string(), keyLayoutName.string()); - } - } - - if (isComplete()) { - return OK; - } - } - - // Try searching by device identifier. - if (probeKeyMap(deviceIdenfifier, String8::empty())) { - return OK; - } - - // Fall back on the Generic key map. - // TODO Apply some additional heuristics here to figure out what kind of - // generic key map to use (US English, etc.) for typical external keyboards. - if (probeKeyMap(deviceIdenfifier, String8("Generic"))) { - return OK; - } - - // Try the Virtual key map as a last resort. - if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) { - return OK; - } - - // Give up! - ALOGE("Could not determine key map for device '%s' and no default key maps were found!", - deviceIdenfifier.name.string()); - return NAME_NOT_FOUND; -} - -bool KeyMap::probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, - const String8& keyMapName) { - if (!haveKeyLayout()) { - loadKeyLayout(deviceIdentifier, keyMapName); - } - if (!haveKeyCharacterMap()) { - loadKeyCharacterMap(deviceIdentifier, keyMapName); - } - return isComplete(); -} - -status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, - const String8& name) { - String8 path(getPath(deviceIdentifier, name, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT)); - if (path.isEmpty()) { - return NAME_NOT_FOUND; - } - - status_t status = KeyLayoutMap::load(path, &keyLayoutMap); - if (status) { - return status; - } - - keyLayoutFile.setTo(path); - return OK; -} - -status_t KeyMap::loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, - const String8& name) { - String8 path(getPath(deviceIdentifier, name, - INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP)); - if (path.isEmpty()) { - return NAME_NOT_FOUND; - } - - status_t status = KeyCharacterMap::load(path, - KeyCharacterMap::FORMAT_BASE, &keyCharacterMap); - if (status) { - return status; - } - - keyCharacterMapFile.setTo(path); - return OK; -} - -String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier, - const String8& name, InputDeviceConfigurationFileType type) { - return name.isEmpty() - ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type) - : getInputDeviceConfigurationFilePathByName(name, type); -} - - -// --- Global functions --- - -bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, - const PropertyMap* deviceConfiguration, const KeyMap* keyMap) { - if (!keyMap->haveKeyCharacterMap() - || keyMap->keyCharacterMap->getKeyboardType() - == KeyCharacterMap::KEYBOARD_TYPE_SPECIAL_FUNCTION) { - return false; - } - - if (deviceConfiguration) { - bool builtIn = false; - if (deviceConfiguration->tryGetProperty(String8("keyboard.builtIn"), builtIn) - && builtIn) { - return true; - } - } - - return strstr(deviceIdentifier.name.string(), "-keypad"); -} - -static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) { - while (list->literal) { - if (strcmp(literal, list->literal) == 0) { - return list->value; - } - list++; - } - return list->value; -} - -static const char* lookupLabelByValue(int value, const KeycodeLabel *list) { - while (list->literal) { - if (list->value == value) { - return list->literal; - } - list++; - } - return NULL; -} - -int32_t getKeyCodeByLabel(const char* label) { - return int32_t(lookupValueByLabel(label, KEYCODES)); -} - -uint32_t getKeyFlagByLabel(const char* label) { - return uint32_t(lookupValueByLabel(label, FLAGS)); -} - -int32_t getAxisByLabel(const char* label) { - return int32_t(lookupValueByLabel(label, AXES)); -} - -const char* getAxisLabel(int32_t axisId) { - return lookupLabelByValue(axisId, AXES); -} - -int32_t getLedByLabel(const char* label) { - return int32_t(lookupValueByLabel(label, LEDS)); -} -static int32_t setEphemeralMetaState(int32_t mask, bool down, int32_t oldMetaState) { - int32_t newMetaState; - if (down) { - newMetaState = oldMetaState | mask; - } else { - newMetaState = oldMetaState & - ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON); - } - - if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { - newMetaState |= AMETA_ALT_ON; - } - - if (newMetaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { - newMetaState |= AMETA_SHIFT_ON; - } - - if (newMetaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { - newMetaState |= AMETA_CTRL_ON; - } - - if (newMetaState & (AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { - newMetaState |= AMETA_META_ON; - } - return newMetaState; -} - -static int32_t toggleLockedMetaState(int32_t mask, bool down, int32_t oldMetaState) { - if (down) { - return oldMetaState; - } else { - return oldMetaState ^ mask; - } -} - -int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState) { - switch (keyCode) { - case AKEYCODE_ALT_LEFT: - return setEphemeralMetaState(AMETA_ALT_LEFT_ON, down, oldMetaState); - case AKEYCODE_ALT_RIGHT: - return setEphemeralMetaState(AMETA_ALT_RIGHT_ON, down, oldMetaState); - case AKEYCODE_SHIFT_LEFT: - return setEphemeralMetaState(AMETA_SHIFT_LEFT_ON, down, oldMetaState); - case AKEYCODE_SHIFT_RIGHT: - return setEphemeralMetaState(AMETA_SHIFT_RIGHT_ON, down, oldMetaState); - case AKEYCODE_SYM: - return setEphemeralMetaState(AMETA_SYM_ON, down, oldMetaState); - case AKEYCODE_FUNCTION: - return setEphemeralMetaState(AMETA_FUNCTION_ON, down, oldMetaState); - case AKEYCODE_CTRL_LEFT: - return setEphemeralMetaState(AMETA_CTRL_LEFT_ON, down, oldMetaState); - case AKEYCODE_CTRL_RIGHT: - return setEphemeralMetaState(AMETA_CTRL_RIGHT_ON, down, oldMetaState); - case AKEYCODE_META_LEFT: - return setEphemeralMetaState(AMETA_META_LEFT_ON, down, oldMetaState); - case AKEYCODE_META_RIGHT: - return setEphemeralMetaState(AMETA_META_RIGHT_ON, down, oldMetaState); - case AKEYCODE_CAPS_LOCK: - return toggleLockedMetaState(AMETA_CAPS_LOCK_ON, down, oldMetaState); - case AKEYCODE_NUM_LOCK: - return toggleLockedMetaState(AMETA_NUM_LOCK_ON, down, oldMetaState); - case AKEYCODE_SCROLL_LOCK: - return toggleLockedMetaState(AMETA_SCROLL_LOCK_ON, down, oldMetaState); - default: - return oldMetaState; - } -} - -bool isMetaKey(int32_t keyCode) { - switch (keyCode) { - case AKEYCODE_ALT_LEFT: - case AKEYCODE_ALT_RIGHT: - case AKEYCODE_SHIFT_LEFT: - case AKEYCODE_SHIFT_RIGHT: - case AKEYCODE_SYM: - case AKEYCODE_FUNCTION: - case AKEYCODE_CTRL_LEFT: - case AKEYCODE_CTRL_RIGHT: - case AKEYCODE_META_LEFT: - case AKEYCODE_META_RIGHT: - case AKEYCODE_CAPS_LOCK: - case AKEYCODE_NUM_LOCK: - case AKEYCODE_SCROLL_LOCK: - return true; - default: - return false; - } -} - - -} // namespace android diff --git a/widget/gonk/libui/Keyboard.h b/widget/gonk/libui/Keyboard.h deleted file mode 100644 index 65921b25b..000000000 --- a/widget/gonk/libui/Keyboard.h +++ /dev/null @@ -1,122 +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. - */ - -#ifndef _ANDROIDFW_KEYBOARD_H -#define _ANDROIDFW_KEYBOARD_H - -#include "Input.h" -#include "InputDevice.h" -#include -#include -#include - -namespace android { - -enum { - /* Device id of the built in keyboard. */ - DEVICE_ID_BUILT_IN_KEYBOARD = 0, - - /* Device id of a generic virtual keyboard with a full layout that can be used - * to synthesize key events. */ - DEVICE_ID_VIRTUAL_KEYBOARD = -1, -}; - -class KeyLayoutMap; -class KeyCharacterMap; - -/** - * Loads the key layout map and key character map for a keyboard device. - */ -class KeyMap { -public: - String8 keyLayoutFile; - sp keyLayoutMap; - - String8 keyCharacterMapFile; - sp keyCharacterMap; - - KeyMap(); - ~KeyMap(); - - status_t load(const InputDeviceIdentifier& deviceIdenfier, - const PropertyMap* deviceConfiguration); - - inline bool haveKeyLayout() const { - return !keyLayoutFile.isEmpty(); - } - - inline bool haveKeyCharacterMap() const { - return !keyCharacterMapFile.isEmpty(); - } - - inline bool isComplete() const { - return haveKeyLayout() && haveKeyCharacterMap(); - } - -private: - bool probeKeyMap(const InputDeviceIdentifier& deviceIdentifier, const String8& name); - status_t loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier, const String8& name); - status_t loadKeyCharacterMap(const InputDeviceIdentifier& deviceIdentifier, - const String8& name); - String8 getPath(const InputDeviceIdentifier& deviceIdentifier, - const String8& name, InputDeviceConfigurationFileType type); -}; - -/** - * Returns true if the keyboard is eligible for use as a built-in keyboard. - */ -extern bool isEligibleBuiltInKeyboard(const InputDeviceIdentifier& deviceIdentifier, - const PropertyMap* deviceConfiguration, const KeyMap* keyMap); - -/** - * Gets a key code by its short form label, eg. "HOME". - * Returns 0 if unknown. - */ -extern int32_t getKeyCodeByLabel(const char* label); - -/** - * Gets a key flag by its short form label, eg. "WAKE". - * Returns 0 if unknown. - */ -extern uint32_t getKeyFlagByLabel(const char* label); - -/** - * Gets a axis by its short form label, eg. "X". - * Returns -1 if unknown. - */ -extern int32_t getAxisByLabel(const char* label); - -/** - * Gets a axis label by its id. - * Returns NULL if unknown. - */ -extern const char* getAxisLabel(int32_t axisId); - -extern int32_t getLedByLabel(const char* label); - -/** - * Updates a meta state field when a key is pressed or released. - */ -extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState); - -/** - * Returns true if a key is a meta key like ALT or CAPS_LOCK. - */ -extern bool isMetaKey(int32_t keyCode); - -} // namespace android - -#endif // _ANDROIDFW_KEYBOARD_H diff --git a/widget/gonk/libui/KeycodeLabels.h b/widget/gonk/libui/KeycodeLabels.h deleted file mode 100644 index 9f994597b..000000000 --- a/widget/gonk/libui/KeycodeLabels.h +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (C) 2008 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. - */ - -#ifndef _ANDROIDFW_KEYCODE_LABELS_H -#define _ANDROIDFW_KEYCODE_LABELS_H - -#include "android_keycodes.h" - -struct KeycodeLabel { - const char *literal; - int value; -}; - -static const KeycodeLabel KEYCODES[] = { - { "SOFT_LEFT", 1 }, - { "SOFT_RIGHT", 2 }, - { "HOME", 3 }, - { "BACK", 4 }, - { "CALL", 5 }, - { "ENDCALL", 6 }, - { "0", 7 }, - { "1", 8 }, - { "2", 9 }, - { "3", 10 }, - { "4", 11 }, - { "5", 12 }, - { "6", 13 }, - { "7", 14 }, - { "8", 15 }, - { "9", 16 }, - { "STAR", 17 }, - { "POUND", 18 }, - { "DPAD_UP", 19 }, - { "DPAD_DOWN", 20 }, - { "DPAD_LEFT", 21 }, - { "DPAD_RIGHT", 22 }, - { "DPAD_CENTER", 23 }, - { "VOLUME_UP", 24 }, - { "VOLUME_DOWN", 25 }, - { "POWER", 26 }, - { "CAMERA", 27 }, - { "CLEAR", 28 }, - { "A", 29 }, - { "B", 30 }, - { "C", 31 }, - { "D", 32 }, - { "E", 33 }, - { "F", 34 }, - { "G", 35 }, - { "H", 36 }, - { "I", 37 }, - { "J", 38 }, - { "K", 39 }, - { "L", 40 }, - { "M", 41 }, - { "N", 42 }, - { "O", 43 }, - { "P", 44 }, - { "Q", 45 }, - { "R", 46 }, - { "S", 47 }, - { "T", 48 }, - { "U", 49 }, - { "V", 50 }, - { "W", 51 }, - { "X", 52 }, - { "Y", 53 }, - { "Z", 54 }, - { "COMMA", 55 }, - { "PERIOD", 56 }, - { "ALT_LEFT", 57 }, - { "ALT_RIGHT", 58 }, - { "SHIFT_LEFT", 59 }, - { "SHIFT_RIGHT", 60 }, - { "TAB", 61 }, - { "SPACE", 62 }, - { "SYM", 63 }, - { "EXPLORER", 64 }, - { "ENVELOPE", 65 }, - { "ENTER", 66 }, - { "DEL", 67 }, - { "GRAVE", 68 }, - { "MINUS", 69 }, - { "EQUALS", 70 }, - { "LEFT_BRACKET", 71 }, - { "RIGHT_BRACKET", 72 }, - { "BACKSLASH", 73 }, - { "SEMICOLON", 74 }, - { "APOSTROPHE", 75 }, - { "SLASH", 76 }, - { "AT", 77 }, - { "NUM", 78 }, - { "HEADSETHOOK", 79 }, - { "FOCUS", 80 }, - { "PLUS", 81 }, - { "MENU", 82 }, - { "NOTIFICATION", 83 }, - { "SEARCH", 84 }, - { "MEDIA_PLAY_PAUSE", 85 }, - { "MEDIA_STOP", 86 }, - { "MEDIA_NEXT", 87 }, - { "MEDIA_PREVIOUS", 88 }, - { "MEDIA_REWIND", 89 }, - { "MEDIA_FAST_FORWARD", 90 }, - { "MUTE", 91 }, - { "PAGE_UP", 92 }, - { "PAGE_DOWN", 93 }, - { "PICTSYMBOLS", 94 }, - { "SWITCH_CHARSET", 95 }, - { "BUTTON_A", 96 }, - { "BUTTON_B", 97 }, - { "BUTTON_C", 98 }, - { "BUTTON_X", 99 }, - { "BUTTON_Y", 100 }, - { "BUTTON_Z", 101 }, - { "BUTTON_L1", 102 }, - { "BUTTON_R1", 103 }, - { "BUTTON_L2", 104 }, - { "BUTTON_R2", 105 }, - { "BUTTON_THUMBL", 106 }, - { "BUTTON_THUMBR", 107 }, - { "BUTTON_START", 108 }, - { "BUTTON_SELECT", 109 }, - { "BUTTON_MODE", 110 }, - { "ESCAPE", 111 }, - { "FORWARD_DEL", 112 }, - { "CTRL_LEFT", 113 }, - { "CTRL_RIGHT", 114 }, - { "CAPS_LOCK", 115 }, - { "SCROLL_LOCK", 116 }, - { "META_LEFT", 117 }, - { "META_RIGHT", 118 }, - { "FUNCTION", 119 }, - { "SYSRQ", 120 }, - { "BREAK", 121 }, - { "MOVE_HOME", 122 }, - { "MOVE_END", 123 }, - { "INSERT", 124 }, - { "FORWARD", 125 }, - { "MEDIA_PLAY", 126 }, - { "MEDIA_PAUSE", 127 }, - { "MEDIA_CLOSE", 128 }, - { "MEDIA_EJECT", 129 }, - { "MEDIA_RECORD", 130 }, - { "F1", 131 }, - { "F2", 132 }, - { "F3", 133 }, - { "F4", 134 }, - { "F5", 135 }, - { "F6", 136 }, - { "F7", 137 }, - { "F8", 138 }, - { "F9", 139 }, - { "F10", 140 }, - { "F11", 141 }, - { "F12", 142 }, - { "NUM_LOCK", 143 }, - { "NUMPAD_0", 144 }, - { "NUMPAD_1", 145 }, - { "NUMPAD_2", 146 }, - { "NUMPAD_3", 147 }, - { "NUMPAD_4", 148 }, - { "NUMPAD_5", 149 }, - { "NUMPAD_6", 150 }, - { "NUMPAD_7", 151 }, - { "NUMPAD_8", 152 }, - { "NUMPAD_9", 153 }, - { "NUMPAD_DIVIDE", 154 }, - { "NUMPAD_MULTIPLY", 155 }, - { "NUMPAD_SUBTRACT", 156 }, - { "NUMPAD_ADD", 157 }, - { "NUMPAD_DOT", 158 }, - { "NUMPAD_COMMA", 159 }, - { "NUMPAD_ENTER", 160 }, - { "NUMPAD_EQUALS", 161 }, - { "NUMPAD_LEFT_PAREN", 162 }, - { "NUMPAD_RIGHT_PAREN", 163 }, - { "VOLUME_MUTE", 164 }, - { "INFO", 165 }, - { "CHANNEL_UP", 166 }, - { "CHANNEL_DOWN", 167 }, - { "ZOOM_IN", 168 }, - { "ZOOM_OUT", 169 }, - { "TV", 170 }, - { "WINDOW", 171 }, - { "GUIDE", 172 }, - { "DVR", 173 }, - { "BOOKMARK", 174 }, - { "CAPTIONS", 175 }, - { "SETTINGS", 176 }, - { "TV_POWER", 177 }, - { "TV_INPUT", 178 }, - { "STB_POWER", 179 }, - { "STB_INPUT", 180 }, - { "AVR_POWER", 181 }, - { "AVR_INPUT", 182 }, - { "PROG_RED", 183 }, - { "PROG_GREEN", 184 }, - { "PROG_YELLOW", 185 }, - { "PROG_BLUE", 186 }, - { "APP_SWITCH", 187 }, - { "BUTTON_1", 188 }, - { "BUTTON_2", 189 }, - { "BUTTON_3", 190 }, - { "BUTTON_4", 191 }, - { "BUTTON_5", 192 }, - { "BUTTON_6", 193 }, - { "BUTTON_7", 194 }, - { "BUTTON_8", 195 }, - { "BUTTON_9", 196 }, - { "BUTTON_10", 197 }, - { "BUTTON_11", 198 }, - { "BUTTON_12", 199 }, - { "BUTTON_13", 200 }, - { "BUTTON_14", 201 }, - { "BUTTON_15", 202 }, - { "BUTTON_16", 203 }, - { "LANGUAGE_SWITCH", 204 }, - { "MANNER_MODE", 205 }, - { "3D_MODE", 206 }, - { "CONTACTS", 207 }, - { "CALENDAR", 208 }, - { "MUSIC", 209 }, - { "CALCULATOR", 210 }, - { "ZENKAKU_HANKAKU", 211 }, - { "EISU", 212 }, - { "MUHENKAN", 213 }, - { "HENKAN", 214 }, - { "KATAKANA_HIRAGANA", 215 }, - { "YEN", 216 }, - { "RO", 217 }, - { "KANA", 218 }, - { "ASSIST", 219 }, - { "BRIGHTNESS_DOWN", 220 }, - { "BRIGHTNESS_UP", 221 }, - { "MEDIA_AUDIO_TRACK", 222 }, - { "SLEEP", 223 }, - { "WAKEUP", 224 }, - { "PAIRING", 225 }, - { "MEDIA_TOP_MENU", 226 }, - { "11", 227 }, - { "12", 228 }, - { "LAST_CHANNEL", 229 }, - { "TV_DATA_SERVICE", 230 }, - { "VOICE_ASSIST", 231 }, - { "TV_RADIO_SERVICE", 232 }, - { "TV_TELETEXT", 233 }, - { "TV_NUMBER_ENTRY", 234 }, - { "TV_TERRESTRIAL_ANALOG", 235 }, - { "TV_TERRESTRIAL_DIGITAL", 236 }, - { "TV_SATELLITE", 237 }, - { "TV_SATELLITE_BS", 238 }, - { "TV_SATELLITE_CS", 239 }, - { "TV_SATELLITE_SERVICE", 240 }, - { "TV_NETWORK", 241 }, - { "TV_ANTENNA_CABLE", 242 }, - { "TV_INPUT_HDMI_1", 243 }, - { "TV_INPUT_HDMI_2", 244 }, - { "TV_INPUT_HDMI_3", 245 }, - { "TV_INPUT_HDMI_4", 246 }, - { "TV_INPUT_COMPOSITE_1", 247 }, - { "TV_INPUT_COMPOSITE_2", 248 }, - { "TV_INPUT_COMPONENT_1", 249 }, - { "TV_INPUT_COMPONENT_2", 250 }, - { "TV_INPUT_VGA_1", 251 }, - { "TV_AUDIO_DESCRIPTION", 252 }, - { "TV_AUDIO_DESCRIPTION_MIX_UP", 253 }, - { "TV_AUDIO_DESCRIPTION_MIX_DOWN", 254 }, - { "TV_ZOOM_MODE", 255 }, - { "TV_CONTENTS_MENU", 256 }, - { "TV_MEDIA_CONTEXT_MENU", 257 }, - { "TV_TIMER_PROGRAMMING", 258 }, - { "HELP", 259 }, - - // NOTE: If you add a new keycode here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. - - { NULL, 0 } -}; - -// NOTE: If you edit these flags, also edit policy flags in Input.h. -static const KeycodeLabel FLAGS[] = { - { "WAKE", 0x00000001 }, - { "WAKE_DROPPED", 0x00000002 }, - { "SHIFT", 0x00000004 }, - { "CAPS_LOCK", 0x00000008 }, - { "ALT", 0x00000010 }, - { "ALT_GR", 0x00000020 }, - { "MENU", 0x00000040 }, - { "LAUNCHER", 0x00000080 }, - { "VIRTUAL", 0x00000100 }, - { "FUNCTION", 0x00000200 }, - { NULL, 0 } -}; - -static const KeycodeLabel AXES[] = { - { "X", 0 }, - { "Y", 1 }, - { "PRESSURE", 2 }, - { "SIZE", 3 }, - { "TOUCH_MAJOR", 4 }, - { "TOUCH_MINOR", 5 }, - { "TOOL_MAJOR", 6 }, - { "TOOL_MINOR", 7 }, - { "ORIENTATION", 8 }, - { "VSCROLL", 9 }, - { "HSCROLL", 10 }, - { "Z", 11 }, - { "RX", 12 }, - { "RY", 13 }, - { "RZ", 14 }, - { "HAT_X", 15 }, - { "HAT_Y", 16 }, - { "LTRIGGER", 17 }, - { "RTRIGGER", 18 }, - { "THROTTLE", 19 }, - { "RUDDER", 20 }, - { "WHEEL", 21 }, - { "GAS", 22 }, - { "BRAKE", 23 }, - { "DISTANCE", 24 }, - { "TILT", 25 }, - { "GENERIC_1", 32 }, - { "GENERIC_2", 33 }, - { "GENERIC_3", 34 }, - { "GENERIC_4", 35 }, - { "GENERIC_5", 36 }, - { "GENERIC_6", 37 }, - { "GENERIC_7", 38 }, - { "GENERIC_8", 39 }, - { "GENERIC_9", 40 }, - { "GENERIC_10", 41 }, - { "GENERIC_11", 42 }, - { "GENERIC_12", 43 }, - { "GENERIC_13", 44 }, - { "GENERIC_14", 45 }, - { "GENERIC_15", 46 }, - { "GENERIC_16", 47 }, - - // NOTE: If you add a new axis here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. - - { NULL, -1 } -}; - -static const KeycodeLabel LEDS[] = { - { "NUM_LOCK", 1}, - { "CAPS_LOCK", 2}, - { "SCROLL_LOCK", 3}, - { "COMPOSE", 4}, - { "KANA", 5}, - { "SLEEP", 6}, - { "SUSPEND", 7}, - { "MUTE", 8}, - { "MISC", 9}, - { "MAIL", 10}, - { "CHARGING", 11}, - { "CONTROLLER_1", 12}, - { "CONTROLLER_2", 13}, - { "CONTROLLER_3", 14}, - { "CONTROLLER_4", 15}, - - // NOTE: If you add new LEDs here, you must also add them to Input.h - { NULL, 0 } -}; - -#endif // _ANDROIDFW_KEYCODE_LABELS_H diff --git a/widget/gonk/libui/PointerController.cpp b/widget/gonk/libui/PointerController.cpp deleted file mode 100644 index ff80a0a9f..000000000 --- a/widget/gonk/libui/PointerController.cpp +++ /dev/null @@ -1,604 +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. - */ - -#define LOG_TAG "PointerController" - -//#define LOG_NDEBUG 0 - -// Log debug messages about pointer updates -#define DEBUG_POINTER_UPDATES 0 - -#include "PointerController.h" - -#include "cutils_log.h" - -#include -#include -#include -#include -#include - -namespace android { - -// --- PointerController --- - -// Time to wait before starting the fade when the pointer is inactive. -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL = 15 * 1000 * 1000000LL; // 15 seconds -static const nsecs_t INACTIVITY_TIMEOUT_DELAY_TIME_SHORT = 3 * 1000 * 1000000LL; // 3 seconds - -// Time to wait between animation frames. -static const nsecs_t ANIMATION_FRAME_INTERVAL = 1000000000LL / 60; - -// Time to spend fading out the spot completely. -static const nsecs_t SPOT_FADE_DURATION = 200 * 1000000LL; // 200 ms - -// Time to spend fading out the pointer completely. -static const nsecs_t POINTER_FADE_DURATION = 500 * 1000000LL; // 500 ms - - -// --- PointerController --- - -PointerController::PointerController(const sp& policy, - const sp& looper, const sp& spriteController) : - mPolicy(policy), mLooper(looper), mSpriteController(spriteController) { - mHandler = new WeakMessageHandler(this); - - AutoMutex _l(mLock); - - mLocked.animationPending = false; - - mLocked.displayWidth = -1; - mLocked.displayHeight = -1; - mLocked.displayOrientation = DISPLAY_ORIENTATION_0; - - mLocked.presentation = PRESENTATION_POINTER; - mLocked.presentationChanged = false; - - mLocked.inactivityTimeout = INACTIVITY_TIMEOUT_NORMAL; - - mLocked.pointerFadeDirection = 0; - mLocked.pointerX = 0; - mLocked.pointerY = 0; - mLocked.pointerAlpha = 0.0f; // pointer is initially faded - mLocked.pointerSprite = mSpriteController->createSprite(); - mLocked.pointerIconChanged = false; - - mLocked.buttonState = 0; - - loadResources(); -} - -PointerController::~PointerController() { - mLooper->removeMessages(mHandler); - - AutoMutex _l(mLock); - - mLocked.pointerSprite.clear(); - - for (size_t i = 0; i < mLocked.spots.size(); i++) { - delete mLocked.spots.itemAt(i); - } - mLocked.spots.clear(); - mLocked.recycledSprites.clear(); -} - -bool PointerController::getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - AutoMutex _l(mLock); - - return getBoundsLocked(outMinX, outMinY, outMaxX, outMaxY); -} - -bool PointerController::getBoundsLocked(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const { - if (mLocked.displayWidth <= 0 || mLocked.displayHeight <= 0) { - return false; - } - - *outMinX = 0; - *outMinY = 0; - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - case DISPLAY_ORIENTATION_270: - *outMaxX = mLocked.displayHeight - 1; - *outMaxY = mLocked.displayWidth - 1; - break; - default: - *outMaxX = mLocked.displayWidth - 1; - *outMaxY = mLocked.displayHeight - 1; - break; - } - return true; -} - -void PointerController::move(float deltaX, float deltaY) { -#if DEBUG_POINTER_UPDATES - ALOGD("Move pointer by deltaX=%0.3f, deltaY=%0.3f", deltaX, deltaY); -#endif - if (deltaX == 0.0f && deltaY == 0.0f) { - return; - } - - AutoMutex _l(mLock); - - setPositionLocked(mLocked.pointerX + deltaX, mLocked.pointerY + deltaY); -} - -void PointerController::setButtonState(int32_t buttonState) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set button state 0x%08x", buttonState); -#endif - AutoMutex _l(mLock); - - if (mLocked.buttonState != buttonState) { - mLocked.buttonState = buttonState; - } -} - -int32_t PointerController::getButtonState() const { - AutoMutex _l(mLock); - - return mLocked.buttonState; -} - -void PointerController::setPosition(float x, float y) { -#if DEBUG_POINTER_UPDATES - ALOGD("Set pointer position to x=%0.3f, y=%0.3f", x, y); -#endif - AutoMutex _l(mLock); - - setPositionLocked(x, y); -} - -void PointerController::setPositionLocked(float x, float y) { - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - if (x <= minX) { - mLocked.pointerX = minX; - } else if (x >= maxX) { - mLocked.pointerX = maxX; - } else { - mLocked.pointerX = x; - } - if (y <= minY) { - mLocked.pointerY = minY; - } else if (y >= maxY) { - mLocked.pointerY = maxY; - } else { - mLocked.pointerY = y; - } - updatePointerLocked(); - } -} - -void PointerController::getPosition(float* outX, float* outY) const { - AutoMutex _l(mLock); - - *outX = mLocked.pointerX; - *outY = mLocked.pointerY; -} - -void PointerController::fade(Transition transition) { - AutoMutex _l(mLock); - - // Remove the inactivity timeout, since we are fading now. - removeInactivityTimeoutLocked(); - - // Start fading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 0.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = -1; - startAnimationLocked(); - } -} - -void PointerController::unfade(Transition transition) { - AutoMutex _l(mLock); - - // Always reset the inactivity timer. - resetInactivityTimeoutLocked(); - - // Start unfading. - if (transition == TRANSITION_IMMEDIATE) { - mLocked.pointerFadeDirection = 0; - mLocked.pointerAlpha = 1.0f; - updatePointerLocked(); - } else { - mLocked.pointerFadeDirection = 1; - startAnimationLocked(); - } -} - -void PointerController::setPresentation(Presentation presentation) { - AutoMutex _l(mLock); - - if (mLocked.presentation != presentation) { - mLocked.presentation = presentation; - mLocked.presentationChanged = true; - - if (presentation != PRESENTATION_SPOT) { - fadeOutAndReleaseAllSpotsLocked(); - } - - updatePointerLocked(); - } -} - -void PointerController::setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits) { -#if DEBUG_POINTER_UPDATES - ALOGD("setSpots: idBits=%08x", spotIdBits.value); - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.firstMarkedBit(); - idBits.clearBit(id); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - ALOGD(" spot %d: position=(%0.3f, %0.3f), pressure=%0.3f", id, - c.getAxisValue(AMOTION_EVENT_AXIS_X), - c.getAxisValue(AMOTION_EVENT_AXIS_Y), - c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE)); - } -#endif - - AutoMutex _l(mLock); - - mSpriteController->openTransaction(); - - // Add or move spots for fingers that are down. - for (BitSet32 idBits(spotIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const PointerCoords& c = spotCoords[spotIdToIndex[id]]; - const SpriteIcon& icon = c.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE) > 0 - ? mResources.spotTouch : mResources.spotHover; - float x = c.getAxisValue(AMOTION_EVENT_AXIS_X); - float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y); - - Spot* spot = getSpotLocked(id); - if (!spot) { - spot = createAndAddSpotLocked(id); - } - - spot->updateSprite(&icon, x, y); - } - - // Remove spots for fingers that went up. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id != Spot::INVALID_ID - && !spotIdBits.hasBit(spot->id)) { - fadeOutAndReleaseSpotLocked(spot); - } - } - - mSpriteController->closeTransaction(); -} - -void PointerController::clearSpots() { -#if DEBUG_POINTER_UPDATES - ALOGD("clearSpots"); -#endif - - AutoMutex _l(mLock); - - fadeOutAndReleaseAllSpotsLocked(); -} - -void PointerController::setInactivityTimeout(InactivityTimeout inactivityTimeout) { - AutoMutex _l(mLock); - - if (mLocked.inactivityTimeout != inactivityTimeout) { - mLocked.inactivityTimeout = inactivityTimeout; - resetInactivityTimeoutLocked(); - } -} - -void PointerController::setDisplayViewport(int32_t width, int32_t height, int32_t orientation) { - AutoMutex _l(mLock); - - // Adjust to use the display's unrotated coordinate frame. - if (orientation == DISPLAY_ORIENTATION_90 - || orientation == DISPLAY_ORIENTATION_270) { - int32_t temp = height; - height = width; - width = temp; - } - - if (mLocked.displayWidth != width || mLocked.displayHeight != height) { - mLocked.displayWidth = width; - mLocked.displayHeight = height; - - float minX, minY, maxX, maxY; - if (getBoundsLocked(&minX, &minY, &maxX, &maxY)) { - mLocked.pointerX = (minX + maxX) * 0.5f; - mLocked.pointerY = (minY + maxY) * 0.5f; - } else { - mLocked.pointerX = 0; - mLocked.pointerY = 0; - } - - fadeOutAndReleaseAllSpotsLocked(); - } - - if (mLocked.displayOrientation != orientation) { - // Apply offsets to convert from the pixel top-left corner position to the pixel center. - // This creates an invariant frame of reference that we can easily rotate when - // taking into account that the pointer may be located at fractional pixel offsets. - float x = mLocked.pointerX + 0.5f; - float y = mLocked.pointerY + 0.5f; - float temp; - - // Undo the previous rotation. - switch (mLocked.displayOrientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = mLocked.displayWidth - y; - y = temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = y; - y = mLocked.displayHeight - temp; - break; - } - - // Perform the new rotation. - switch (orientation) { - case DISPLAY_ORIENTATION_90: - temp = x; - x = y; - y = mLocked.displayWidth - temp; - break; - case DISPLAY_ORIENTATION_180: - x = mLocked.displayWidth - x; - y = mLocked.displayHeight - y; - break; - case DISPLAY_ORIENTATION_270: - temp = x; - x = mLocked.displayHeight - y; - y = temp; - break; - } - - // Apply offsets to convert from the pixel center to the pixel top-left corner position - // and save the results. - mLocked.pointerX = x - 0.5f; - mLocked.pointerY = y - 0.5f; - mLocked.displayOrientation = orientation; - } - - updatePointerLocked(); -} - -void PointerController::setPointerIcon(const SpriteIcon& icon) { - AutoMutex _l(mLock); - - mLocked.pointerIcon = icon.copy(); - mLocked.pointerIconChanged = true; - - updatePointerLocked(); -} - -void PointerController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_ANIMATE: - doAnimate(); - break; - case MSG_INACTIVITY_TIMEOUT: - doInactivityTimeout(); - break; - } -} - -void PointerController::doAnimate() { - AutoMutex _l(mLock); - - bool keepAnimating = false; - mLocked.animationPending = false; - nsecs_t frameDelay = systemTime(SYSTEM_TIME_MONOTONIC) - mLocked.animationTime; - - // Animate pointer fade. - if (mLocked.pointerFadeDirection < 0) { - mLocked.pointerAlpha -= float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha <= 0.0f) { - mLocked.pointerAlpha = 0.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } else if (mLocked.pointerFadeDirection > 0) { - mLocked.pointerAlpha += float(frameDelay) / POINTER_FADE_DURATION; - if (mLocked.pointerAlpha >= 1.0f) { - mLocked.pointerAlpha = 1.0f; - mLocked.pointerFadeDirection = 0; - } else { - keepAnimating = true; - } - updatePointerLocked(); - } - - // Animate spots that are fading out and being removed. - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - spot->alpha -= float(frameDelay) / SPOT_FADE_DURATION; - if (spot->alpha <= 0) { - mLocked.spots.removeAt(i--); - releaseSpotLocked(spot); - } else { - spot->sprite->setAlpha(spot->alpha); - keepAnimating = true; - } - } - } - - if (keepAnimating) { - startAnimationLocked(); - } -} - -void PointerController::doInactivityTimeout() { - fade(TRANSITION_GRADUAL); -} - -void PointerController::startAnimationLocked() { - if (!mLocked.animationPending) { - mLocked.animationPending = true; - mLocked.animationTime = systemTime(SYSTEM_TIME_MONOTONIC); - mLooper->sendMessageDelayed(ANIMATION_FRAME_INTERVAL, mHandler, Message(MSG_ANIMATE)); - } -} - -void PointerController::resetInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); - - nsecs_t timeout = mLocked.inactivityTimeout == INACTIVITY_TIMEOUT_SHORT - ? INACTIVITY_TIMEOUT_DELAY_TIME_SHORT : INACTIVITY_TIMEOUT_DELAY_TIME_NORMAL; - mLooper->sendMessageDelayed(timeout, mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::removeInactivityTimeoutLocked() { - mLooper->removeMessages(mHandler, MSG_INACTIVITY_TIMEOUT); -} - -void PointerController::updatePointerLocked() { - mSpriteController->openTransaction(); - - mLocked.pointerSprite->setLayer(Sprite::BASE_LAYER_POINTER); - mLocked.pointerSprite->setPosition(mLocked.pointerX, mLocked.pointerY); - - if (mLocked.pointerAlpha > 0) { - mLocked.pointerSprite->setAlpha(mLocked.pointerAlpha); - mLocked.pointerSprite->setVisible(true); - } else { - mLocked.pointerSprite->setVisible(false); - } - - if (mLocked.pointerIconChanged || mLocked.presentationChanged) { - mLocked.pointerSprite->setIcon(mLocked.presentation == PRESENTATION_POINTER - ? mLocked.pointerIcon : mResources.spotAnchor); - mLocked.pointerIconChanged = false; - mLocked.presentationChanged = false; - } - - mSpriteController->closeTransaction(); -} - -PointerController::Spot* PointerController::getSpotLocked(uint32_t id) { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == id) { - return spot; - } - } - return NULL; -} - -PointerController::Spot* PointerController::createAndAddSpotLocked(uint32_t id) { - // Remove spots until we have fewer than MAX_SPOTS remaining. - while (mLocked.spots.size() >= MAX_SPOTS) { - Spot* spot = removeFirstFadingSpotLocked(); - if (!spot) { - spot = mLocked.spots.itemAt(0); - mLocked.spots.removeAt(0); - } - releaseSpotLocked(spot); - } - - // Obtain a sprite from the recycled pool. - sp sprite; - if (! mLocked.recycledSprites.isEmpty()) { - sprite = mLocked.recycledSprites.top(); - mLocked.recycledSprites.pop(); - } else { - sprite = mSpriteController->createSprite(); - } - - // Return the new spot. - Spot* spot = new Spot(id, sprite); - mLocked.spots.push(spot); - return spot; -} - -PointerController::Spot* PointerController::removeFirstFadingSpotLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - if (spot->id == Spot::INVALID_ID) { - mLocked.spots.removeAt(i); - return spot; - } - } - return NULL; -} - -void PointerController::releaseSpotLocked(Spot* spot) { - spot->sprite->clearIcon(); - - if (mLocked.recycledSprites.size() < MAX_RECYCLED_SPRITES) { - mLocked.recycledSprites.push(spot->sprite); - } - - delete spot; -} - -void PointerController::fadeOutAndReleaseSpotLocked(Spot* spot) { - if (spot->id != Spot::INVALID_ID) { - spot->id = Spot::INVALID_ID; - startAnimationLocked(); - } -} - -void PointerController::fadeOutAndReleaseAllSpotsLocked() { - for (size_t i = 0; i < mLocked.spots.size(); i++) { - Spot* spot = mLocked.spots.itemAt(i); - fadeOutAndReleaseSpotLocked(spot); - } -} - -void PointerController::loadResources() { - mPolicy->loadPointerResources(&mResources); -} - - -// --- PointerController::Spot --- - -void PointerController::Spot::updateSprite(const SpriteIcon* icon, float x, float y) { - sprite->setLayer(Sprite::BASE_LAYER_SPOT + id); - sprite->setAlpha(alpha); - sprite->setTransformationMatrix(SpriteTransformationMatrix(scale, 0.0f, 0.0f, scale)); - sprite->setPosition(x, y); - - this->x = x; - this->y = y; - - if (icon != lastIcon) { - lastIcon = icon; - if (icon) { - sprite->setIcon(*icon); - sprite->setVisible(true); - } else { - sprite->setVisible(false); - } - } -} - -} // namespace android diff --git a/widget/gonk/libui/PointerController.h b/widget/gonk/libui/PointerController.h deleted file mode 100644 index eb48d9a1f..000000000 --- a/widget/gonk/libui/PointerController.h +++ /dev/null @@ -1,266 +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. - */ - -#ifndef _UI_POINTER_CONTROLLER_H -#define _UI_POINTER_CONTROLLER_H - -#include "SpriteController.h" - -#include -#include "Input.h" -#include -#include -#include -#include - -#include - -namespace android { - -/** - * Interface for tracking a mouse / touch pad pointer and touch pad spots. - * - * The spots are sprites on screen that visually represent the positions of - * fingers - * - * The pointer controller is responsible for providing synchronization and for tracking - * display orientation changes if needed. - */ -class PointerControllerInterface : public virtual RefBase { -protected: - PointerControllerInterface() { } - virtual ~PointerControllerInterface() { } - -public: - /* Gets the bounds of the region that the pointer can traverse. - * Returns true if the bounds are available. */ - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const = 0; - - /* Move the pointer. */ - virtual void move(float deltaX, float deltaY) = 0; - - /* Sets a mask that indicates which buttons are pressed. */ - virtual void setButtonState(int32_t buttonState) = 0; - - /* Gets a mask that indicates which buttons are pressed. */ - virtual int32_t getButtonState() const = 0; - - /* Sets the absolute location of the pointer. */ - virtual void setPosition(float x, float y) = 0; - - /* Gets the absolute location of the pointer. */ - virtual void getPosition(float* outX, float* outY) const = 0; - - enum Transition { - // Fade/unfade immediately. - TRANSITION_IMMEDIATE, - // Fade/unfade gradually. - TRANSITION_GRADUAL, - }; - - /* Fades the pointer out now. */ - virtual void fade(Transition transition) = 0; - - /* Makes the pointer visible if it has faded out. - * The pointer never unfades itself automatically. This method must be called - * by the client whenever the pointer is moved or a button is pressed and it - * wants to ensure that the pointer becomes visible again. */ - virtual void unfade(Transition transition) = 0; - - enum Presentation { - // Show the mouse pointer. - PRESENTATION_POINTER, - // Show spots and a spot anchor in place of the mouse pointer. - PRESENTATION_SPOT, - }; - - /* Sets the mode of the pointer controller. */ - virtual void setPresentation(Presentation presentation) = 0; - - /* Sets the spots for the current gesture. - * The spots are not subject to the inactivity timeout like the pointer - * itself it since they are expected to remain visible for so long as - * the fingers are on the touch pad. - * - * The values of the AMOTION_EVENT_AXIS_PRESSURE axis is significant. - * For spotCoords, pressure != 0 indicates that the spot's location is being - * pressed (not hovering). - */ - virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits) = 0; - - /* Removes all spots. */ - virtual void clearSpots() = 0; -}; - - -/* - * Pointer resources. - */ -struct PointerResources { - SpriteIcon spotHover; - SpriteIcon spotTouch; - SpriteIcon spotAnchor; -}; - - -/* - * Pointer controller policy interface. - * - * The pointer controller policy is used by the pointer controller to interact with - * the Window Manager and other system components. - * - * The actual implementation is partially supported by callbacks into the DVM - * via JNI. This interface is also mocked in the unit tests. - */ -class PointerControllerPolicyInterface : public virtual RefBase { -protected: - PointerControllerPolicyInterface() { } - virtual ~PointerControllerPolicyInterface() { } - -public: - virtual void loadPointerResources(PointerResources* outResources) = 0; -}; - - -/* - * Tracks pointer movements and draws the pointer sprite to a surface. - * - * Handles pointer acceleration and animation. - */ -class PointerController : public PointerControllerInterface, public MessageHandler { -protected: - virtual ~PointerController(); - -public: - enum InactivityTimeout { - INACTIVITY_TIMEOUT_NORMAL = 0, - INACTIVITY_TIMEOUT_SHORT = 1, - }; - - PointerController(const sp& policy, - const sp& looper, const sp& spriteController); - - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; - virtual void move(float deltaX, float deltaY); - virtual void setButtonState(int32_t buttonState); - virtual int32_t getButtonState() const; - virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; - virtual void fade(Transition transition); - virtual void unfade(Transition transition); - - virtual void setPresentation(Presentation presentation); - virtual void setSpots(const PointerCoords* spotCoords, - const uint32_t* spotIdToIndex, BitSet32 spotIdBits); - virtual void clearSpots(); - - void setDisplayViewport(int32_t width, int32_t height, int32_t orientation); - void setPointerIcon(const SpriteIcon& icon); - void setInactivityTimeout(InactivityTimeout inactivityTimeout); - -private: - static const size_t MAX_RECYCLED_SPRITES = 12; - static const size_t MAX_SPOTS = 12; - - enum { - MSG_ANIMATE, - MSG_INACTIVITY_TIMEOUT, - }; - - struct Spot { - static const uint32_t INVALID_ID = 0xffffffff; - - uint32_t id; - sp sprite; - float alpha; - float scale; - float x, y; - - inline Spot(uint32_t id, const sp& sprite) - : id(id), sprite(sprite), alpha(1.0f), scale(1.0f), - x(0.0f), y(0.0f), lastIcon(NULL) { } - - void updateSprite(const SpriteIcon* icon, float x, float y); - - private: - const SpriteIcon* lastIcon; - }; - - mutable Mutex mLock; - - sp mPolicy; - sp mLooper; - sp mSpriteController; - sp mHandler; - - PointerResources mResources; - - struct Locked { - bool animationPending; - nsecs_t animationTime; - - int32_t displayWidth; - int32_t displayHeight; - int32_t displayOrientation; - - InactivityTimeout inactivityTimeout; - - Presentation presentation; - bool presentationChanged; - - int32_t pointerFadeDirection; - float pointerX; - float pointerY; - float pointerAlpha; - sp pointerSprite; - SpriteIcon pointerIcon; - bool pointerIconChanged; - - int32_t buttonState; - - Vector spots; - Vector > recycledSprites; - } mLocked; - - bool getBoundsLocked(float* outMinX, float* outMinY, float* outMaxX, float* outMaxY) const; - void setPositionLocked(float x, float y); - - void handleMessage(const Message& message); - void doAnimate(); - void doInactivityTimeout(); - - void startAnimationLocked(); - - void resetInactivityTimeoutLocked(); - void removeInactivityTimeoutLocked(); - void updatePointerLocked(); - - Spot* getSpotLocked(uint32_t id); - Spot* createAndAddSpotLocked(uint32_t id); - Spot* removeFirstFadingSpotLocked(); - void releaseSpotLocked(Spot* spot); - void fadeOutAndReleaseSpotLocked(Spot* spot); - void fadeOutAndReleaseAllSpotsLocked(); - - void loadResources(); -}; - -} // namespace android - -#endif // _UI_POINTER_CONTROLLER_H diff --git a/widget/gonk/libui/PowerManager.h b/widget/gonk/libui/PowerManager.h deleted file mode 100644 index ba98db07c..000000000 --- a/widget/gonk/libui/PowerManager.h +++ /dev/null @@ -1,33 +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. - */ - -#ifndef _ANDROIDFW_POWER_MANAGER_H -#define _ANDROIDFW_POWER_MANAGER_H - - -namespace android { - -enum { - USER_ACTIVITY_EVENT_OTHER = 0, - USER_ACTIVITY_EVENT_BUTTON = 1, - USER_ACTIVITY_EVENT_TOUCH = 2, - - USER_ACTIVITY_EVENT_LAST = USER_ACTIVITY_EVENT_TOUCH, // Last valid event code. -}; - -} // namespace android - -#endif // _ANDROIDFW_POWER_MANAGER_H diff --git a/widget/gonk/libui/SpriteController.cpp b/widget/gonk/libui/SpriteController.cpp deleted file mode 100644 index 8677476b1..000000000 --- a/widget/gonk/libui/SpriteController.cpp +++ /dev/null @@ -1,515 +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. - */ - -#define LOG_TAG "Sprites" - -//#define LOG_NDEBUG 0 - -#include "SpriteController.h" - -#include "cutils_log.h" -#include -#ifdef HAVE_ANDROID_OS -#include -#endif - -#include -#include -#include -#include -#include -#include - -namespace android { - -// --- SpriteController --- - -SpriteController::SpriteController(const sp& looper, int32_t overlayLayer) : - mLooper(looper), mOverlayLayer(overlayLayer) { -#ifdef HAVE_ANDROID_OS - mHandler = new WeakMessageHandler(this); -#endif - - mLocked.transactionNestingCount = 0; - mLocked.deferredSpriteUpdate = false; -} - -SpriteController::~SpriteController() { -#ifdef HAVE_ANDROID_OS - mLooper->removeMessages(mHandler); - - if (mSurfaceComposerClient != NULL) { - mSurfaceComposerClient->dispose(); - mSurfaceComposerClient.clear(); - } -#endif -} - -sp SpriteController::createSprite() { - return new SpriteImpl(this); -} - -void SpriteController::openTransaction() { - AutoMutex _l(mLock); - - mLocked.transactionNestingCount += 1; -} - -void SpriteController::closeTransaction() { - AutoMutex _l(mLock); - - LOG_ALWAYS_FATAL_IF(mLocked.transactionNestingCount == 0, - "Sprite closeTransaction() called but there is no open sprite transaction"); - - mLocked.transactionNestingCount -= 1; - if (mLocked.transactionNestingCount == 0 && mLocked.deferredSpriteUpdate) { - mLocked.deferredSpriteUpdate = false; -#ifdef HAVE_ANDROID_OS - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); -#endif - } -} - -void SpriteController::invalidateSpriteLocked(const sp& sprite) { - bool wasEmpty = mLocked.invalidatedSprites.isEmpty(); - mLocked.invalidatedSprites.push(sprite); - if (wasEmpty) { - if (mLocked.transactionNestingCount != 0) { - mLocked.deferredSpriteUpdate = true; - } else { -#ifdef HAVE_ANDROID_OS - mLooper->sendMessage(mHandler, Message(MSG_UPDATE_SPRITES)); -#endif - } - } -} - -#ifdef HAVE_ANDROID_OS -void SpriteController::disposeSurfaceLocked(const sp& surfaceControl) { - bool wasEmpty = mLocked.disposedSurfaces.isEmpty(); - mLocked.disposedSurfaces.push(surfaceControl); - if (wasEmpty) { - mLooper->sendMessage(mHandler, Message(MSG_DISPOSE_SURFACES)); - } -} - -void SpriteController::handleMessage(const Message& message) { - switch (message.what) { - case MSG_UPDATE_SPRITES: - doUpdateSprites(); - break; - case MSG_DISPOSE_SURFACES: - doDisposeSurfaces(); - break; - } -} -#endif - -void SpriteController::doUpdateSprites() { - // Collect information about sprite updates. - // Each sprite update record includes a reference to its associated sprite so we can - // be certain the sprites will not be deleted while this function runs. Sprites - // may invalidate themselves again during this time but we will handle those changes - // in the next iteration. - Vector updates; - size_t numSprites; - { // acquire lock - AutoMutex _l(mLock); - - numSprites = mLocked.invalidatedSprites.size(); - for (size_t i = 0; i < numSprites; i++) { - const sp& sprite = mLocked.invalidatedSprites.itemAt(i); - - updates.push(SpriteUpdate(sprite, sprite->getStateLocked())); - sprite->resetDirtyLocked(); - } - mLocked.invalidatedSprites.clear(); - } // release lock - - // Create missing surfaces. - bool surfaceChanged = false; -#ifdef HAVE_ANDROID_OS - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - if (update.state.surfaceControl == NULL && update.state.wantSurfaceVisible()) { - update.state.surfaceWidth = update.state.icon.bitmap.width(); - update.state.surfaceHeight = update.state.icon.bitmap.height(); - update.state.surfaceDrawn = false; - update.state.surfaceVisible = false; - update.state.surfaceControl = obtainSurface( - update.state.surfaceWidth, update.state.surfaceHeight); - if (update.state.surfaceControl != NULL) { - update.surfaceChanged = surfaceChanged = true; - } - } - } -#endif - - // Resize sprites if needed, inside a global transaction. -#ifdef HAVE_ANDROID_OS - bool haveGlobalTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - if (update.state.surfaceControl != NULL && update.state.wantSurfaceVisible()) { - int32_t desiredWidth = update.state.icon.bitmap.width(); - int32_t desiredHeight = update.state.icon.bitmap.height(); - if (update.state.surfaceWidth < desiredWidth - || update.state.surfaceHeight < desiredHeight) { - if (!haveGlobalTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveGlobalTransaction = true; - } - - status_t status = update.state.surfaceControl->setSize(desiredWidth, desiredHeight); - if (status) { - ALOGE("Error %d resizing sprite surface from %dx%d to %dx%d", - status, update.state.surfaceWidth, update.state.surfaceHeight, - desiredWidth, desiredHeight); - } else { - update.state.surfaceWidth = desiredWidth; - update.state.surfaceHeight = desiredHeight; - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - - if (update.state.surfaceVisible) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface after resize.", status); - } else { - update.state.surfaceVisible = false; - } - } - } - } - } - } -#endif -#ifdef HAVE_ANDROID_OS - if (haveGlobalTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } -#endif - - // Redraw sprites if needed. - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - - if ((update.state.dirty & DIRTY_BITMAP) && update.state.surfaceDrawn) { - update.state.surfaceDrawn = false; - update.surfaceChanged = surfaceChanged = true; - } - -#ifdef HAVE_ANDROID_OS - if (update.state.surfaceControl != NULL && !update.state.surfaceDrawn - && update.state.wantSurfaceVisible()) { - sp surface = update.state.surfaceControl->getSurface(); - ANativeWindow_Buffer outBuffer; - status_t status = surface->lock(&outBuffer, NULL); - if (status) { - ALOGE("Error %d locking sprite surface before drawing.", status); - } else { - SkBitmap surfaceBitmap; - ssize_t bpr = outBuffer.stride * bytesPerPixel(outBuffer.format); - surfaceBitmap.setConfig(SkBitmap::kARGB_8888_Config, - outBuffer.width, outBuffer.height, bpr); - surfaceBitmap.setPixels(outBuffer.bits); - - SkCanvas surfaceCanvas(surfaceBitmap); - - SkPaint paint; - paint.setXfermodeMode(SkXfermode::kSrc_Mode); - surfaceCanvas.drawBitmap(update.state.icon.bitmap, 0, 0, &paint); - - if (outBuffer.width > uint32_t(update.state.icon.bitmap.width())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(update.state.icon.bitmap.width(), 0, - outBuffer.width, update.state.icon.bitmap.height(), paint); - } - if (outBuffer.height > uint32_t(update.state.icon.bitmap.height())) { - paint.setColor(0); // transparent fill color - surfaceCanvas.drawRectCoords(0, update.state.icon.bitmap.height(), - outBuffer.width, outBuffer.height, paint); - } - - status = surface->unlockAndPost(); - if (status) { - ALOGE("Error %d unlocking and posting sprite surface after drawing.", status); - } else { - update.state.surfaceDrawn = true; - update.surfaceChanged = surfaceChanged = true; - } - } - } -#endif - } - -#ifdef HAVE_ANDROID_OS - // Set sprite surface properties and make them visible. - bool haveTransaction = false; - for (size_t i = 0; i < numSprites; i++) { - SpriteUpdate& update = updates.editItemAt(i); - bool wantSurfaceVisibleAndDrawn = update.state.wantSurfaceVisible() - && update.state.surfaceDrawn; - bool becomingVisible = wantSurfaceVisibleAndDrawn && !update.state.surfaceVisible; - bool becomingHidden = !wantSurfaceVisibleAndDrawn && update.state.surfaceVisible; - if (update.state.surfaceControl != NULL && (becomingVisible || becomingHidden - || (wantSurfaceVisibleAndDrawn && (update.state.dirty & (DIRTY_ALPHA - | DIRTY_POSITION | DIRTY_TRANSFORMATION_MATRIX | DIRTY_LAYER - | DIRTY_VISIBILITY | DIRTY_HOTSPOT))))) { - status_t status; - if (!haveTransaction) { - SurfaceComposerClient::openGlobalTransaction(); - haveTransaction = true; - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_ALPHA))) { - status = update.state.surfaceControl->setAlpha(update.state.alpha); - if (status) { - ALOGE("Error %d setting sprite surface alpha.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & (DIRTY_POSITION - | DIRTY_HOTSPOT)))) { - status = update.state.surfaceControl->setPosition( - update.state.positionX - update.state.icon.hotSpotX, - update.state.positionY - update.state.icon.hotSpotY); - if (status) { - ALOGE("Error %d setting sprite surface position.", status); - } - } - - if (wantSurfaceVisibleAndDrawn - && (becomingVisible - || (update.state.dirty & DIRTY_TRANSFORMATION_MATRIX))) { - status = update.state.surfaceControl->setMatrix( - update.state.transformationMatrix.dsdx, - update.state.transformationMatrix.dtdx, - update.state.transformationMatrix.dsdy, - update.state.transformationMatrix.dtdy); - if (status) { - ALOGE("Error %d setting sprite surface transformation matrix.", status); - } - } - - int32_t surfaceLayer = mOverlayLayer + update.state.layer; - if (wantSurfaceVisibleAndDrawn - && (becomingVisible || (update.state.dirty & DIRTY_LAYER))) { - status = update.state.surfaceControl->setLayer(surfaceLayer); - if (status) { - ALOGE("Error %d setting sprite surface layer.", status); - } - } - - if (becomingVisible) { - status = update.state.surfaceControl->show(); - if (status) { - ALOGE("Error %d showing sprite surface.", status); - } else { - update.state.surfaceVisible = true; - update.surfaceChanged = surfaceChanged = true; - } - } else if (becomingHidden) { - status = update.state.surfaceControl->hide(); - if (status) { - ALOGE("Error %d hiding sprite surface.", status); - } else { - update.state.surfaceVisible = false; - update.surfaceChanged = surfaceChanged = true; - } - } - } - } -#endif - -#ifdef HAVE_ANDROID_OS - if (haveTransaction) { - SurfaceComposerClient::closeGlobalTransaction(); - } -#endif - -#ifdef HAVE_ANDROID_OS - // If any surfaces were changed, write back the new surface properties to the sprites. - if (surfaceChanged) { // acquire lock - AutoMutex _l(mLock); - - for (size_t i = 0; i < numSprites; i++) { - const SpriteUpdate& update = updates.itemAt(i); - - if (update.surfaceChanged) { - update.sprite->setSurfaceLocked(update.state.surfaceControl, - update.state.surfaceWidth, update.state.surfaceHeight, - update.state.surfaceDrawn, update.state.surfaceVisible); - } - } - } // release lock -#endif - - // Clear the sprite update vector outside the lock. It is very important that - // we do not clear sprite references inside the lock since we could be releasing - // the last remaining reference to the sprite here which would result in the - // sprite being deleted and the lock being reacquired by the sprite destructor - // while already held. - updates.clear(); -} - -void SpriteController::doDisposeSurfaces() { -#ifdef HAVE_ANDROID_OS - // Collect disposed surfaces. - Vector > disposedSurfaces; - { // acquire lock - AutoMutex _l(mLock); - - disposedSurfaces = mLocked.disposedSurfaces; - mLocked.disposedSurfaces.clear(); - } // release lock - - // Release the last reference to each surface outside of the lock. - // We don't want the surfaces to be deleted while we are holding our lock. - disposedSurfaces.clear(); -#endif -} - -void SpriteController::ensureSurfaceComposerClient() { -#ifdef HAVE_ANDROID_OS - if (mSurfaceComposerClient == NULL) { - mSurfaceComposerClient = new SurfaceComposerClient(); - } -#endif -} - -#ifdef HAVE_ANDROID_OS -sp SpriteController::obtainSurface(int32_t width, int32_t height) { - ensureSurfaceComposerClient(); - - sp surfaceControl = mSurfaceComposerClient->createSurface( - String8("Sprite"), width, height, PIXEL_FORMAT_RGBA_8888, - ISurfaceComposerClient::eHidden); - if (surfaceControl == NULL || !surfaceControl->isValid()) { - ALOGE("Error creating sprite surface."); - return NULL; - } - return surfaceControl; -} -#endif - - -// --- SpriteController::SpriteImpl --- - -SpriteController::SpriteImpl::SpriteImpl(const sp controller) : - mController(controller) { -} - -SpriteController::SpriteImpl::~SpriteImpl() { - AutoMutex _m(mController->mLock); - -#ifdef HAVE_ANDROID_OS - // Let the controller take care of deleting the last reference to sprite - // surfaces so that we do not block the caller on an IPC here. - if (mLocked.state.surfaceControl != NULL) { - mController->disposeSurfaceLocked(mLocked.state.surfaceControl); - mLocked.state.surfaceControl.clear(); - } -#endif -} - -void SpriteController::SpriteImpl::setIcon(const SpriteIcon& icon) { - AutoMutex _l(mController->mLock); - -#ifdef HAVE_ANDROID_OS - uint32_t dirty; - if (icon.isValid()) { - icon.bitmap.copyTo(&mLocked.state.icon.bitmap, SkBitmap::kARGB_8888_Config); - - if (!mLocked.state.icon.isValid() - || mLocked.state.icon.hotSpotX != icon.hotSpotX - || mLocked.state.icon.hotSpotY != icon.hotSpotY) { - mLocked.state.icon.hotSpotX = icon.hotSpotX; - mLocked.state.icon.hotSpotY = icon.hotSpotY; - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - dirty = DIRTY_BITMAP; - } - } else if (mLocked.state.icon.isValid()) { - mLocked.state.icon.bitmap.reset(); - dirty = DIRTY_BITMAP | DIRTY_HOTSPOT; - } else { - return; // setting to invalid icon and already invalid so nothing to do - } - - invalidateLocked(dirty); -#endif -} - -void SpriteController::SpriteImpl::setVisible(bool visible) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.visible != visible) { - mLocked.state.visible = visible; - invalidateLocked(DIRTY_VISIBILITY); - } -} - -void SpriteController::SpriteImpl::setPosition(float x, float y) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.positionX != x || mLocked.state.positionY != y) { - mLocked.state.positionX = x; - mLocked.state.positionY = y; - invalidateLocked(DIRTY_POSITION); - } -} - -void SpriteController::SpriteImpl::setLayer(int32_t layer) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.layer != layer) { - mLocked.state.layer = layer; - invalidateLocked(DIRTY_LAYER); - } -} - -void SpriteController::SpriteImpl::setAlpha(float alpha) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.alpha != alpha) { - mLocked.state.alpha = alpha; - invalidateLocked(DIRTY_ALPHA); - } -} - -void SpriteController::SpriteImpl::setTransformationMatrix( - const SpriteTransformationMatrix& matrix) { - AutoMutex _l(mController->mLock); - - if (mLocked.state.transformationMatrix != matrix) { - mLocked.state.transformationMatrix = matrix; - invalidateLocked(DIRTY_TRANSFORMATION_MATRIX); - } -} - -void SpriteController::SpriteImpl::invalidateLocked(uint32_t dirty) { - bool wasDirty = mLocked.state.dirty; - mLocked.state.dirty |= dirty; - - if (!wasDirty) { - mController->invalidateSpriteLocked(this); - } -} - -} // namespace android diff --git a/widget/gonk/libui/SpriteController.h b/widget/gonk/libui/SpriteController.h deleted file mode 100644 index 4926095ec..000000000 --- a/widget/gonk/libui/SpriteController.h +++ /dev/null @@ -1,319 +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. - */ - -#ifndef _UI_SPRITES_H -#define _UI_SPRITES_H - -#include -#include - -#ifdef HAVE_ANDROID_OS -#include -#endif - -#include - -namespace android { - -/* - * Transformation matrix for a sprite. - */ -struct SpriteTransformationMatrix { - inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { } - inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) : - dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { } - - float dsdx; - float dtdx; - float dsdy; - float dtdy; - - inline bool operator== (const SpriteTransformationMatrix& other) { - return dsdx == other.dsdx - && dtdx == other.dtdx - && dsdy == other.dsdy - && dtdy == other.dtdy; - } - - inline bool operator!= (const SpriteTransformationMatrix& other) { - return !(*this == other); - } -}; - -/* - * Icon that a sprite displays, including its hotspot. - */ -struct SpriteIcon { - inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } -#ifdef HAVE_ANDROID_OS - inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : - bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } - - SkBitmap bitmap; -#endif - float hotSpotX; - float hotSpotY; - - inline SpriteIcon copy() const { -#ifdef HAVE_ANDROID_OS - SkBitmap bitmapCopy; - bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config); - return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); -#else - return SpriteIcon(); -#endif - } - - inline void reset() { -#ifdef HAVE_ANDROID_OS - bitmap.reset(); - hotSpotX = 0; - hotSpotY = 0; -#endif - } - - inline bool isValid() const { -#ifdef HAVE_ANDROID_OS - return !bitmap.isNull() && !bitmap.empty(); -#else - return false; -#endif - } -}; - -/* - * A sprite is a simple graphical object that is displayed on-screen above other layers. - * The basic sprite class is an interface. - * The implementation is provided by the sprite controller. - */ -class Sprite : public RefBase { -protected: - Sprite() { } - virtual ~Sprite() { } - -public: - enum { - // The base layer for pointer sprites. - BASE_LAYER_POINTER = 0, // reserve space for 1 pointer - - // The base layer for spot sprites. - BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots - }; - - /* Sets the bitmap that is drawn by the sprite. - * The sprite retains a copy of the bitmap for subsequent rendering. */ - virtual void setIcon(const SpriteIcon& icon) = 0; - - inline void clearIcon() { - setIcon(SpriteIcon()); - } - - /* Sets whether the sprite is visible. */ - virtual void setVisible(bool visible) = 0; - - /* Sets the sprite position on screen, relative to the sprite's hot spot. */ - virtual void setPosition(float x, float y) = 0; - - /* Sets the layer of the sprite, relative to the system sprite overlay layer. - * Layer 0 is the overlay layer, > 0 appear above this layer. */ - virtual void setLayer(int32_t layer) = 0; - - /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */ - virtual void setAlpha(float alpha) = 0; - - /* Sets the sprite transformation matrix. */ - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0; -}; - -/* - * Displays sprites on the screen. - * - * This interface is used by PointerController and SpotController to draw pointers or - * spot representations of fingers. It is not intended for general purpose use - * by other components. - * - * All sprite position updates and rendering is performed asynchronously. - * - * Clients are responsible for animating sprites by periodically updating their properties. - */ -class SpriteController : public MessageHandler { -protected: - virtual ~SpriteController(); - -public: - SpriteController(const sp& looper, int32_t overlayLayer); - - /* Creates a new sprite, initially invisible. */ - sp createSprite(); - - /* Opens or closes a transaction to perform a batch of sprite updates as part of - * a single operation such as setPosition and setAlpha. It is not necessary to - * open a transaction when updating a single property. - * Calls to openTransaction() nest and must be matched by an equal number - * of calls to closeTransaction(). */ - void openTransaction(); - void closeTransaction(); - -private: - enum { - MSG_UPDATE_SPRITES, - MSG_DISPOSE_SURFACES, - }; - - enum { - DIRTY_BITMAP = 1 << 0, - DIRTY_ALPHA = 1 << 1, - DIRTY_POSITION = 1 << 2, - DIRTY_TRANSFORMATION_MATRIX = 1 << 3, - DIRTY_LAYER = 1 << 4, - DIRTY_VISIBILITY = 1 << 5, - DIRTY_HOTSPOT = 1 << 6, - }; - - /* Describes the state of a sprite. - * This structure is designed so that it can be copied during updates so that - * surfaces can be resized and redrawn without blocking the client by holding a lock - * on the sprites for a long time. - * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ - struct SpriteState { - inline SpriteState() : - dirty(0), visible(false), - positionX(0), positionY(0), layer(0), alpha(1.0f), - surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) { - } - - uint32_t dirty; - - SpriteIcon icon; - bool visible; - float positionX; - float positionY; - int32_t layer; - float alpha; - SpriteTransformationMatrix transformationMatrix; - -#ifdef HAVE_ANDROID_OS - sp surfaceControl; -#endif - int32_t surfaceWidth; - int32_t surfaceHeight; - bool surfaceDrawn; - bool surfaceVisible; - - inline bool wantSurfaceVisible() const { - return visible && alpha > 0.0f && icon.isValid(); - } - }; - - /* Client interface for a sprite. - * Requests acquire a lock on the controller, update local state and request the - * controller to invalidate the sprite. - * The real heavy lifting of creating, resizing and redrawing surfaces happens - * asynchronously with no locks held except in short critical section to copy - * the sprite state before the work and update the sprite surface control afterwards. - */ - class SpriteImpl : public Sprite { - protected: - virtual ~SpriteImpl(); - - public: - SpriteImpl(const sp controller); - - virtual void setIcon(const SpriteIcon& icon); - virtual void setVisible(bool visible); - virtual void setPosition(float x, float y); - virtual void setLayer(int32_t layer); - virtual void setAlpha(float alpha); - virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix); - - inline const SpriteState& getStateLocked() const { - return mLocked.state; - } - - inline void resetDirtyLocked() { - mLocked.state.dirty = 0; - } - -#ifdef HAVE_ANDROID_OS - inline void setSurfaceLocked(const sp& surfaceControl, - int32_t width, int32_t height, bool drawn, bool visible) { - mLocked.state.surfaceControl = surfaceControl; - mLocked.state.surfaceWidth = width; - mLocked.state.surfaceHeight = height; - mLocked.state.surfaceDrawn = drawn; - mLocked.state.surfaceVisible = visible; - } -#endif - - private: - sp mController; - - struct Locked { - SpriteState state; - } mLocked; // guarded by mController->mLock - - void invalidateLocked(uint32_t dirty); - }; - - /* Stores temporary information collected during the sprite update cycle. */ - struct SpriteUpdate { - inline SpriteUpdate() : surfaceChanged(false) { } - inline SpriteUpdate(const sp sprite, const SpriteState& state) : - sprite(sprite), state(state), surfaceChanged(false) { - } - - sp sprite; - SpriteState state; - bool surfaceChanged; - }; - - mutable Mutex mLock; - - sp mLooper; - const int32_t mOverlayLayer; -#ifdef HAVE_ANDROID_OS - sp mHandler; - - sp mSurfaceComposerClient; -#endif - - struct Locked { - Vector > invalidatedSprites; -#ifdef HAVE_ANDROID_OS - Vector > disposedSurfaces; -#endif - uint32_t transactionNestingCount; - bool deferredSpriteUpdate; - } mLocked; // guarded by mLock - - void invalidateSpriteLocked(const sp& sprite); -#ifdef HAVE_ANDROID_OS - void disposeSurfaceLocked(const sp& surfaceControl); - - void handleMessage(const Message& message); -#endif - void doUpdateSprites(); - void doDisposeSurfaces(); - - void ensureSurfaceComposerClient(); -#ifdef HAVE_ANDROID_OS - sp obtainSurface(int32_t width, int32_t height); -#endif -}; - -} // namespace android - -#endif // _UI_SPRITES_H diff --git a/widget/gonk/libui/Tokenizer.cpp b/widget/gonk/libui/Tokenizer.cpp deleted file mode 100644 index 2f585cb4e..000000000 --- a/widget/gonk/libui/Tokenizer.cpp +++ /dev/null @@ -1,175 +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. - */ - -#define LOG_TAG "Tokenizer" -#include "cutils_log.h" - -#include -#include -#include -#include -#include -#include -#include "Tokenizer.h" - -// Enables debug output for the tokenizer. -#define DEBUG_TOKENIZER 0 - - -namespace android { - -static inline bool isDelimiter(char ch, const char* delimiters) { - return strchr(delimiters, ch) != NULL; -} - -Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, - bool ownBuffer, size_t length) : - mFilename(filename), mFileMap(fileMap), - mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length), - mCurrent(buffer), mLineNumber(1) { -} - -Tokenizer::~Tokenizer() { - if (mFileMap) { - mFileMap->release(); - } - if (mOwnBuffer) { - delete[] mBuffer; - } -} - -status_t Tokenizer::open(const String8& filename, Tokenizer** outTokenizer) { - *outTokenizer = NULL; - - int result = NO_ERROR; - int fd = ::open(filename.string(), O_RDONLY); - if (fd < 0) { - result = -errno; - ALOGE("Error opening file '%s', %s.", filename.string(), strerror(errno)); - } else { - struct stat stat; - if (fstat(fd, &stat)) { - result = -errno; - ALOGE("Error getting size of file '%s', %s.", filename.string(), strerror(errno)); - } else { - size_t length = size_t(stat.st_size); - - FileMap* fileMap = new FileMap(); - bool ownBuffer = false; - char* buffer; - if (fileMap->create(NULL, fd, 0, length, true)) { - fileMap->advise(FileMap::SEQUENTIAL); - buffer = static_cast(fileMap->getDataPtr()); - } else { - fileMap->release(); - fileMap = NULL; - - // Fall back to reading into a buffer since we can't mmap files in sysfs. - // The length we obtained from stat is wrong too (it will always be 4096) - // so we must trust that read will read the entire file. - buffer = new char[length]; - ownBuffer = true; - ssize_t nrd = read(fd, buffer, length); - if (nrd < 0) { - result = -errno; - ALOGE("Error reading file '%s', %s.", filename.string(), strerror(errno)); - delete[] buffer; - buffer = NULL; - } else { - length = size_t(nrd); - } - } - - if (!result) { - *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length); - } - } - close(fd); - } - return result; -} - -status_t Tokenizer::fromContents(const String8& filename, - const char* contents, Tokenizer** outTokenizer) { - *outTokenizer = new Tokenizer(filename, NULL, - const_cast(contents), false, strlen(contents)); - return OK; -} - -String8 Tokenizer::getLocation() const { - String8 result; - result.appendFormat("%s:%d", mFilename.string(), mLineNumber); - return result; -} - -String8 Tokenizer::peekRemainderOfLine() const { - const char* end = getEnd(); - const char* eol = mCurrent; - while (eol != end) { - char ch = *eol; - if (ch == '\n') { - break; - } - eol += 1; - } - return String8(mCurrent, eol - mCurrent); -} - -String8 Tokenizer::nextToken(const char* delimiters) { -#if DEBUG_TOKENIZER - ALOGD("nextToken"); -#endif - const char* end = getEnd(); - const char* tokenStart = mCurrent; - while (mCurrent != end) { - char ch = *mCurrent; - if (ch == '\n' || isDelimiter(ch, delimiters)) { - break; - } - mCurrent += 1; - } - return String8(tokenStart, mCurrent - tokenStart); -} - -void Tokenizer::nextLine() { -#if DEBUG_TOKENIZER - ALOGD("nextLine"); -#endif - const char* end = getEnd(); - while (mCurrent != end) { - char ch = *(mCurrent++); - if (ch == '\n') { - mLineNumber += 1; - break; - } - } -} - -void Tokenizer::skipDelimiters(const char* delimiters) { -#if DEBUG_TOKENIZER - ALOGD("skipDelimiters"); -#endif - const char* end = getEnd(); - while (mCurrent != end) { - char ch = *mCurrent; - if (ch == '\n' || !isDelimiter(ch, delimiters)) { - break; - } - mCurrent += 1; - } -} - -} // namespace android diff --git a/widget/gonk/libui/Tokenizer.h b/widget/gonk/libui/Tokenizer.h deleted file mode 100644 index bb25f374c..000000000 --- a/widget/gonk/libui/Tokenizer.h +++ /dev/null @@ -1,136 +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. - */ - -#ifndef _UTILS_TOKENIZER_H -#define _UTILS_TOKENIZER_H - -#include -#include -#include -#include - -namespace android { - -/** - * A simple tokenizer for loading and parsing ASCII text files line by line. - */ -class Tokenizer { - Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, - bool ownBuffer, size_t length); - -public: - ~Tokenizer(); - - /** - * Opens a file and maps it into memory. - * - * Returns NO_ERROR and a tokenizer for the file, if successful. - * Otherwise returns an error and sets outTokenizer to NULL. - */ - static status_t open(const String8& filename, Tokenizer** outTokenizer); - - /** - * Prepares to tokenize the contents of a string. - * - * Returns NO_ERROR and a tokenizer for the string, if successful. - * Otherwise returns an error and sets outTokenizer to NULL. - */ - static status_t fromContents(const String8& filename, - const char* contents, Tokenizer** outTokenizer); - - /** - * Returns true if at the end of the file. - */ - inline bool isEof() const { return mCurrent == getEnd(); } - - /** - * Returns true if at the end of the line or end of the file. - */ - inline bool isEol() const { return isEof() || *mCurrent == '\n'; } - - /** - * Gets the name of the file. - */ - inline String8 getFilename() const { return mFilename; } - - /** - * Gets a 1-based line number index for the current position. - */ - inline int32_t getLineNumber() const { return mLineNumber; } - - /** - * Formats a location string consisting of the filename and current line number. - * Returns a string like "MyFile.txt:33". - */ - String8 getLocation() const; - - /** - * Gets the character at the current position. - * Returns null at end of file. - */ - inline char peekChar() const { return isEof() ? '\0' : *mCurrent; } - - /** - * Gets the remainder of the current line as a string, excluding the newline character. - */ - String8 peekRemainderOfLine() const; - - /** - * Gets the character at the current position and advances past it. - * Returns null at end of file. - */ - inline char nextChar() { return isEof() ? '\0' : *(mCurrent++); } - - /** - * Gets the next token on this line stopping at the specified delimiters - * or the end of the line whichever comes first and advances past it. - * Also stops at embedded nulls. - * Returns the token or an empty string if the current character is a delimiter - * or is at the end of the line. - */ - String8 nextToken(const char* delimiters); - - /** - * Advances to the next line. - * Does nothing if already at the end of the file. - */ - void nextLine(); - - /** - * Skips over the specified delimiters in the line. - * Also skips embedded nulls. - */ - void skipDelimiters(const char* delimiters); - -private: - Tokenizer(const Tokenizer& other); // not copyable - - String8 mFilename; - FileMap* mFileMap; - char* mBuffer; - bool mOwnBuffer; - size_t mLength; - - const char* mCurrent; - int32_t mLineNumber; - - inline const char* getEnd() const { return mBuffer + mLength; } - -}; - -} // namespace android - -#endif // _UTILS_TOKENIZER_H diff --git a/widget/gonk/libui/Trace.h b/widget/gonk/libui/Trace.h deleted file mode 100644 index 24fbfb602..000000000 --- a/widget/gonk/libui/Trace.h +++ /dev/null @@ -1,64 +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. - */ - -#ifndef ANDROID_TRACE_H -#define ANDROID_TRACE_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include "cutils_trace.h" - -// See for more ATRACE_* macros. - -// ATRACE_NAME traces the beginning and end of the current scope. To trace -// the correct start and end times this macro should be declared first in the -// scope body. -#define ATRACE_NAME(name) android::ScopedTrace ___tracer(ATRACE_TAG, name) -// ATRACE_CALL is an ATRACE_NAME that uses the current function name. -#define ATRACE_CALL() ATRACE_NAME(__FUNCTION__) - -namespace android { - -class ScopedTrace { -public: -inline ScopedTrace(uint64_t tag, const char* name) - : mTag(tag) { -#ifdef HAVE_ANDROID_OS - atrace_begin(mTag,name); -#endif -} - -inline ~ScopedTrace() { -#ifdef HAVE_ANDROID_OS - atrace_end(mTag); -#endif -} - -private: - uint64_t mTag; -}; - -}; // namespace android - -#endif // ANDROID_TRACE_H diff --git a/widget/gonk/libui/VelocityControl.cpp b/widget/gonk/libui/VelocityControl.cpp deleted file mode 100644 index 31365a220..000000000 --- a/widget/gonk/libui/VelocityControl.cpp +++ /dev/null @@ -1,110 +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. - */ - -#define LOG_TAG "VelocityControl" -//#define LOG_NDEBUG 0 - -// Log debug messages about acceleration. -#define DEBUG_ACCELERATION 0 - -#include -#include - -#include "VelocityControl.h" -#include -#include - -namespace android { - -// --- VelocityControl --- - -const nsecs_t VelocityControl::STOP_TIME; - -VelocityControl::VelocityControl() { - reset(); -} - -void VelocityControl::setParameters(const VelocityControlParameters& parameters) { - mParameters = parameters; - reset(); -} - -void VelocityControl::reset() { - mLastMovementTime = LLONG_MIN; - mRawPosition.x = 0; - mRawPosition.y = 0; - mVelocityTracker.clear(); -} - -void VelocityControl::move(nsecs_t eventTime, float* deltaX, float* deltaY) { - if ((deltaX && *deltaX) || (deltaY && *deltaY)) { - if (eventTime >= mLastMovementTime + STOP_TIME) { -#if DEBUG_ACCELERATION - ALOGD("VelocityControl: stopped, last movement was %0.3fms ago", - (eventTime - mLastMovementTime) * 0.000001f); -#endif - reset(); - } - - mLastMovementTime = eventTime; - if (deltaX) { - mRawPosition.x += *deltaX; - } - if (deltaY) { - mRawPosition.y += *deltaY; - } - mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition); - - float vx, vy; - float scale = mParameters.scale; - if (mVelocityTracker.getVelocity(0, &vx, &vy)) { - float speed = hypotf(vx, vy) * scale; - if (speed >= mParameters.highThreshold) { - // Apply full acceleration above the high speed threshold. - scale *= mParameters.acceleration; - } else if (speed > mParameters.lowThreshold) { - // Linearly interpolate the acceleration to apply between the low and high - // speed thresholds. - scale *= 1 + (speed - mParameters.lowThreshold) - / (mParameters.highThreshold - mParameters.lowThreshold) - * (mParameters.acceleration - 1); - } - -#if DEBUG_ACCELERATION - ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): " - "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f", - mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, - mParameters.acceleration, - vx, vy, speed, scale / mParameters.scale); -#endif - } else { -#if DEBUG_ACCELERATION - ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): unknown velocity", - mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold, - mParameters.acceleration); -#endif - } - - if (deltaX) { - *deltaX *= scale; - } - if (deltaY) { - *deltaY *= scale; - } - } -} - -} // namespace android diff --git a/widget/gonk/libui/VelocityControl.h b/widget/gonk/libui/VelocityControl.h deleted file mode 100644 index 8a2c695d6..000000000 --- a/widget/gonk/libui/VelocityControl.h +++ /dev/null @@ -1,107 +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. - */ - -#ifndef _ANDROIDFW_VELOCITY_CONTROL_H -#define _ANDROIDFW_VELOCITY_CONTROL_H - -#include "Input.h" -#include "VelocityTracker.h" -#include - -namespace android { - -/* - * Specifies parameters that govern pointer or wheel acceleration. - */ -struct VelocityControlParameters { - // A scale factor that is multiplied with the raw velocity deltas - // prior to applying any other velocity control factors. The scale - // factor should be used to adapt the input device resolution - // (eg. counts per inch) to the output device resolution (eg. pixels per inch). - // - // Must be a positive value. - // Default is 1.0 (no scaling). - float scale; - - // The scaled speed at which acceleration begins to be applied. - // This value establishes the upper bound of a low speed regime for - // small precise motions that are performed without any acceleration. - // - // Must be a non-negative value. - // Default is 0.0 (no low threshold). - float lowThreshold; - - // The scaled speed at which maximum acceleration is applied. - // The difference between highThreshold and lowThreshold controls - // the range of speeds over which the acceleration factor is interpolated. - // The wider the range, the smoother the acceleration. - // - // Must be a non-negative value greater than or equal to lowThreshold. - // Default is 0.0 (no high threshold). - float highThreshold; - - // The acceleration factor. - // When the speed is above the low speed threshold, the velocity will scaled - // by an interpolated value between 1.0 and this amount. - // - // Must be a positive greater than or equal to 1.0. - // Default is 1.0 (no acceleration). - float acceleration; - - VelocityControlParameters() : - scale(1.0f), lowThreshold(0.0f), highThreshold(0.0f), acceleration(1.0f) { - } - - VelocityControlParameters(float scale, float lowThreshold, - float highThreshold, float acceleration) : - scale(scale), lowThreshold(lowThreshold), - highThreshold(highThreshold), acceleration(acceleration) { - } -}; - -/* - * Implements mouse pointer and wheel speed control and acceleration. - */ -class VelocityControl { -public: - VelocityControl(); - - /* Sets the various parameters. */ - void setParameters(const VelocityControlParameters& parameters); - - /* Resets the current movement counters to zero. - * This has the effect of nullifying any acceleration. */ - void reset(); - - /* Translates a raw movement delta into an appropriately - * scaled / accelerated delta based on the current velocity. */ - void move(nsecs_t eventTime, float* deltaX, float* deltaY); - -private: - // If no movements are received within this amount of time, - // we assume the movement has stopped and reset the movement counters. - static const nsecs_t STOP_TIME = 500 * 1000000; // 500 ms - - VelocityControlParameters mParameters; - - nsecs_t mLastMovementTime; - VelocityTracker::Position mRawPosition; - VelocityTracker mVelocityTracker; -}; - -} // namespace android - -#endif // _ANDROIDFW_VELOCITY_CONTROL_H diff --git a/widget/gonk/libui/VelocityTracker.cpp b/widget/gonk/libui/VelocityTracker.cpp deleted file mode 100644 index 11a8bf7fc..000000000 --- a/widget/gonk/libui/VelocityTracker.cpp +++ /dev/null @@ -1,929 +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. - */ - -#define LOG_TAG "VelocityTracker" -//#define LOG_NDEBUG 0 -#include "cutils_log.h" - -// Log debug messages about velocity tracking. -#define DEBUG_VELOCITY 0 - -// Log debug messages about the progress of the algorithm itself. -#define DEBUG_STRATEGY 0 - -#include -#include - -#include "VelocityTracker.h" -#include -#include -#include - -#include - -namespace android { - -// Nanoseconds per milliseconds. -static const nsecs_t NANOS_PER_MS = 1000000; - -// Threshold for determining that a pointer has stopped moving. -// Some input devices do not send ACTION_MOVE events in the case where a pointer has -// stopped. We need to detect this case so that we can accurately predict the -// velocity after the pointer starts moving again. -static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS; - - -static float vectorDot(const float* a, const float* b, uint32_t m) { - float r = 0; - while (m--) { - r += *(a++) * *(b++); - } - return r; -} - -static float vectorNorm(const float* a, uint32_t m) { - float r = 0; - while (m--) { - float t = *(a++); - r += t * t; - } - return sqrtf(r); -} - -#if DEBUG_STRATEGY || DEBUG_VELOCITY -static String8 vectorToString(const float* a, uint32_t m) { - String8 str; - str.append("["); - while (m--) { - str.appendFormat(" %f", *(a++)); - if (m) { - str.append(","); - } - } - str.append(" ]"); - return str; -} - -static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) { - String8 str; - str.append("["); - for (size_t i = 0; i < m; i++) { - if (i) { - str.append(","); - } - str.append(" ["); - for (size_t j = 0; j < n; j++) { - if (j) { - str.append(","); - } - str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]); - } - str.append(" ]"); - } - str.append(" ]"); - return str; -} -#endif - - -// --- VelocityTracker --- - -// The default velocity tracker strategy. -// Although other strategies are available for testing and comparison purposes, -// this is the strategy that applications will actually use. Be very careful -// when adjusting the default strategy because it can dramatically affect -// (often in a bad way) the user experience. -const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2"; - -VelocityTracker::VelocityTracker(const char* strategy) : - mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) { - char value[PROPERTY_VALUE_MAX]; - - // Allow the default strategy to be overridden using a system property for debugging. - if (!strategy) { - int length = property_get("debug.velocitytracker.strategy", value, NULL); - if (length > 0) { - strategy = value; - } else { - strategy = DEFAULT_STRATEGY; - } - } - - // Configure the strategy. - if (!configureStrategy(strategy)) { - ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy); - if (!configureStrategy(DEFAULT_STRATEGY)) { - LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!", - strategy); - } - } -} - -VelocityTracker::~VelocityTracker() { - delete mStrategy; -} - -bool VelocityTracker::configureStrategy(const char* strategy) { - mStrategy = createStrategy(strategy); - return mStrategy != NULL; -} - -VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) { - if (!strcmp("lsq1", strategy)) { - // 1st order least squares. Quality: POOR. - // Frequently underfits the touch data especially when the finger accelerates - // or changes direction. Often underestimates velocity. The direction - // is overly influenced by historical touch points. - return new LeastSquaresVelocityTrackerStrategy(1); - } - if (!strcmp("lsq2", strategy)) { - // 2nd order least squares. Quality: VERY GOOD. - // Pretty much ideal, but can be confused by certain kinds of touch data, - // particularly if the panel has a tendency to generate delayed, - // duplicate or jittery touch coordinates when the finger is released. - return new LeastSquaresVelocityTrackerStrategy(2); - } - if (!strcmp("lsq3", strategy)) { - // 3rd order least squares. Quality: UNUSABLE. - // Frequently overfits the touch data yielding wildly divergent estimates - // of the velocity when the finger is released. - return new LeastSquaresVelocityTrackerStrategy(3); - } - if (!strcmp("wlsq2-delta", strategy)) { - // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL - return new LeastSquaresVelocityTrackerStrategy(2, - LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA); - } - if (!strcmp("wlsq2-central", strategy)) { - // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL - return new LeastSquaresVelocityTrackerStrategy(2, - LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL); - } - if (!strcmp("wlsq2-recent", strategy)) { - // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL - return new LeastSquaresVelocityTrackerStrategy(2, - LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT); - } - if (!strcmp("int1", strategy)) { - // 1st order integrating filter. Quality: GOOD. - // Not as good as 'lsq2' because it cannot estimate acceleration but it is - // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate - // the velocity of a fling but this strategy tends to respond to changes in - // direction more quickly and accurately. - return new IntegratingVelocityTrackerStrategy(1); - } - if (!strcmp("int2", strategy)) { - // 2nd order integrating filter. Quality: EXPERIMENTAL. - // For comparison purposes only. Unlike 'int1' this strategy can compensate - // for acceleration but it typically overestimates the effect. - return new IntegratingVelocityTrackerStrategy(2); - } - if (!strcmp("legacy", strategy)) { - // Legacy velocity tracker algorithm. Quality: POOR. - // For comparison purposes only. This algorithm is strongly influenced by - // old data points, consistently underestimates velocity and takes a very long - // time to adjust to changes in direction. - return new LegacyVelocityTrackerStrategy(); - } - return NULL; -} - -void VelocityTracker::clear() { - mCurrentPointerIdBits.clear(); - mActivePointerId = -1; - - mStrategy->clear(); -} - -void VelocityTracker::clearPointers(BitSet32 idBits) { - BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value); - mCurrentPointerIdBits = remainingIdBits; - - if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) { - mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1; - } - - mStrategy->clearPointers(idBits); -} - -void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) { - while (idBits.count() > MAX_POINTERS) { - idBits.clearLastMarkedBit(); - } - - if ((mCurrentPointerIdBits.value & idBits.value) - && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) { -#if DEBUG_VELOCITY - ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.", - (eventTime - mLastEventTime) * 0.000001f); -#endif - // We have not received any movements for too long. Assume that all pointers - // have stopped. - mStrategy->clear(); - } - mLastEventTime = eventTime; - - mCurrentPointerIdBits = idBits; - if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) { - mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit(); - } - - mStrategy->addMovement(eventTime, idBits, positions); - -#if DEBUG_VELOCITY - ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d", - eventTime, idBits.value, mActivePointerId); - for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) { - uint32_t id = iterBits.firstMarkedBit(); - uint32_t index = idBits.getIndexOfBit(id); - iterBits.clearBit(id); - Estimator estimator; - getEstimator(id, &estimator); - ALOGD(" %d: position (%0.3f, %0.3f), " - "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)", - id, positions[index].x, positions[index].y, - int(estimator.degree), - vectorToString(estimator.xCoeff, estimator.degree + 1).string(), - vectorToString(estimator.yCoeff, estimator.degree + 1).string(), - estimator.confidence); - } -#endif -} - -void VelocityTracker::addMovement(const MotionEvent* event) { - int32_t actionMasked = event->getActionMasked(); - - switch (actionMasked) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - // Clear all pointers on down before adding the new movement. - clear(); - break; - case AMOTION_EVENT_ACTION_POINTER_DOWN: { - // Start a new movement trace for a pointer that just went down. - // We do this on down instead of on up because the client may want to query the - // final velocity for a pointer that just went up. - BitSet32 downIdBits; - downIdBits.markBit(event->getPointerId(event->getActionIndex())); - clearPointers(downIdBits); - break; - } - case AMOTION_EVENT_ACTION_MOVE: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - break; - default: - // Ignore all other actions because they do not convey any new information about - // pointer movement. We also want to preserve the last known velocity of the pointers. - // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position - // of the pointers that went up. ACTION_POINTER_UP does include the new position of - // pointers that remained down but we will also receive an ACTION_MOVE with this - // information if any of them actually moved. Since we don't know how many pointers - // will be going up at once it makes sense to just wait for the following ACTION_MOVE - // before adding the movement. - return; - } - - size_t pointerCount = event->getPointerCount(); - if (pointerCount > MAX_POINTERS) { - pointerCount = MAX_POINTERS; - } - - BitSet32 idBits; - for (size_t i = 0; i < pointerCount; i++) { - idBits.markBit(event->getPointerId(i)); - } - - uint32_t pointerIndex[MAX_POINTERS]; - for (size_t i = 0; i < pointerCount; i++) { - pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i)); - } - - nsecs_t eventTime; - Position positions[pointerCount]; - - size_t historySize = event->getHistorySize(); - for (size_t h = 0; h < historySize; h++) { - eventTime = event->getHistoricalEventTime(h); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t index = pointerIndex[i]; - positions[index].x = event->getHistoricalX(i, h); - positions[index].y = event->getHistoricalY(i, h); - } - addMovement(eventTime, idBits, positions); - } - - eventTime = event->getEventTime(); - for (size_t i = 0; i < pointerCount; i++) { - uint32_t index = pointerIndex[i]; - positions[index].x = event->getX(i); - positions[index].y = event->getY(i); - } - addMovement(eventTime, idBits, positions); -} - -bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const { - Estimator estimator; - if (getEstimator(id, &estimator) && estimator.degree >= 1) { - *outVx = estimator.xCoeff[1]; - *outVy = estimator.yCoeff[1]; - return true; - } - *outVx = 0; - *outVy = 0; - return false; -} - -bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const { - return mStrategy->getEstimator(id, outEstimator); -} - - -// --- LeastSquaresVelocityTrackerStrategy --- - -const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON; -const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE; - -LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy( - uint32_t degree, Weighting weighting) : - mDegree(degree), mWeighting(weighting) { - clear(); -} - -LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() { -} - -void LeastSquaresVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - -void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { - BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); - mMovements[mIndex].idBits = remainingIdBits; -} - -void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) { - if (++mIndex == HISTORY_SIZE) { - mIndex = 0; - } - - Movement& movement = mMovements[mIndex]; - movement.eventTime = eventTime; - movement.idBits = idBits; - uint32_t count = idBits.count(); - for (uint32_t i = 0; i < count; i++) { - movement.positions[i] = positions[i]; - } -} - -/** - * Solves a linear least squares problem to obtain a N degree polynomial that fits - * the specified input data as nearly as possible. - * - * Returns true if a solution is found, false otherwise. - * - * The input consists of two vectors of data points X and Y with indices 0..m-1 - * along with a weight vector W of the same size. - * - * The output is a vector B with indices 0..n that describes a polynomial - * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i] - * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized. - * - * Accordingly, the weight vector W should be initialized by the caller with the - * reciprocal square root of the variance of the error in each input data point. - * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]). - * The weights express the relative importance of each data point. If the weights are - * all 1, then the data points are considered to be of equal importance when fitting - * the polynomial. It is a good idea to choose weights that diminish the importance - * of data points that may have higher than usual error margins. - * - * Errors among data points are assumed to be independent. W is represented here - * as a vector although in the literature it is typically taken to be a diagonal matrix. - * - * That is to say, the function that generated the input data can be approximated - * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n. - * - * The coefficient of determination (R^2) is also returned to describe the goodness - * of fit of the model for the given data. It is a value between 0 and 1, where 1 - * indicates perfect correspondence. - * - * This function first expands the X vector to a m by n matrix A such that - * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then - * multiplies it by w[i]./ - * - * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q - * and an m by n upper triangular matrix R. Because R is upper triangular (lower - * part is all zeroes), we can simplify the decomposition into an m by n matrix - * Q1 and a n by n matrix R1 such that A = Q1 R1. - * - * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y) - * to find B. - * - * For efficiency, we lay out A and Q column-wise in memory because we frequently - * operate on the column vectors. Conversely, we lay out R row-wise. - * - * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares - * http://en.wikipedia.org/wiki/Gram-Schmidt - */ -static bool solveLeastSquares(const float* x, const float* y, - const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) { -#if DEBUG_STRATEGY - ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n), - vectorToString(x, m).string(), vectorToString(y, m).string(), - vectorToString(w, m).string()); -#endif - - // Expand the X vector to a matrix A, pre-multiplied by the weights. - float a[n][m]; // column-major order - for (uint32_t h = 0; h < m; h++) { - a[0][h] = w[h]; - for (uint32_t i = 1; i < n; i++) { - a[i][h] = a[i - 1][h] * x[h]; - } - } -#if DEBUG_STRATEGY - ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string()); -#endif - - // Apply the Gram-Schmidt process to A to obtain its QR decomposition. - float q[n][m]; // orthonormal basis, column-major order - float r[n][n]; // upper triangular matrix, row-major order - for (uint32_t j = 0; j < n; j++) { - for (uint32_t h = 0; h < m; h++) { - q[j][h] = a[j][h]; - } - for (uint32_t i = 0; i < j; i++) { - float dot = vectorDot(&q[j][0], &q[i][0], m); - for (uint32_t h = 0; h < m; h++) { - q[j][h] -= dot * q[i][h]; - } - } - - float norm = vectorNorm(&q[j][0], m); - if (norm < 0.000001f) { - // vectors are linearly dependent or zero so no solution -#if DEBUG_STRATEGY - ALOGD(" - no solution, norm=%f", norm); -#endif - return false; - } - - float invNorm = 1.0f / norm; - for (uint32_t h = 0; h < m; h++) { - q[j][h] *= invNorm; - } - for (uint32_t i = 0; i < n; i++) { - r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m); - } - } -#if DEBUG_STRATEGY - ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string()); - ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string()); - - // calculate QR, if we factored A correctly then QR should equal A - float qr[n][m]; - for (uint32_t h = 0; h < m; h++) { - for (uint32_t i = 0; i < n; i++) { - qr[i][h] = 0; - for (uint32_t j = 0; j < n; j++) { - qr[i][h] += q[j][h] * r[j][i]; - } - } - } - ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string()); -#endif - - // Solve R B = Qt W Y to find B. This is easy because R is upper triangular. - // We just work from bottom-right to top-left calculating B's coefficients. - float wy[m]; - for (uint32_t h = 0; h < m; h++) { - wy[h] = y[h] * w[h]; - } - for (uint32_t i = n; i-- != 0; ) { - outB[i] = vectorDot(&q[i][0], wy, m); - for (uint32_t j = n - 1; j > i; j--) { - outB[i] -= r[i][j] * outB[j]; - } - outB[i] /= r[i][i]; - } -#if DEBUG_STRATEGY - ALOGD(" - b=%s", vectorToString(outB, n).string()); -#endif - - // Calculate the coefficient of determination as 1 - (SSerr / SStot) where - // SSerr is the residual sum of squares (variance of the error), - // and SStot is the total sum of squares (variance of the data) where each - // has been weighted. - float ymean = 0; - for (uint32_t h = 0; h < m; h++) { - ymean += y[h]; - } - ymean /= m; - - float sserr = 0; - float sstot = 0; - for (uint32_t h = 0; h < m; h++) { - float err = y[h] - outB[0]; - float term = 1; - for (uint32_t i = 1; i < n; i++) { - term *= x[h]; - err -= term * outB[i]; - } - sserr += w[h] * w[h] * err * err; - float var = y[h] - ymean; - sstot += w[h] * w[h] * var * var; - } - *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1; -#if DEBUG_STRATEGY - ALOGD(" - sserr=%f", sserr); - ALOGD(" - sstot=%f", sstot); - ALOGD(" - det=%f", *outDet); -#endif - return true; -} - -bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->clear(); - - // Iterate over movement samples in reverse time order and collect samples. - float x[HISTORY_SIZE]; - float y[HISTORY_SIZE]; - float w[HISTORY_SIZE]; - float time[HISTORY_SIZE]; - uint32_t m = 0; - uint32_t index = mIndex; - const Movement& newestMovement = mMovements[mIndex]; - do { - const Movement& movement = mMovements[index]; - if (!movement.idBits.hasBit(id)) { - break; - } - - nsecs_t age = newestMovement.eventTime - movement.eventTime; - if (age > HORIZON) { - break; - } - - const VelocityTracker::Position& position = movement.getPosition(id); - x[m] = position.x; - y[m] = position.y; - w[m] = chooseWeight(index); - time[m] = -age * 0.000000001f; - index = (index == 0 ? HISTORY_SIZE : index) - 1; - } while (++m < HISTORY_SIZE); - - if (m == 0) { - return false; // no data - } - - // Calculate a least squares polynomial fit. - uint32_t degree = mDegree; - if (degree > m - 1) { - degree = m - 1; - } - if (degree >= 1) { - float xdet, ydet; - uint32_t n = degree + 1; - if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet) - && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) { - outEstimator->time = newestMovement.eventTime; - outEstimator->degree = degree; - outEstimator->confidence = xdet * ydet; -#if DEBUG_STRATEGY - ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f", - int(outEstimator->degree), - vectorToString(outEstimator->xCoeff, n).string(), - vectorToString(outEstimator->yCoeff, n).string(), - outEstimator->confidence); -#endif - return true; - } - } - - // No velocity data available for this pointer, but we do have its current position. - outEstimator->xCoeff[0] = x[0]; - outEstimator->yCoeff[0] = y[0]; - outEstimator->time = newestMovement.eventTime; - outEstimator->degree = 0; - outEstimator->confidence = 1; - return true; -} - -float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const { - switch (mWeighting) { - case WEIGHTING_DELTA: { - // Weight points based on how much time elapsed between them and the next - // point so that points that "cover" a shorter time span are weighed less. - // delta 0ms: 0.5 - // delta 10ms: 1.0 - if (index == mIndex) { - return 1.0f; - } - uint32_t nextIndex = (index + 1) % HISTORY_SIZE; - float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime) - * 0.000001f; - if (deltaMillis < 0) { - return 0.5f; - } - if (deltaMillis < 10) { - return 0.5f + deltaMillis * 0.05; - } - return 1.0f; - } - - case WEIGHTING_CENTRAL: { - // Weight points based on their age, weighing very recent and very old points less. - // age 0ms: 0.5 - // age 10ms: 1.0 - // age 50ms: 1.0 - // age 60ms: 0.5 - float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) - * 0.000001f; - if (ageMillis < 0) { - return 0.5f; - } - if (ageMillis < 10) { - return 0.5f + ageMillis * 0.05; - } - if (ageMillis < 50) { - return 1.0f; - } - if (ageMillis < 60) { - return 0.5f + (60 - ageMillis) * 0.05; - } - return 0.5f; - } - - case WEIGHTING_RECENT: { - // Weight points based on their age, weighing older points less. - // age 0ms: 1.0 - // age 50ms: 1.0 - // age 100ms: 0.5 - float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime) - * 0.000001f; - if (ageMillis < 50) { - return 1.0f; - } - if (ageMillis < 100) { - return 0.5f + (100 - ageMillis) * 0.01f; - } - return 0.5f; - } - - case WEIGHTING_NONE: - default: - return 1.0f; - } -} - - -// --- IntegratingVelocityTrackerStrategy --- - -IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) : - mDegree(degree) { -} - -IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() { -} - -void IntegratingVelocityTrackerStrategy::clear() { - mPointerIdBits.clear(); -} - -void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { - mPointerIdBits.value &= ~idBits.value; -} - -void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) { - uint32_t index = 0; - for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) { - uint32_t id = iterIdBits.clearFirstMarkedBit(); - State& state = mPointerState[id]; - const VelocityTracker::Position& position = positions[index++]; - if (mPointerIdBits.hasBit(id)) { - updateState(state, eventTime, position.x, position.y); - } else { - initState(state, eventTime, position.x, position.y); - } - } - - mPointerIdBits = idBits; -} - -bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->clear(); - - if (mPointerIdBits.hasBit(id)) { - const State& state = mPointerState[id]; - populateEstimator(state, outEstimator); - return true; - } - - return false; -} - -void IntegratingVelocityTrackerStrategy::initState(State& state, - nsecs_t eventTime, float xpos, float ypos) const { - state.updateTime = eventTime; - state.degree = 0; - - state.xpos = xpos; - state.xvel = 0; - state.xaccel = 0; - state.ypos = ypos; - state.yvel = 0; - state.yaccel = 0; -} - -void IntegratingVelocityTrackerStrategy::updateState(State& state, - nsecs_t eventTime, float xpos, float ypos) const { - const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS; - const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds - - if (eventTime <= state.updateTime + MIN_TIME_DELTA) { - return; - } - - float dt = (eventTime - state.updateTime) * 0.000000001f; - state.updateTime = eventTime; - - float xvel = (xpos - state.xpos) / dt; - float yvel = (ypos - state.ypos) / dt; - if (state.degree == 0) { - state.xvel = xvel; - state.yvel = yvel; - state.degree = 1; - } else { - float alpha = dt / (FILTER_TIME_CONSTANT + dt); - if (mDegree == 1) { - state.xvel += (xvel - state.xvel) * alpha; - state.yvel += (yvel - state.yvel) * alpha; - } else { - float xaccel = (xvel - state.xvel) / dt; - float yaccel = (yvel - state.yvel) / dt; - if (state.degree == 1) { - state.xaccel = xaccel; - state.yaccel = yaccel; - state.degree = 2; - } else { - state.xaccel += (xaccel - state.xaccel) * alpha; - state.yaccel += (yaccel - state.yaccel) * alpha; - } - state.xvel += (state.xaccel * dt) * alpha; - state.yvel += (state.yaccel * dt) * alpha; - } - } - state.xpos = xpos; - state.ypos = ypos; -} - -void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->time = state.updateTime; - outEstimator->confidence = 1.0f; - outEstimator->degree = state.degree; - outEstimator->xCoeff[0] = state.xpos; - outEstimator->xCoeff[1] = state.xvel; - outEstimator->xCoeff[2] = state.xaccel / 2; - outEstimator->yCoeff[0] = state.ypos; - outEstimator->yCoeff[1] = state.yvel; - outEstimator->yCoeff[2] = state.yaccel / 2; -} - - -// --- LegacyVelocityTrackerStrategy --- - -const nsecs_t LegacyVelocityTrackerStrategy::HORIZON; -const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE; -const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION; - -LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() { - clear(); -} - -LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() { -} - -void LegacyVelocityTrackerStrategy::clear() { - mIndex = 0; - mMovements[0].idBits.clear(); -} - -void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) { - BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value); - mMovements[mIndex].idBits = remainingIdBits; -} - -void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) { - if (++mIndex == HISTORY_SIZE) { - mIndex = 0; - } - - Movement& movement = mMovements[mIndex]; - movement.eventTime = eventTime; - movement.idBits = idBits; - uint32_t count = idBits.count(); - for (uint32_t i = 0; i < count; i++) { - movement.positions[i] = positions[i]; - } -} - -bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id, - VelocityTracker::Estimator* outEstimator) const { - outEstimator->clear(); - - const Movement& newestMovement = mMovements[mIndex]; - if (!newestMovement.idBits.hasBit(id)) { - return false; // no data - } - - // Find the oldest sample that contains the pointer and that is not older than HORIZON. - nsecs_t minTime = newestMovement.eventTime - HORIZON; - uint32_t oldestIndex = mIndex; - uint32_t numTouches = 1; - do { - uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1; - const Movement& nextOldestMovement = mMovements[nextOldestIndex]; - if (!nextOldestMovement.idBits.hasBit(id) - || nextOldestMovement.eventTime < minTime) { - break; - } - oldestIndex = nextOldestIndex; - } while (++numTouches < HISTORY_SIZE); - - // Calculate an exponentially weighted moving average of the velocity estimate - // at different points in time measured relative to the oldest sample. - // This is essentially an IIR filter. Newer samples are weighted more heavily - // than older samples. Samples at equal time points are weighted more or less - // equally. - // - // One tricky problem is that the sample data may be poorly conditioned. - // Sometimes samples arrive very close together in time which can cause us to - // overestimate the velocity at that time point. Most samples might be measured - // 16ms apart but some consecutive samples could be only 0.5sm apart because - // the hardware or driver reports them irregularly or in bursts. - float accumVx = 0; - float accumVy = 0; - uint32_t index = oldestIndex; - uint32_t samplesUsed = 0; - const Movement& oldestMovement = mMovements[oldestIndex]; - const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id); - nsecs_t lastDuration = 0; - - while (numTouches-- > 1) { - if (++index == HISTORY_SIZE) { - index = 0; - } - const Movement& movement = mMovements[index]; - nsecs_t duration = movement.eventTime - oldestMovement.eventTime; - - // If the duration between samples is small, we may significantly overestimate - // the velocity. Consequently, we impose a minimum duration constraint on the - // samples that we include in the calculation. - if (duration >= MIN_DURATION) { - const VelocityTracker::Position& position = movement.getPosition(id); - float scale = 1000000000.0f / duration; // one over time delta in seconds - float vx = (position.x - oldestPosition.x) * scale; - float vy = (position.y - oldestPosition.y) * scale; - accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration); - accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration); - lastDuration = duration; - samplesUsed += 1; - } - } - - // Report velocity. - const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id); - outEstimator->time = newestMovement.eventTime; - outEstimator->confidence = 1; - outEstimator->xCoeff[0] = newestPosition.x; - outEstimator->yCoeff[0] = newestPosition.y; - if (samplesUsed) { - outEstimator->xCoeff[1] = accumVx; - outEstimator->yCoeff[1] = accumVy; - outEstimator->degree = 1; - } else { - outEstimator->degree = 0; - } - return true; -} - -} // namespace android diff --git a/widget/gonk/libui/VelocityTracker.h b/widget/gonk/libui/VelocityTracker.h deleted file mode 100644 index fd077d438..000000000 --- a/widget/gonk/libui/VelocityTracker.h +++ /dev/null @@ -1,269 +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. - */ - -#ifndef _ANDROIDFW_VELOCITY_TRACKER_H -#define _ANDROIDFW_VELOCITY_TRACKER_H - -#include "Input.h" -#include -#include - -namespace android { - -class VelocityTrackerStrategy; - -/* - * Calculates the velocity of pointer movements over time. - */ -class VelocityTracker { -public: - struct Position { - float x, y; - }; - - struct Estimator { - static const size_t MAX_DEGREE = 4; - - // Estimator time base. - nsecs_t time; - - // Polynomial coefficients describing motion in X and Y. - float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1]; - - // Polynomial degree (number of coefficients), or zero if no information is - // available. - uint32_t degree; - - // Confidence (coefficient of determination), between 0 (no fit) and 1 (perfect fit). - float confidence; - - inline void clear() { - time = 0; - degree = 0; - confidence = 0; - for (size_t i = 0; i <= MAX_DEGREE; i++) { - xCoeff[i] = 0; - yCoeff[i] = 0; - } - } - }; - - // Creates a velocity tracker using the specified strategy. - // If strategy is NULL, uses the default strategy for the platform. - VelocityTracker(const char* strategy = NULL); - - ~VelocityTracker(); - - // Resets the velocity tracker state. - void clear(); - - // Resets the velocity tracker state for specific pointers. - // Call this method when some pointers have changed and may be reusing - // an id that was assigned to a different pointer earlier. - void clearPointers(BitSet32 idBits); - - // Adds movement information for a set of pointers. - // The idBits bitfield specifies the pointer ids of the pointers whose positions - // are included in the movement. - // The positions array contains position information for each pointer in order by - // increasing id. Its size should be equal to the number of one bits in idBits. - void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions); - - // Adds movement information for all pointers in a MotionEvent, including historical samples. - void addMovement(const MotionEvent* event); - - // Gets the velocity of the specified pointer id in position units per second. - // Returns false and sets the velocity components to zero if there is - // insufficient movement information for the pointer. - bool getVelocity(uint32_t id, float* outVx, float* outVy) const; - - // Gets an estimator for the recent movements of the specified pointer id. - // Returns false and clears the estimator if there is no information available - // about the pointer. - bool getEstimator(uint32_t id, Estimator* outEstimator) const; - - // Gets the active pointer id, or -1 if none. - inline int32_t getActivePointerId() const { return mActivePointerId; } - - // Gets a bitset containing all pointer ids from the most recent movement. - inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; } - -private: - static const char* DEFAULT_STRATEGY; - - nsecs_t mLastEventTime; - BitSet32 mCurrentPointerIdBits; - int32_t mActivePointerId; - VelocityTrackerStrategy* mStrategy; - - bool configureStrategy(const char* strategy); - - static VelocityTrackerStrategy* createStrategy(const char* strategy); -}; - - -/* - * Implements a particular velocity tracker algorithm. - */ -class VelocityTrackerStrategy { -protected: - VelocityTrackerStrategy() { } - -public: - virtual ~VelocityTrackerStrategy() { } - - virtual void clear() = 0; - virtual void clearPointers(BitSet32 idBits) = 0; - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions) = 0; - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0; -}; - - -/* - * Velocity tracker algorithm based on least-squares linear regression. - */ -class LeastSquaresVelocityTrackerStrategy : public VelocityTrackerStrategy { -public: - enum Weighting { - // No weights applied. All data points are equally reliable. - WEIGHTING_NONE, - - // Weight by time delta. Data points clustered together are weighted less. - WEIGHTING_DELTA, - - // Weight such that points within a certain horizon are weighed more than those - // outside of that horizon. - WEIGHTING_CENTRAL, - - // Weight such that points older than a certain amount are weighed less. - WEIGHTING_RECENT, - }; - - // Degree must be no greater than Estimator::MAX_DEGREE. - LeastSquaresVelocityTrackerStrategy(uint32_t degree, Weighting weighting = WEIGHTING_NONE); - virtual ~LeastSquaresVelocityTrackerStrategy(); - - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions); - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; - -private: - // Sample horizon. - // We don't use too much history by default since we want to react to quick - // changes in direction. - static const nsecs_t HORIZON = 100 * 1000000; // 100 ms - - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - struct Movement { - nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } - }; - - float chooseWeight(uint32_t index) const; - - const uint32_t mDegree; - const Weighting mWeighting; - uint32_t mIndex; - Movement mMovements[HISTORY_SIZE]; -}; - - -/* - * Velocity tracker algorithm that uses an IIR filter. - */ -class IntegratingVelocityTrackerStrategy : public VelocityTrackerStrategy { -public: - // Degree must be 1 or 2. - IntegratingVelocityTrackerStrategy(uint32_t degree); - ~IntegratingVelocityTrackerStrategy(); - - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions); - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; - -private: - // Current state estimate for a particular pointer. - struct State { - nsecs_t updateTime; - uint32_t degree; - - float xpos, xvel, xaccel; - float ypos, yvel, yaccel; - }; - - const uint32_t mDegree; - BitSet32 mPointerIdBits; - State mPointerState[MAX_POINTER_ID + 1]; - - void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const; - void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const; - void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const; -}; - - -/* - * Velocity tracker strategy used prior to ICS. - */ -class LegacyVelocityTrackerStrategy : public VelocityTrackerStrategy { -public: - LegacyVelocityTrackerStrategy(); - virtual ~LegacyVelocityTrackerStrategy(); - - virtual void clear(); - virtual void clearPointers(BitSet32 idBits); - virtual void addMovement(nsecs_t eventTime, BitSet32 idBits, - const VelocityTracker::Position* positions); - virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const; - -private: - // Oldest sample to consider when calculating the velocity. - static const nsecs_t HORIZON = 200 * 1000000; // 100 ms - - // Number of samples to keep. - static const uint32_t HISTORY_SIZE = 20; - - // The minimum duration between samples when estimating velocity. - static const nsecs_t MIN_DURATION = 10 * 1000000; // 10 ms - - struct Movement { - nsecs_t eventTime; - BitSet32 idBits; - VelocityTracker::Position positions[MAX_POINTERS]; - - inline const VelocityTracker::Position& getPosition(uint32_t id) const { - return positions[idBits.getIndexOfBit(id)]; - } - }; - - uint32_t mIndex; - Movement mMovements[HISTORY_SIZE]; -}; - -} // namespace android - -#endif // _ANDROIDFW_VELOCITY_TRACKER_H diff --git a/widget/gonk/libui/VirtualKeyMap.cpp b/widget/gonk/libui/VirtualKeyMap.cpp deleted file mode 100644 index 444ab3718..000000000 --- a/widget/gonk/libui/VirtualKeyMap.cpp +++ /dev/null @@ -1,171 +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. - */ - -#define LOG_TAG "VirtualKeyMap" -#include "cutils_log.h" - -#include -#include -#include "VirtualKeyMap.h" -#include -#include "Tokenizer.h" -#include - -// Enables debug output for the parser. -#define DEBUG_PARSER 0 - -// Enables debug output for parser performance. -#define DEBUG_PARSER_PERFORMANCE 0 - - -namespace android { - -static const char* WHITESPACE = " \t\r"; -static const char* WHITESPACE_OR_FIELD_DELIMITER = " \t\r:"; - - -// --- VirtualKeyMap --- - -VirtualKeyMap::VirtualKeyMap() { -} - -VirtualKeyMap::~VirtualKeyMap() { -} - -status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) { - *outMap = NULL; - - Tokenizer* tokenizer; - status_t status = Tokenizer::open(filename, &tokenizer); - if (status) { - ALOGE("Error %d opening virtual key map file %s.", status, filename.string()); - } else { - VirtualKeyMap* map = new VirtualKeyMap(); - if (!map) { - ALOGE("Error allocating virtual key map."); - status = NO_MEMORY; - } else { -#if DEBUG_PARSER_PERFORMANCE - nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC); -#endif - Parser parser(map, tokenizer); - status = parser.parse(); -#if DEBUG_PARSER_PERFORMANCE - nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime; - ALOGD("Parsed key character map file '%s' %d lines in %0.3fms.", - tokenizer->getFilename().string(), tokenizer->getLineNumber(), - elapsedTime / 1000000.0); -#endif - if (status) { - delete map; - } else { - *outMap = map; - } - } - delete tokenizer; - } - return status; -} - - -// --- VirtualKeyMap::Parser --- - -VirtualKeyMap::Parser::Parser(VirtualKeyMap* map, Tokenizer* tokenizer) : - mMap(map), mTokenizer(tokenizer) { -} - -VirtualKeyMap::Parser::~Parser() { -} - -status_t VirtualKeyMap::Parser::parse() { - while (!mTokenizer->isEof()) { -#if DEBUG_PARSER - ALOGD("Parsing %s: '%s'.", mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); -#endif - - mTokenizer->skipDelimiters(WHITESPACE); - - if (!mTokenizer->isEol() && mTokenizer->peekChar() != '#') { - // Multiple keys can appear on one line or they can be broken up across multiple lines. - do { - String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); - if (token != "0x01") { - ALOGE("%s: Unknown virtual key type, expected 0x01.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - - VirtualKeyDefinition defn; - bool success = parseNextIntField(&defn.scanCode) - && parseNextIntField(&defn.centerX) - && parseNextIntField(&defn.centerY) - && parseNextIntField(&defn.width) - && parseNextIntField(&defn.height); - if (!success) { - ALOGE("%s: Expected 5 colon-delimited integers in virtual key definition.", - mTokenizer->getLocation().string()); - return BAD_VALUE; - } - -#if DEBUG_PARSER - ALOGD("Parsed virtual key: scanCode=%d, centerX=%d, centerY=%d, " - "width=%d, height=%d", - defn.scanCode, defn.centerX, defn.centerY, defn.width, defn.height); -#endif - mMap->mVirtualKeys.push(defn); - } while (consumeFieldDelimiterAndSkipWhitespace()); - - if (!mTokenizer->isEol()) { - ALOGE("%s: Expected end of line, got '%s'.", - mTokenizer->getLocation().string(), - mTokenizer->peekRemainderOfLine().string()); - return BAD_VALUE; - } - } - - mTokenizer->nextLine(); - } - - return NO_ERROR; -} - -bool VirtualKeyMap::Parser::consumeFieldDelimiterAndSkipWhitespace() { - mTokenizer->skipDelimiters(WHITESPACE); - if (mTokenizer->peekChar() == ':') { - mTokenizer->nextChar(); - mTokenizer->skipDelimiters(WHITESPACE); - return true; - } - return false; -} - -bool VirtualKeyMap::Parser::parseNextIntField(int32_t* outValue) { - if (!consumeFieldDelimiterAndSkipWhitespace()) { - return false; - } - - String8 token = mTokenizer->nextToken(WHITESPACE_OR_FIELD_DELIMITER); - char* end; - *outValue = strtol(token.string(), &end, 0); - if (token.isEmpty() || *end != '\0') { - ALOGE("Expected an integer, got '%s'.", token.string()); - return false; - } - return true; -} - -} // namespace android diff --git a/widget/gonk/libui/VirtualKeyMap.h b/widget/gonk/libui/VirtualKeyMap.h deleted file mode 100644 index 79d61a536..000000000 --- a/widget/gonk/libui/VirtualKeyMap.h +++ /dev/null @@ -1,81 +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. - */ - -#ifndef _ANDROIDFW_VIRTUAL_KEY_MAP_H -#define _ANDROIDFW_VIRTUAL_KEY_MAP_H - -#include - -#include "Input.h" -#include -#include -#include "Tokenizer.h" -#include -#include - -namespace android { - -/* Describes a virtual key. */ -struct VirtualKeyDefinition { - int32_t scanCode; - - // configured position data, specified in display coords - int32_t centerX; - int32_t centerY; - int32_t width; - int32_t height; -}; - - -/** - * Describes a collection of virtual keys on a touch screen in terms of - * virtual scan codes and hit rectangles. - * - * This object is immutable after it has been loaded. - */ -class VirtualKeyMap { -public: - ~VirtualKeyMap(); - - static status_t load(const String8& filename, VirtualKeyMap** outMap); - - inline const Vector& getVirtualKeys() const { - return mVirtualKeys; - } - -private: - class Parser { - VirtualKeyMap* mMap; - Tokenizer* mTokenizer; - - public: - Parser(VirtualKeyMap* map, Tokenizer* tokenizer); - ~Parser(); - status_t parse(); - - private: - bool consumeFieldDelimiterAndSkipWhitespace(); - bool parseNextIntField(int32_t* outValue); - }; - - Vector mVirtualKeys; - - VirtualKeyMap(); -}; - -} // namespace android - -#endif // _ANDROIDFW_KEY_CHARACTER_MAP_H diff --git a/widget/gonk/libui/android_input.h b/widget/gonk/libui/android_input.h deleted file mode 100644 index 00e81b28d..000000000 --- a/widget/gonk/libui/android_input.h +++ /dev/null @@ -1,850 +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. - */ - -#ifndef _ANDROID_INPUT_H -#define _ANDROID_INPUT_H - -/****************************************************************** - * - * IMPORTANT NOTICE: - * - * This file is part of Android's set of stable system headers - * exposed by the Android NDK (Native Development Kit). - * - * Third-party source AND binary code relies on the definitions - * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. - * - * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) - * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS - * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY - * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES - */ - -/* - * Structures and functions to receive and process input events in - * native code. - * - * NOTE: These functions MUST be implemented by /system/lib/libui.so - */ - -#include -#include -#include "android_keycodes.h" -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Key states (may be returned by queries about the current state of a - * particular key code, scan code or switch). - */ -enum { - /* The key state is unknown or the requested key itself is not supported. */ - AKEY_STATE_UNKNOWN = -1, - - /* The key is up. */ - AKEY_STATE_UP = 0, - - /* The key is down. */ - AKEY_STATE_DOWN = 1, - - /* The key is down but is a virtual key press that is being emulated by the system. */ - AKEY_STATE_VIRTUAL = 2 -}; - -/* - * Meta key / modifer state. - */ -enum { - /* No meta keys are pressed. */ - AMETA_NONE = 0, - - /* This mask is used to check whether one of the ALT meta keys is pressed. */ - AMETA_ALT_ON = 0x02, - - /* This mask is used to check whether the left ALT meta key is pressed. */ - AMETA_ALT_LEFT_ON = 0x10, - - /* This mask is used to check whether the right ALT meta key is pressed. */ - AMETA_ALT_RIGHT_ON = 0x20, - - /* This mask is used to check whether one of the SHIFT meta keys is pressed. */ - AMETA_SHIFT_ON = 0x01, - - /* This mask is used to check whether the left SHIFT meta key is pressed. */ - AMETA_SHIFT_LEFT_ON = 0x40, - - /* This mask is used to check whether the right SHIFT meta key is pressed. */ - AMETA_SHIFT_RIGHT_ON = 0x80, - - /* This mask is used to check whether the SYM meta key is pressed. */ - AMETA_SYM_ON = 0x04, - - /* This mask is used to check whether the FUNCTION meta key is pressed. */ - AMETA_FUNCTION_ON = 0x08, - - /* This mask is used to check whether one of the CTRL meta keys is pressed. */ - AMETA_CTRL_ON = 0x1000, - - /* This mask is used to check whether the left CTRL meta key is pressed. */ - AMETA_CTRL_LEFT_ON = 0x2000, - - /* This mask is used to check whether the right CTRL meta key is pressed. */ - AMETA_CTRL_RIGHT_ON = 0x4000, - - /* This mask is used to check whether one of the META meta keys is pressed. */ - AMETA_META_ON = 0x10000, - - /* This mask is used to check whether the left META meta key is pressed. */ - AMETA_META_LEFT_ON = 0x20000, - - /* This mask is used to check whether the right META meta key is pressed. */ - AMETA_META_RIGHT_ON = 0x40000, - - /* This mask is used to check whether the CAPS LOCK meta key is on. */ - AMETA_CAPS_LOCK_ON = 0x100000, - - /* This mask is used to check whether the NUM LOCK meta key is on. */ - AMETA_NUM_LOCK_ON = 0x200000, - - /* This mask is used to check whether the SCROLL LOCK meta key is on. */ - AMETA_SCROLL_LOCK_ON = 0x400000, -}; - -/* - * Input events. - * - * Input events are opaque structures. Use the provided accessors functions to - * read their properties. - */ -struct AInputEvent; -typedef struct AInputEvent AInputEvent; - -/* - * Input event types. - */ -enum { - /* Indicates that the input event is a key event. */ - AINPUT_EVENT_TYPE_KEY = 1, - - /* Indicates that the input event is a motion event. */ - AINPUT_EVENT_TYPE_MOTION = 2 -}; - -/* - * Key event actions. - */ -enum { - /* The key has been pressed down. */ - AKEY_EVENT_ACTION_DOWN = 0, - - /* The key has been released. */ - AKEY_EVENT_ACTION_UP = 1, - - /* Multiple duplicate key events have occurred in a row, or a complex string is - * being delivered. The repeat_count property of the key event contains the number - * of times the given key code should be executed. - */ - AKEY_EVENT_ACTION_MULTIPLE = 2 -}; - -/* - * Key event flags. - */ -enum { - /* This mask is set if the device woke because of this key event. */ - AKEY_EVENT_FLAG_WOKE_HERE = 0x1, - - /* This mask is set if the key event was generated by a software keyboard. */ - AKEY_EVENT_FLAG_SOFT_KEYBOARD = 0x2, - - /* This mask is set if we don't want the key event to cause us to leave touch mode. */ - AKEY_EVENT_FLAG_KEEP_TOUCH_MODE = 0x4, - - /* This mask is set if an event was known to come from a trusted part - * of the system. That is, the event is known to come from the user, - * and could not have been spoofed by a third party component. */ - AKEY_EVENT_FLAG_FROM_SYSTEM = 0x8, - - /* This mask is used for compatibility, to identify enter keys that are - * coming from an IME whose enter key has been auto-labelled "next" or - * "done". This allows TextView to dispatch these as normal enter keys - * for old applications, but still do the appropriate action when - * receiving them. */ - AKEY_EVENT_FLAG_EDITOR_ACTION = 0x10, - - /* When associated with up key events, this indicates that the key press - * has been canceled. Typically this is used with virtual touch screen - * keys, where the user can slide from the virtual key area on to the - * display: in that case, the application will receive a canceled up - * event and should not perform the action normally associated with the - * key. Note that for this to work, the application can not perform an - * action for a key until it receives an up or the long press timeout has - * expired. */ - AKEY_EVENT_FLAG_CANCELED = 0x20, - - /* This key event was generated by a virtual (on-screen) hard key area. - * Typically this is an area of the touchscreen, outside of the regular - * display, dedicated to "hardware" buttons. */ - AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY = 0x40, - - /* This flag is set for the first key repeat that occurs after the - * long press timeout. */ - AKEY_EVENT_FLAG_LONG_PRESS = 0x80, - - /* Set when a key event has AKEY_EVENT_FLAG_CANCELED set because a long - * press action was executed while it was down. */ - AKEY_EVENT_FLAG_CANCELED_LONG_PRESS = 0x100, - - /* Set for AKEY_EVENT_ACTION_UP when this event's key code is still being - * tracked from its initial down. That is, somebody requested that tracking - * started on the key down and a long press has not caused - * the tracking to be canceled. */ - AKEY_EVENT_FLAG_TRACKING = 0x200, - - /* Set when a key event has been synthesized to implement default behavior - * for an event that the application did not handle. - * Fallback key events are generated by unhandled trackball motions - * (to emulate a directional keypad) and by certain unhandled key presses - * that are declared in the key map (such as special function numeric keypad - * keys when numlock is off). */ - AKEY_EVENT_FLAG_FALLBACK = 0x400, -}; - -/* - * Motion event actions. - */ - -/* Bit shift for the action bits holding the pointer index as - * defined by AMOTION_EVENT_ACTION_POINTER_INDEX_MASK. - */ -#define AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT 8 - -enum { - /* Bit mask of the parts of the action code that are the action itself. - */ - AMOTION_EVENT_ACTION_MASK = 0xff, - - /* Bits in the action code that represent a pointer index, used with - * AMOTION_EVENT_ACTION_POINTER_DOWN and AMOTION_EVENT_ACTION_POINTER_UP. Shifting - * down by AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT provides the actual pointer - * index where the data for the pointer going up or down can be found. - */ - AMOTION_EVENT_ACTION_POINTER_INDEX_MASK = 0xff00, - - /* A pressed gesture has started, the motion contains the initial starting location. - */ - AMOTION_EVENT_ACTION_DOWN = 0, - - /* A pressed gesture has finished, the motion contains the final release location - * as well as any intermediate points since the last down or move event. - */ - AMOTION_EVENT_ACTION_UP = 1, - - /* A change has happened during a press gesture (between AMOTION_EVENT_ACTION_DOWN and - * AMOTION_EVENT_ACTION_UP). The motion contains the most recent point, as well as - * any intermediate points since the last down or move event. - */ - AMOTION_EVENT_ACTION_MOVE = 2, - - /* The current gesture has been aborted. - * You will not receive any more points in it. You should treat this as - * an up event, but not perform any action that you normally would. - */ - AMOTION_EVENT_ACTION_CANCEL = 3, - - /* A movement has happened outside of the normal bounds of the UI element. - * This does not provide a full gesture, but only the initial location of the movement/touch. - */ - AMOTION_EVENT_ACTION_OUTSIDE = 4, - - /* A non-primary pointer has gone down. - * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. - */ - AMOTION_EVENT_ACTION_POINTER_DOWN = 5, - - /* A non-primary pointer has gone up. - * The bits in AMOTION_EVENT_ACTION_POINTER_INDEX_MASK indicate which pointer changed. - */ - AMOTION_EVENT_ACTION_POINTER_UP = 6, - - /* A change happened but the pointer is not down (unlike AMOTION_EVENT_ACTION_MOVE). - * The motion contains the most recent point, as well as any intermediate points since - * the last hover move event. - */ - AMOTION_EVENT_ACTION_HOVER_MOVE = 7, - - /* The motion event contains relative vertical and/or horizontal scroll offsets. - * Use getAxisValue to retrieve the information from AMOTION_EVENT_AXIS_VSCROLL - * and AMOTION_EVENT_AXIS_HSCROLL. - * The pointer may or may not be down when this event is dispatched. - * This action is always delivered to the winder under the pointer, which - * may not be the window currently touched. - */ - AMOTION_EVENT_ACTION_SCROLL = 8, - - /* The pointer is not down but has entered the boundaries of a window or view. - */ - AMOTION_EVENT_ACTION_HOVER_ENTER = 9, - - /* The pointer is not down but has exited the boundaries of a window or view. - */ - AMOTION_EVENT_ACTION_HOVER_EXIT = 10, -}; - -/* - * Motion event flags. - */ -enum { - /* This flag indicates that the window that received this motion event is partly - * or wholly obscured by another visible window above it. This flag is set to true - * even if the event did not directly pass through the obscured area. - * A security sensitive application can check this flag to identify situations in which - * a malicious application may have covered up part of its content for the purpose - * of misleading the user or hijacking touches. An appropriate response might be - * to drop the suspect touches or to take additional precautions to confirm the user's - * actual intent. - */ - AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED = 0x1, -}; - -/* - * Motion event edge touch flags. - */ -enum { - /* No edges intersected */ - AMOTION_EVENT_EDGE_FLAG_NONE = 0, - - /* Flag indicating the motion event intersected the top edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_TOP = 0x01, - - /* Flag indicating the motion event intersected the bottom edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_BOTTOM = 0x02, - - /* Flag indicating the motion event intersected the left edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_LEFT = 0x04, - - /* Flag indicating the motion event intersected the right edge of the screen. */ - AMOTION_EVENT_EDGE_FLAG_RIGHT = 0x08 -}; - -/* - * Constants that identify each individual axis of a motion event. - * Refer to the documentation on the MotionEvent class for descriptions of each axis. - */ -enum { - AMOTION_EVENT_AXIS_X = 0, - AMOTION_EVENT_AXIS_Y = 1, - AMOTION_EVENT_AXIS_PRESSURE = 2, - AMOTION_EVENT_AXIS_SIZE = 3, - AMOTION_EVENT_AXIS_TOUCH_MAJOR = 4, - AMOTION_EVENT_AXIS_TOUCH_MINOR = 5, - AMOTION_EVENT_AXIS_TOOL_MAJOR = 6, - AMOTION_EVENT_AXIS_TOOL_MINOR = 7, - AMOTION_EVENT_AXIS_ORIENTATION = 8, - AMOTION_EVENT_AXIS_VSCROLL = 9, - AMOTION_EVENT_AXIS_HSCROLL = 10, - AMOTION_EVENT_AXIS_Z = 11, - AMOTION_EVENT_AXIS_RX = 12, - AMOTION_EVENT_AXIS_RY = 13, - AMOTION_EVENT_AXIS_RZ = 14, - AMOTION_EVENT_AXIS_HAT_X = 15, - AMOTION_EVENT_AXIS_HAT_Y = 16, - AMOTION_EVENT_AXIS_LTRIGGER = 17, - AMOTION_EVENT_AXIS_RTRIGGER = 18, - AMOTION_EVENT_AXIS_THROTTLE = 19, - AMOTION_EVENT_AXIS_RUDDER = 20, - AMOTION_EVENT_AXIS_WHEEL = 21, - AMOTION_EVENT_AXIS_GAS = 22, - AMOTION_EVENT_AXIS_BRAKE = 23, - AMOTION_EVENT_AXIS_DISTANCE = 24, - AMOTION_EVENT_AXIS_TILT = 25, - AMOTION_EVENT_AXIS_GENERIC_1 = 32, - AMOTION_EVENT_AXIS_GENERIC_2 = 33, - AMOTION_EVENT_AXIS_GENERIC_3 = 34, - AMOTION_EVENT_AXIS_GENERIC_4 = 35, - AMOTION_EVENT_AXIS_GENERIC_5 = 36, - AMOTION_EVENT_AXIS_GENERIC_6 = 37, - AMOTION_EVENT_AXIS_GENERIC_7 = 38, - AMOTION_EVENT_AXIS_GENERIC_8 = 39, - AMOTION_EVENT_AXIS_GENERIC_9 = 40, - AMOTION_EVENT_AXIS_GENERIC_10 = 41, - AMOTION_EVENT_AXIS_GENERIC_11 = 42, - AMOTION_EVENT_AXIS_GENERIC_12 = 43, - AMOTION_EVENT_AXIS_GENERIC_13 = 44, - AMOTION_EVENT_AXIS_GENERIC_14 = 45, - AMOTION_EVENT_AXIS_GENERIC_15 = 46, - AMOTION_EVENT_AXIS_GENERIC_16 = 47, - - // NOTE: If you add a new axis here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list. -}; - -/* - * Constants that identify buttons that are associated with motion events. - * Refer to the documentation on the MotionEvent class for descriptions of each button. - */ -enum { - AMOTION_EVENT_BUTTON_PRIMARY = 1 << 0, - AMOTION_EVENT_BUTTON_SECONDARY = 1 << 1, - AMOTION_EVENT_BUTTON_TERTIARY = 1 << 2, - AMOTION_EVENT_BUTTON_BACK = 1 << 3, - AMOTION_EVENT_BUTTON_FORWARD = 1 << 4, -}; - -/* - * Constants that identify tool types. - * Refer to the documentation on the MotionEvent class for descriptions of each tool type. - */ -enum { - AMOTION_EVENT_TOOL_TYPE_UNKNOWN = 0, - AMOTION_EVENT_TOOL_TYPE_FINGER = 1, - AMOTION_EVENT_TOOL_TYPE_STYLUS = 2, - AMOTION_EVENT_TOOL_TYPE_MOUSE = 3, - AMOTION_EVENT_TOOL_TYPE_ERASER = 4, -}; - -/* - * Input sources. - * - * Refer to the documentation on android.view.InputDevice for more details about input sources - * and their correct interpretation. - */ -enum { - AINPUT_SOURCE_CLASS_MASK = 0x000000ff, - - AINPUT_SOURCE_CLASS_NONE = 0x00000000, - AINPUT_SOURCE_CLASS_BUTTON = 0x00000001, - AINPUT_SOURCE_CLASS_POINTER = 0x00000002, - AINPUT_SOURCE_CLASS_NAVIGATION = 0x00000004, - AINPUT_SOURCE_CLASS_POSITION = 0x00000008, - AINPUT_SOURCE_CLASS_JOYSTICK = 0x00000010, -}; - -enum { - AINPUT_SOURCE_UNKNOWN = 0x00000000, - - AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON, - AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON, - AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON, - AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER, - AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER, - AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER, - AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION, - AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION, - AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE, - AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK, - - AINPUT_SOURCE_ANY = 0xffffff00, -}; - -/* - * Keyboard types. - * - * Refer to the documentation on android.view.InputDevice for more details. - */ -enum { - AINPUT_KEYBOARD_TYPE_NONE = 0, - AINPUT_KEYBOARD_TYPE_NON_ALPHABETIC = 1, - AINPUT_KEYBOARD_TYPE_ALPHABETIC = 2, -}; - -/* - * Constants used to retrieve information about the range of motion for a particular - * coordinate of a motion event. - * - * Refer to the documentation on android.view.InputDevice for more details about input sources - * and their correct interpretation. - * - * DEPRECATION NOTICE: These constants are deprecated. Use AMOTION_EVENT_AXIS_* constants instead. - */ -enum { - AINPUT_MOTION_RANGE_X = AMOTION_EVENT_AXIS_X, - AINPUT_MOTION_RANGE_Y = AMOTION_EVENT_AXIS_Y, - AINPUT_MOTION_RANGE_PRESSURE = AMOTION_EVENT_AXIS_PRESSURE, - AINPUT_MOTION_RANGE_SIZE = AMOTION_EVENT_AXIS_SIZE, - AINPUT_MOTION_RANGE_TOUCH_MAJOR = AMOTION_EVENT_AXIS_TOUCH_MAJOR, - AINPUT_MOTION_RANGE_TOUCH_MINOR = AMOTION_EVENT_AXIS_TOUCH_MINOR, - AINPUT_MOTION_RANGE_TOOL_MAJOR = AMOTION_EVENT_AXIS_TOOL_MAJOR, - AINPUT_MOTION_RANGE_TOOL_MINOR = AMOTION_EVENT_AXIS_TOOL_MINOR, - AINPUT_MOTION_RANGE_ORIENTATION = AMOTION_EVENT_AXIS_ORIENTATION, -} __attribute__ ((deprecated)); - - -/* - * Input event accessors. - * - * Note that most functions can only be used on input events that are of a given type. - * Calling these functions on input events of other types will yield undefined behavior. - */ - -/*** Accessors for all input events. ***/ - -/* Get the input event type. */ -int32_t AInputEvent_getType(const AInputEvent* event); - -/* Get the id for the device that an input event came from. - * - * Input events can be generated by multiple different input devices. - * Use the input device id to obtain information about the input - * device that was responsible for generating a particular event. - * - * An input device id of 0 indicates that the event didn't come from a physical device; - * other numbers are arbitrary and you shouldn't depend on the values. - * Use the provided input device query API to obtain information about input devices. - */ -int32_t AInputEvent_getDeviceId(const AInputEvent* event); - -/* Get the input event source. */ -int32_t AInputEvent_getSource(const AInputEvent* event); - -/*** Accessors for key events only. ***/ - -/* Get the key event action. */ -int32_t AKeyEvent_getAction(const AInputEvent* key_event); - -/* Get the key event flags. */ -int32_t AKeyEvent_getFlags(const AInputEvent* key_event); - -/* Get the key code of the key event. - * This is the physical key that was pressed, not the Unicode character. */ -int32_t AKeyEvent_getKeyCode(const AInputEvent* key_event); - -/* Get the hardware key id of this key event. - * These values are not reliable and vary from device to device. */ -int32_t AKeyEvent_getScanCode(const AInputEvent* key_event); - -/* Get the meta key state. */ -int32_t AKeyEvent_getMetaState(const AInputEvent* key_event); - -/* Get the repeat count of the event. - * For both key up an key down events, this is the number of times the key has - * repeated with the first down starting at 0 and counting up from there. For - * multiple key events, this is the number of down/up pairs that have occurred. */ -int32_t AKeyEvent_getRepeatCount(const AInputEvent* key_event); - -/* Get the time of the most recent key down event, in the - * java.lang.System.nanoTime() time base. If this is a down event, - * this will be the same as eventTime. - * Note that when chording keys, this value is the down time of the most recently - * pressed key, which may not be the same physical key of this event. */ -int64_t AKeyEvent_getDownTime(const AInputEvent* key_event); - -/* Get the time this event occurred, in the - * java.lang.System.nanoTime() time base. */ -int64_t AKeyEvent_getEventTime(const AInputEvent* key_event); - -/*** Accessors for motion events only. ***/ - -/* Get the combined motion event action code and pointer index. */ -int32_t AMotionEvent_getAction(const AInputEvent* motion_event); - -/* Get the motion event flags. */ -int32_t AMotionEvent_getFlags(const AInputEvent* motion_event); - -/* Get the state of any meta / modifier keys that were in effect when the - * event was generated. */ -int32_t AMotionEvent_getMetaState(const AInputEvent* motion_event); - -/* Get the button state of all buttons that are pressed. */ -int32_t AMotionEvent_getButtonState(const AInputEvent* motion_event); - -/* Get a bitfield indicating which edges, if any, were touched by this motion event. - * For touch events, clients can use this to determine if the user's finger was - * touching the edge of the display. */ -int32_t AMotionEvent_getEdgeFlags(const AInputEvent* motion_event); - -/* Get the time when the user originally pressed down to start a stream of - * position events, in the java.lang.System.nanoTime() time base. */ -int64_t AMotionEvent_getDownTime(const AInputEvent* motion_event); - -/* Get the time when this specific event was generated, - * in the java.lang.System.nanoTime() time base. */ -int64_t AMotionEvent_getEventTime(const AInputEvent* motion_event); - -/* Get the X coordinate offset. - * For touch events on the screen, this is the delta that was added to the raw - * screen coordinates to adjust for the absolute position of the containing windows - * and views. */ -float AMotionEvent_getXOffset(const AInputEvent* motion_event); - -/* Get the precision of the Y coordinates being reported. - * For touch events on the screen, this is the delta that was added to the raw - * screen coordinates to adjust for the absolute position of the containing windows - * and views. */ -float AMotionEvent_getYOffset(const AInputEvent* motion_event); - -/* Get the precision of the X coordinates being reported. - * You can multiply this number with an X coordinate sample to find the - * actual hardware value of the X coordinate. */ -float AMotionEvent_getXPrecision(const AInputEvent* motion_event); - -/* Get the precision of the Y coordinates being reported. - * You can multiply this number with a Y coordinate sample to find the - * actual hardware value of the Y coordinate. */ -float AMotionEvent_getYPrecision(const AInputEvent* motion_event); - -/* Get the number of pointers of data contained in this event. - * Always >= 1. */ -size_t AMotionEvent_getPointerCount(const AInputEvent* motion_event); - -/* Get the pointer identifier associated with a particular pointer - * data index in this event. The identifier tells you the actual pointer - * number associated with the data, accounting for individual pointers - * going up and down since the start of the current gesture. */ -int32_t AMotionEvent_getPointerId(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the tool type of a pointer for the given pointer index. - * The tool type indicates the type of tool used to make contact such as a - * finger or stylus, if known. */ -int32_t AMotionEvent_getToolType(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the original raw X coordinate of this event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. */ -float AMotionEvent_getRawX(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the original raw X coordinate of this event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. */ -float AMotionEvent_getRawY(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current X coordinate of this event for the given pointer index. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getX(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current Y coordinate of this event for the given pointer index. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getY(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current pressure of this event for the given pointer index. - * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), - * although values higher than 1 may be generated depending on the calibration of - * the input device. */ -float AMotionEvent_getPressure(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current scaled value of the approximate size for the given pointer index. - * This represents some approximation of the area of the screen being - * pressed; the actual value in pixels corresponding to the - * touch is normalized with the device specific range of values - * and scaled to a value between 0 and 1. The value of size can be used to - * determine fat touch events. */ -float AMotionEvent_getSize(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the major axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index. */ -float AMotionEvent_getTouchMajor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the minor axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index. */ -float AMotionEvent_getTouchMinor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the major axis of an ellipse that describes the size - * of the approaching tool for the given pointer index. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getToolMajor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current length of the minor axis of an ellipse that describes the size - * of the approaching tool for the given pointer index. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getToolMinor(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the current orientation of the touch area and tool area in radians clockwise from - * vertical for the given pointer index. - * An angle of 0 degrees indicates that the major axis of contact is oriented - * upwards, is perfectly circular or is of unknown orientation. A positive angle - * indicates that the major axis of contact is oriented to the right. A negative angle - * indicates that the major axis of contact is oriented to the left. - * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians - * (finger pointing fully right). */ -float AMotionEvent_getOrientation(const AInputEvent* motion_event, size_t pointer_index); - -/* Get the value of the request axis for the given pointer index. */ -float AMotionEvent_getAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index); - -/* Get the number of historical points in this event. These are movements that - * have occurred between this event and the previous event. This only applies - * to AMOTION_EVENT_ACTION_MOVE events -- all other actions will have a size of 0. - * Historical samples are indexed from oldest to newest. */ -size_t AMotionEvent_getHistorySize(const AInputEvent* motion_event); - -/* Get the time that a historical movement occurred between this event and - * the previous event, in the java.lang.System.nanoTime() time base. */ -int64_t AMotionEvent_getHistoricalEventTime(AInputEvent* motion_event, - size_t history_index); - -/* Get the historical raw X coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalRawX(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical raw Y coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * For touch events on the screen, this is the original location of the event - * on the screen, before it had been adjusted for the containing window - * and views. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalRawY(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical X coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalX(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical Y coordinate of this event for the given pointer index that - * occurred between this event and the previous motion event. - * Whole numbers are pixels; the value may have a fraction for input devices - * that are sub-pixel precise. */ -float AMotionEvent_getHistoricalY(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical pressure of this event for the given pointer index that - * occurred between this event and the previous motion event. - * The pressure generally ranges from 0 (no pressure at all) to 1 (normal pressure), - * although values higher than 1 may be generated depending on the calibration of - * the input device. */ -float AMotionEvent_getHistoricalPressure(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the current scaled value of the approximate size for the given pointer index that - * occurred between this event and the previous motion event. - * This represents some approximation of the area of the screen being - * pressed; the actual value in pixels corresponding to the - * touch is normalized with the device specific range of values - * and scaled to a value between 0 and 1. The value of size can be used to - * determine fat touch events. */ -float AMotionEvent_getHistoricalSize(AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the major axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index that - * occurred between this event and the previous motion event. */ -float AMotionEvent_getHistoricalTouchMajor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the minor axis of an ellipse that describes the touch area - * at the point of contact for the given pointer index that - * occurred between this event and the previous motion event. */ -float AMotionEvent_getHistoricalTouchMinor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the major axis of an ellipse that describes the size - * of the approaching tool for the given pointer index that - * occurred between this event and the previous motion event. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getHistoricalToolMajor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical length of the minor axis of an ellipse that describes the size - * of the approaching tool for the given pointer index that - * occurred between this event and the previous motion event. - * The tool area represents the estimated size of the finger or pen that is - * touching the device independent of its actual touch area at the point of contact. */ -float AMotionEvent_getHistoricalToolMinor(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical orientation of the touch area and tool area in radians clockwise from - * vertical for the given pointer index that - * occurred between this event and the previous motion event. - * An angle of 0 degrees indicates that the major axis of contact is oriented - * upwards, is perfectly circular or is of unknown orientation. A positive angle - * indicates that the major axis of contact is oriented to the right. A negative angle - * indicates that the major axis of contact is oriented to the left. - * The full range is from -PI/2 radians (finger pointing fully left) to PI/2 radians - * (finger pointing fully right). */ -float AMotionEvent_getHistoricalOrientation(const AInputEvent* motion_event, size_t pointer_index, - size_t history_index); - -/* Get the historical value of the request axis for the given pointer index - * that occurred between this event and the previous motion event. */ -float AMotionEvent_getHistoricalAxisValue(const AInputEvent* motion_event, - int32_t axis, size_t pointer_index, size_t history_index); - - -/* - * Input queue - * - * An input queue is the facility through which you retrieve input - * events. - */ -struct AInputQueue; -typedef struct AInputQueue AInputQueue; - -/* - * Add this input queue to a looper for processing. See - * ALooper_addFd() for information on the ident, callback, and data params. - */ -void AInputQueue_attachLooper(AInputQueue* queue, ALooper* looper, - int ident, ALooper_callbackFunc callback, void* data); - -/* - * Remove the input queue from the looper it is currently attached to. - */ -void AInputQueue_detachLooper(AInputQueue* queue); - -/* - * Returns true if there are one or more events available in the - * input queue. Returns 1 if the queue has events; 0 if - * it does not have events; and a negative value if there is an error. - */ -int32_t AInputQueue_hasEvents(AInputQueue* queue); - -/* - * Returns the next available event from the queue. Returns a negative - * value if no events are available or an error has occurred. - */ -int32_t AInputQueue_getEvent(AInputQueue* queue, AInputEvent** outEvent); - -/* - * Sends the key for standard pre-dispatching -- that is, possibly deliver - * it to the current IME to be consumed before the app. Returns 0 if it - * was not pre-dispatched, meaning you can process it right now. If non-zero - * is returned, you must abandon the current event processing and allow the - * event to appear again in the event queue (if it does not get consumed during - * pre-dispatching). - */ -int32_t AInputQueue_preDispatchEvent(AInputQueue* queue, AInputEvent* event); - -/* - * Report that dispatching has finished with the given event. - * This must be called after receiving an event with AInputQueue_get_event(). - */ -void AInputQueue_finishEvent(AInputQueue* queue, AInputEvent* event, int handled); - -#ifdef __cplusplus -} -#endif - -#endif // _ANDROID_INPUT_H diff --git a/widget/gonk/libui/android_keycodes.h b/widget/gonk/libui/android_keycodes.h deleted file mode 100644 index 9e63d1d01..000000000 --- a/widget/gonk/libui/android_keycodes.h +++ /dev/null @@ -1,315 +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. - */ - -#ifndef _ANDROID_KEYCODES_H -#define _ANDROID_KEYCODES_H - -/****************************************************************** - * - * IMPORTANT NOTICE: - * - * This file is part of Android's set of stable system headers - * exposed by the Android NDK (Native Development Kit). - * - * Third-party source AND binary code relies on the definitions - * here to be FROZEN ON ALL UPCOMING PLATFORM RELEASES. - * - * - DO NOT MODIFY ENUMS (EXCEPT IF YOU ADD NEW 32-BIT VALUES) - * - DO NOT MODIFY CONSTANTS OR FUNCTIONAL MACROS - * - DO NOT CHANGE THE SIGNATURE OF FUNCTIONS IN ANY WAY - * - DO NOT CHANGE THE LAYOUT OR SIZE OF STRUCTURES - */ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Key codes. - */ -enum { - AKEYCODE_UNKNOWN = 0, - AKEYCODE_SOFT_LEFT = 1, - AKEYCODE_SOFT_RIGHT = 2, - AKEYCODE_HOME = 3, - AKEYCODE_BACK = 4, - AKEYCODE_CALL = 5, - AKEYCODE_ENDCALL = 6, - AKEYCODE_0 = 7, - AKEYCODE_1 = 8, - AKEYCODE_2 = 9, - AKEYCODE_3 = 10, - AKEYCODE_4 = 11, - AKEYCODE_5 = 12, - AKEYCODE_6 = 13, - AKEYCODE_7 = 14, - AKEYCODE_8 = 15, - AKEYCODE_9 = 16, - AKEYCODE_STAR = 17, - AKEYCODE_POUND = 18, - AKEYCODE_DPAD_UP = 19, - AKEYCODE_DPAD_DOWN = 20, - AKEYCODE_DPAD_LEFT = 21, - AKEYCODE_DPAD_RIGHT = 22, - AKEYCODE_DPAD_CENTER = 23, - AKEYCODE_VOLUME_UP = 24, - AKEYCODE_VOLUME_DOWN = 25, - AKEYCODE_POWER = 26, - AKEYCODE_CAMERA = 27, - AKEYCODE_CLEAR = 28, - AKEYCODE_A = 29, - AKEYCODE_B = 30, - AKEYCODE_C = 31, - AKEYCODE_D = 32, - AKEYCODE_E = 33, - AKEYCODE_F = 34, - AKEYCODE_G = 35, - AKEYCODE_H = 36, - AKEYCODE_I = 37, - AKEYCODE_J = 38, - AKEYCODE_K = 39, - AKEYCODE_L = 40, - AKEYCODE_M = 41, - AKEYCODE_N = 42, - AKEYCODE_O = 43, - AKEYCODE_P = 44, - AKEYCODE_Q = 45, - AKEYCODE_R = 46, - AKEYCODE_S = 47, - AKEYCODE_T = 48, - AKEYCODE_U = 49, - AKEYCODE_V = 50, - AKEYCODE_W = 51, - AKEYCODE_X = 52, - AKEYCODE_Y = 53, - AKEYCODE_Z = 54, - AKEYCODE_COMMA = 55, - AKEYCODE_PERIOD = 56, - AKEYCODE_ALT_LEFT = 57, - AKEYCODE_ALT_RIGHT = 58, - AKEYCODE_SHIFT_LEFT = 59, - AKEYCODE_SHIFT_RIGHT = 60, - AKEYCODE_TAB = 61, - AKEYCODE_SPACE = 62, - AKEYCODE_SYM = 63, - AKEYCODE_EXPLORER = 64, - AKEYCODE_ENVELOPE = 65, - AKEYCODE_ENTER = 66, - AKEYCODE_DEL = 67, - AKEYCODE_GRAVE = 68, - AKEYCODE_MINUS = 69, - AKEYCODE_EQUALS = 70, - AKEYCODE_LEFT_BRACKET = 71, - AKEYCODE_RIGHT_BRACKET = 72, - AKEYCODE_BACKSLASH = 73, - AKEYCODE_SEMICOLON = 74, - AKEYCODE_APOSTROPHE = 75, - AKEYCODE_SLASH = 76, - AKEYCODE_AT = 77, - AKEYCODE_NUM = 78, - AKEYCODE_HEADSETHOOK = 79, - AKEYCODE_FOCUS = 80, // *Camera* focus - AKEYCODE_PLUS = 81, - AKEYCODE_MENU = 82, - AKEYCODE_NOTIFICATION = 83, - AKEYCODE_SEARCH = 84, - AKEYCODE_MEDIA_PLAY_PAUSE= 85, - AKEYCODE_MEDIA_STOP = 86, - AKEYCODE_MEDIA_NEXT = 87, - AKEYCODE_MEDIA_PREVIOUS = 88, - AKEYCODE_MEDIA_REWIND = 89, - AKEYCODE_MEDIA_FAST_FORWARD = 90, - AKEYCODE_MUTE = 91, - AKEYCODE_PAGE_UP = 92, - AKEYCODE_PAGE_DOWN = 93, - AKEYCODE_PICTSYMBOLS = 94, - AKEYCODE_SWITCH_CHARSET = 95, - AKEYCODE_BUTTON_A = 96, - AKEYCODE_BUTTON_B = 97, - AKEYCODE_BUTTON_C = 98, - AKEYCODE_BUTTON_X = 99, - AKEYCODE_BUTTON_Y = 100, - AKEYCODE_BUTTON_Z = 101, - AKEYCODE_BUTTON_L1 = 102, - AKEYCODE_BUTTON_R1 = 103, - AKEYCODE_BUTTON_L2 = 104, - AKEYCODE_BUTTON_R2 = 105, - AKEYCODE_BUTTON_THUMBL = 106, - AKEYCODE_BUTTON_THUMBR = 107, - AKEYCODE_BUTTON_START = 108, - AKEYCODE_BUTTON_SELECT = 109, - AKEYCODE_BUTTON_MODE = 110, - AKEYCODE_ESCAPE = 111, - AKEYCODE_FORWARD_DEL = 112, - AKEYCODE_CTRL_LEFT = 113, - AKEYCODE_CTRL_RIGHT = 114, - AKEYCODE_CAPS_LOCK = 115, - AKEYCODE_SCROLL_LOCK = 116, - AKEYCODE_META_LEFT = 117, - AKEYCODE_META_RIGHT = 118, - AKEYCODE_FUNCTION = 119, - AKEYCODE_SYSRQ = 120, - AKEYCODE_BREAK = 121, - AKEYCODE_MOVE_HOME = 122, - AKEYCODE_MOVE_END = 123, - AKEYCODE_INSERT = 124, - AKEYCODE_FORWARD = 125, - AKEYCODE_MEDIA_PLAY = 126, - AKEYCODE_MEDIA_PAUSE = 127, - AKEYCODE_MEDIA_CLOSE = 128, - AKEYCODE_MEDIA_EJECT = 129, - AKEYCODE_MEDIA_RECORD = 130, - AKEYCODE_F1 = 131, - AKEYCODE_F2 = 132, - AKEYCODE_F3 = 133, - AKEYCODE_F4 = 134, - AKEYCODE_F5 = 135, - AKEYCODE_F6 = 136, - AKEYCODE_F7 = 137, - AKEYCODE_F8 = 138, - AKEYCODE_F9 = 139, - AKEYCODE_F10 = 140, - AKEYCODE_F11 = 141, - AKEYCODE_F12 = 142, - AKEYCODE_NUM_LOCK = 143, - AKEYCODE_NUMPAD_0 = 144, - AKEYCODE_NUMPAD_1 = 145, - AKEYCODE_NUMPAD_2 = 146, - AKEYCODE_NUMPAD_3 = 147, - AKEYCODE_NUMPAD_4 = 148, - AKEYCODE_NUMPAD_5 = 149, - AKEYCODE_NUMPAD_6 = 150, - AKEYCODE_NUMPAD_7 = 151, - AKEYCODE_NUMPAD_8 = 152, - AKEYCODE_NUMPAD_9 = 153, - AKEYCODE_NUMPAD_DIVIDE = 154, - AKEYCODE_NUMPAD_MULTIPLY = 155, - AKEYCODE_NUMPAD_SUBTRACT = 156, - AKEYCODE_NUMPAD_ADD = 157, - AKEYCODE_NUMPAD_DOT = 158, - AKEYCODE_NUMPAD_COMMA = 159, - AKEYCODE_NUMPAD_ENTER = 160, - AKEYCODE_NUMPAD_EQUALS = 161, - AKEYCODE_NUMPAD_LEFT_PAREN = 162, - AKEYCODE_NUMPAD_RIGHT_PAREN = 163, - AKEYCODE_VOLUME_MUTE = 164, - AKEYCODE_INFO = 165, - AKEYCODE_CHANNEL_UP = 166, - AKEYCODE_CHANNEL_DOWN = 167, - AKEYCODE_ZOOM_IN = 168, - AKEYCODE_ZOOM_OUT = 169, - AKEYCODE_TV = 170, - AKEYCODE_WINDOW = 171, - AKEYCODE_GUIDE = 172, - AKEYCODE_DVR = 173, - AKEYCODE_BOOKMARK = 174, - AKEYCODE_CAPTIONS = 175, - AKEYCODE_SETTINGS = 176, - AKEYCODE_TV_POWER = 177, - AKEYCODE_TV_INPUT = 178, - AKEYCODE_STB_POWER = 179, - AKEYCODE_STB_INPUT = 180, - AKEYCODE_AVR_POWER = 181, - AKEYCODE_AVR_INPUT = 182, - AKEYCODE_PROG_RED = 183, - AKEYCODE_PROG_GREEN = 184, - AKEYCODE_PROG_YELLOW = 185, - AKEYCODE_PROG_BLUE = 186, - AKEYCODE_APP_SWITCH = 187, - AKEYCODE_BUTTON_1 = 188, - AKEYCODE_BUTTON_2 = 189, - AKEYCODE_BUTTON_3 = 190, - AKEYCODE_BUTTON_4 = 191, - AKEYCODE_BUTTON_5 = 192, - AKEYCODE_BUTTON_6 = 193, - AKEYCODE_BUTTON_7 = 194, - AKEYCODE_BUTTON_8 = 195, - AKEYCODE_BUTTON_9 = 196, - AKEYCODE_BUTTON_10 = 197, - AKEYCODE_BUTTON_11 = 198, - AKEYCODE_BUTTON_12 = 199, - AKEYCODE_BUTTON_13 = 200, - AKEYCODE_BUTTON_14 = 201, - AKEYCODE_BUTTON_15 = 202, - AKEYCODE_BUTTON_16 = 203, - AKEYCODE_LANGUAGE_SWITCH = 204, - AKEYCODE_MANNER_MODE = 205, - AKEYCODE_3D_MODE = 206, - AKEYCODE_CONTACTS = 207, - AKEYCODE_CALENDAR = 208, - AKEYCODE_MUSIC = 209, - AKEYCODE_CALCULATOR = 210, - AKEYCODE_ZENKAKU_HANKAKU = 211, - AKEYCODE_EISU = 212, - AKEYCODE_MUHENKAN = 213, - AKEYCODE_HENKAN = 214, - AKEYCODE_KATAKANA_HIRAGANA = 215, - AKEYCODE_YEN = 216, - AKEYCODE_RO = 217, - AKEYCODE_KANA = 218, - AKEYCODE_ASSIST = 219, - AKEYCODE_BRIGHTNESS_DOWN = 220, - AKEYCODE_BRIGHTNESS_UP = 221, - AKEYCODE_MEDIA_AUDIO_TRACK = 222, - AKEYCODE_SLEEP = 223, - AKEYCODE_WAKEUP = 224, - AKEYCODE_PAIRING = 225, - AKEYCODE_MEDIA_TOP_MENU = 226, - AKEYCODE_11 = 227, - AKEYCODE_12 = 228, - AKEYCODE_LAST_CHANNEL = 229, - AKEYCODE_TV_DATA_SERVICE = 230, - AKEYCODE_VOICE_ASSIST = 231, - AKEYCODE_TV_RADIO_SERVICE = 232, - AKEYCODE_TV_TELETEXT = 233, - AKEYCODE_TV_NUMBER_ENTRY = 234, - AKEYCODE_TV_TERRESTRIAL_ANALOG = 235, - AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236, - AKEYCODE_TV_SATELLITE = 237, - AKEYCODE_TV_SATELLITE_BS = 238, - AKEYCODE_TV_SATELLITE_CS = 239, - AKEYCODE_TV_SATELLITE_SERVICE = 240, - AKEYCODE_TV_NETWORK = 241, - AKEYCODE_TV_ANTENNA_CABLE = 242, - AKEYCODE_TV_INPUT_HDMI_1 = 243, - AKEYCODE_TV_INPUT_HDMI_2 = 244, - AKEYCODE_TV_INPUT_HDMI_3 = 245, - AKEYCODE_TV_INPUT_HDMI_4 = 246, - AKEYCODE_TV_INPUT_COMPOSITE_1 = 247, - AKEYCODE_TV_INPUT_COMPOSITE_2 = 248, - AKEYCODE_TV_INPUT_COMPONENT_1 = 249, - AKEYCODE_TV_INPUT_COMPONENT_2 = 250, - AKEYCODE_TV_INPUT_VGA_1 = 251, - AKEYCODE_TV_AUDIO_DESCRIPTION = 252, - AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253, - AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254, - AKEYCODE_TV_ZOOM_MODE = 255, - AKEYCODE_TV_CONTENTS_MENU = 256, - AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257, - AKEYCODE_TV_TIMER_PROGRAMMING = 258, - AKEYCODE_HELP = 259, - - // NOTE: If you add a new keycode here you must also add it to several other files. - // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. -}; - -#ifdef __cplusplus -} -#endif - -#endif // _ANDROID_KEYCODES_H diff --git a/widget/gonk/libui/cutils_log.h b/widget/gonk/libui/cutils_log.h deleted file mode 100644 index f4252c867..000000000 --- a/widget/gonk/libui/cutils_log.h +++ /dev/null @@ -1,569 +0,0 @@ -/* - * Copyright (C) 2005 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. - */ - -// -// C/C++ logging functions. See the logging documentation for API details. -// -// We'd like these to be available from C code (in case we import some from -// somewhere), so this has a C interface. -// -// The output will be correct when the log file is shared between multiple -// threads and/or multiple processes so long as the operating system -// supports O_APPEND. These calls have mutex-protected data structures -// and so are NOT reentrant. Do not use LOG in a signal handler. -// -#if !defined(_LIBS_CUTILS_LOG_H) && !defined(_LIBS_LOG_LOG_H) -#define _LIBS_LOG_LOG_H -#define _LIBS_CUTILS_LOG_H - -#include -#include -#include -#include -#ifdef HAVE_PTHREADS -#include -#endif -#include - -#if ANDROID_VERSION >= 19 -#include -#include -#else -#include -#include -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -// --------------------------------------------------------------------- - -/* - * Normally we strip ALOGV (VERBOSE messages) from release builds. - * You can modify this (for example with "#define LOG_NDEBUG 0" - * at the top of your source file) to change that behavior. - */ -#ifndef LOG_NDEBUG -#ifdef NDEBUG -#define LOG_NDEBUG 1 -#else -#define LOG_NDEBUG 0 -#endif -#endif - -/* - * This is the local tag used for the following simplified - * logging macros. You can change this preprocessor definition - * before using the other macros to change the tag. - */ -#ifndef LOG_TAG -#define LOG_TAG NULL -#endif - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose log message using the current LOG_TAG. - */ -#ifndef ALOGV -#if LOG_NDEBUG -#define ALOGV(...) ((void)0) -#else -#define ALOGV(...) ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - -#ifndef ALOGV_IF -#if LOG_NDEBUG -#define ALOGV_IF(cond, ...) ((void)0) -#else -#define ALOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug log message using the current LOG_TAG. - */ -#ifndef ALOGD -#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGD_IF -#define ALOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info log message using the current LOG_TAG. - */ -#ifndef ALOGI -#define ALOGI(...) ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGI_IF -#define ALOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning log message using the current LOG_TAG. - */ -#ifndef ALOGW -#define ALOGW(...) ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGW_IF -#define ALOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error log message using the current LOG_TAG. - */ -#ifndef ALOGE -#define ALOGE(...) ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef ALOGE_IF -#define ALOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)ALOG(LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -// --------------------------------------------------------------------- - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * verbose priority. - */ -#ifndef IF_ALOGV -#if LOG_NDEBUG -#define IF_ALOGV() if (false) -#else -#define IF_ALOGV() IF_ALOG(LOG_VERBOSE, LOG_TAG) -#endif -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * debug priority. - */ -#ifndef IF_ALOGD -#define IF_ALOGD() IF_ALOG(LOG_DEBUG, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * info priority. - */ -#ifndef IF_ALOGI -#define IF_ALOGI() IF_ALOG(LOG_INFO, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * warn priority. - */ -#ifndef IF_ALOGW -#define IF_ALOGW() IF_ALOG(LOG_WARN, LOG_TAG) -#endif - -/* - * Conditional based on whether the current LOG_TAG is enabled at - * error priority. - */ -#ifndef IF_ALOGE -#define IF_ALOGE() IF_ALOG(LOG_ERROR, LOG_TAG) -#endif - - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose system log message using the current LOG_TAG. - */ -#ifndef SLOGV -#if LOG_NDEBUG -#define SLOGV(...) ((void)0) -#else -#define SLOGV(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - -#ifndef SLOGV_IF -#if LOG_NDEBUG -#define SLOGV_IF(cond, ...) ((void)0) -#else -#define SLOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug system log message using the current LOG_TAG. - */ -#ifndef SLOGD -#define SLOGD(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGD_IF -#define SLOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info system log message using the current LOG_TAG. - */ -#ifndef SLOGI -#define SLOGI(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGI_IF -#define SLOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning system log message using the current LOG_TAG. - */ -#ifndef SLOGW -#define SLOGW(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGW_IF -#define SLOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error system log message using the current LOG_TAG. - */ -#ifndef SLOGE -#define SLOGE(...) ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef SLOGE_IF -#define SLOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_SYSTEM, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -// --------------------------------------------------------------------- - -/* - * Simplified macro to send a verbose radio log message using the current LOG_TAG. - */ -#ifndef RLOGV -#if LOG_NDEBUG -#define RLOGV(...) ((void)0) -#else -#define RLOGV(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) -#endif -#endif - -#define CONDITION(cond) (__builtin_expect((cond)!=0, 0)) - -#ifndef RLOGV_IF -#if LOG_NDEBUG -#define RLOGV_IF(cond, ...) ((void)0) -#else -#define RLOGV_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif -#endif - -/* - * Simplified macro to send a debug radio log message using the current LOG_TAG. - */ -#ifndef RLOGD -#define RLOGD(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGD_IF -#define RLOGD_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an info radio log message using the current LOG_TAG. - */ -#ifndef RLOGI -#define RLOGI(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGI_IF -#define RLOGI_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send a warning radio log message using the current LOG_TAG. - */ -#ifndef RLOGW -#define RLOGW(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGW_IF -#define RLOGW_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - -/* - * Simplified macro to send an error radio log message using the current LOG_TAG. - */ -#ifndef RLOGE -#define RLOGE(...) ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) -#endif - -#ifndef RLOGE_IF -#define RLOGE_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)__android_log_buf_print(LOG_ID_RADIO, ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) \ - : (void)0 ) -#endif - - -// --------------------------------------------------------------------- - -/* - * Log a fatal error. If the given condition fails, this stops program - * execution like a normal assertion, but also generating the given message. - * It is NOT stripped from release builds. Note that the condition test - * is -inverted- from the normal assert() semantics. - */ -#ifndef LOG_ALWAYS_FATAL_IF -#define LOG_ALWAYS_FATAL_IF(cond, ...) \ - ( (CONDITION(cond)) \ - ? ((void)android_printAssert(#cond, LOG_TAG, ## __VA_ARGS__)) \ - : (void)0 ) -#endif - -#ifndef LOG_ALWAYS_FATAL -#define LOG_ALWAYS_FATAL(...) \ - ( ((void)android_printAssert(NULL, LOG_TAG, ## __VA_ARGS__)) ) -#endif - -/* - * Versions of LOG_ALWAYS_FATAL_IF and LOG_ALWAYS_FATAL that - * are stripped out of release builds. - */ -#if LOG_NDEBUG - -#ifndef LOG_FATAL_IF -#define LOG_FATAL_IF(cond, ...) ((void)0) -#endif -#ifndef LOG_FATAL -#define LOG_FATAL(...) ((void)0) -#endif - -#else - -#ifndef LOG_FATAL_IF -#define LOG_FATAL_IF(cond, ...) LOG_ALWAYS_FATAL_IF(cond, ## __VA_ARGS__) -#endif -#ifndef LOG_FATAL -#define LOG_FATAL(...) LOG_ALWAYS_FATAL(__VA_ARGS__) -#endif - -#endif - -/* - * Assertion that generates a log message when the assertion fails. - * Stripped out of release builds. Uses the current LOG_TAG. - */ -#ifndef ALOG_ASSERT -#define ALOG_ASSERT(cond, ...) LOG_FATAL_IF(!(cond), ## __VA_ARGS__) -//#define ALOG_ASSERT(cond) LOG_FATAL_IF(!(cond), "Assertion failed: " #cond) -#endif - -// --------------------------------------------------------------------- - -/* - * Basic log message macro. - * - * Example: - * ALOG(LOG_WARN, NULL, "Failed with error %d", errno); - * - * The second argument may be NULL or "" to indicate the "global" tag. - */ -#ifndef ALOG -#define ALOG(priority, tag, ...) \ - LOG_PRI(ANDROID_##priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to specify a number for the priority. - */ -#ifndef LOG_PRI -#define LOG_PRI(priority, tag, ...) \ - android_printLog(priority, tag, __VA_ARGS__) -#endif - -/* - * Log macro that allows you to pass in a varargs ("args" is a va_list). - */ -#ifndef LOG_PRI_VA -#define LOG_PRI_VA(priority, tag, fmt, args) \ - android_vprintLog(priority, NULL, tag, fmt, args) -#endif - -/* - * Conditional given a desired logging priority and tag. - */ -#ifndef IF_ALOG -#define IF_ALOG(priority, tag) \ - if (android_testLog(ANDROID_##priority, tag)) -#endif - -// --------------------------------------------------------------------- - -/* - * Event logging. - */ - -/* - * Event log entry types. These must match up with the declarations in - * java/android/android/util/EventLog.java. - */ -typedef enum { - EVENT_TYPE_INT = 0, - EVENT_TYPE_LONG = 1, - EVENT_TYPE_STRING = 2, - EVENT_TYPE_LIST = 3, -} AndroidEventLogType; - - -#ifndef LOG_EVENT_INT -#define LOG_EVENT_INT(_tag, _value) { \ - int intBuf = _value; \ - (void) android_btWriteLog(_tag, EVENT_TYPE_INT, &intBuf, \ - sizeof(intBuf)); \ - } -#endif -#ifndef LOG_EVENT_LONG -#define LOG_EVENT_LONG(_tag, _value) { \ - long long longBuf = _value; \ - (void) android_btWriteLog(_tag, EVENT_TYPE_LONG, &longBuf, \ - sizeof(longBuf)); \ - } -#endif -#ifndef LOG_EVENT_STRING -#define LOG_EVENT_STRING(_tag, _value) \ - ((void) 0) /* not implemented -- must combine len with string */ -#endif -/* TODO: something for LIST */ - -/* - * =========================================================================== - * - * The stuff in the rest of this file should not be used directly. - */ - -#define android_printLog(prio, tag, fmt...) \ - __android_log_print(prio, tag, fmt) - -#define android_vprintLog(prio, cond, tag, fmt...) \ - __android_log_vprint(prio, tag, fmt) - -/* XXX Macros to work around syntax errors in places where format string - * arg is not passed to ALOG_ASSERT, LOG_ALWAYS_FATAL or LOG_ALWAYS_FATAL_IF - * (happens only in debug builds). - */ - -/* Returns 2nd arg. Used to substitute default value if caller's vararg list - * is empty. - */ -#define __android_second(dummy, second, ...) second - -/* If passed multiple args, returns ',' followed by all but 1st arg, otherwise - * returns nothing. - */ -#define __android_rest(first, ...) , ## __VA_ARGS__ - -#define android_printAssert(cond, tag, fmt...) \ - __android_log_assert(cond, tag, \ - __android_second(0, ## fmt, NULL) __android_rest(fmt)) - -#define android_writeLog(prio, tag, text) \ - __android_log_write(prio, tag, text) - -#define android_bWriteLog(tag, payload, len) \ - __android_log_bwrite(tag, payload, len) -#define android_btWriteLog(tag, type, payload, len) \ - __android_log_btwrite(tag, type, payload, len) - -// TODO: remove these prototypes and their users -#define android_testLog(prio, tag) (1) -#define android_writevLog(vec,num) do{}while(0) -#define android_write1Log(str,len) do{}while (0) -#define android_setMinPriority(tag, prio) do{}while(0) -//#define android_logToCallback(func) do{}while(0) -#define android_logToFile(tag, file) (0) -#define android_logToFd(tag, fd) (0) - -typedef enum { - LOG_ID_MAIN = 0, - LOG_ID_RADIO = 1, - LOG_ID_EVENTS = 2, - LOG_ID_SYSTEM = 3, - - LOG_ID_MAX -} log_id_t; - -/* - * Send a simple string to the log. - */ -int __android_log_buf_write(int bufID, int prio, const char *tag, const char *text); -int __android_log_buf_print(int bufID, int prio, const char *tag, const char *fmt, ...); - - -#ifdef __cplusplus -} -#endif - -#endif // _LIBS_CUTILS_LOG_H diff --git a/widget/gonk/libui/cutils_trace.h b/widget/gonk/libui/cutils_trace.h deleted file mode 100644 index 29034cab5..000000000 --- a/widget/gonk/libui/cutils_trace.h +++ /dev/null @@ -1,276 +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. - */ - -#ifndef _LIBS_CUTILS_TRACE_H -#define _LIBS_CUTILS_TRACE_H - -#include -#include -#include -#include -#include -#include - -#ifdef ANDROID_SMP -#include -#else -#include -#endif - -__BEGIN_DECLS - -/** - * The ATRACE_TAG macro can be defined before including this header to trace - * using one of the tags defined below. It must be defined to one of the - * following ATRACE_TAG_* macros. The trace tag is used to filter tracing in - * userland to avoid some of the runtime cost of tracing when it is not desired. - * - * Defining ATRACE_TAG to be ATRACE_TAG_ALWAYS will result in the tracing always - * being enabled - this should ONLY be done for debug code, as userland tracing - * has a performance cost even when the trace is not being recorded. Defining - * ATRACE_TAG to be ATRACE_TAG_NEVER or leaving ATRACE_TAG undefined will result - * in the tracing always being disabled. - * - * ATRACE_TAG_HAL should be bitwise ORed with the relevant tags for tracing - * within a hardware module. For example a camera hardware module would set: - * #define ATRACE_TAG (ATRACE_TAG_CAMERA | ATRACE_TAG_HAL) - * - * Keep these in sync with frameworks/base/core/java/android/os/Trace.java. - */ -#define ATRACE_TAG_NEVER 0 // This tag is never enabled. -#define ATRACE_TAG_ALWAYS (1<<0) // This tag is always enabled. -#define ATRACE_TAG_GRAPHICS (1<<1) -#define ATRACE_TAG_INPUT (1<<2) -#define ATRACE_TAG_VIEW (1<<3) -#define ATRACE_TAG_WEBVIEW (1<<4) -#define ATRACE_TAG_WINDOW_MANAGER (1<<5) -#define ATRACE_TAG_ACTIVITY_MANAGER (1<<6) -#define ATRACE_TAG_SYNC_MANAGER (1<<7) -#define ATRACE_TAG_AUDIO (1<<8) -#define ATRACE_TAG_VIDEO (1<<9) -#define ATRACE_TAG_CAMERA (1<<10) -#define ATRACE_TAG_HAL (1<<11) -#define ATRACE_TAG_APP (1<<12) -#define ATRACE_TAG_RESOURCES (1<<13) -#define ATRACE_TAG_DALVIK (1<<14) -#define ATRACE_TAG_LAST ATRACE_TAG_DALVIK - -// Reserved for initialization. -#define ATRACE_TAG_NOT_READY (1LL<<63) - -#define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST) - -#ifndef ATRACE_TAG -#define ATRACE_TAG ATRACE_TAG_NEVER -#elif ATRACE_TAG > ATRACE_TAG_VALID_MASK -#error ATRACE_TAG must be defined to be one of the tags defined in cutils/trace.h -#endif - -#ifdef HAVE_ANDROID_OS -/** - * Maximum size of a message that can be logged to the trace buffer. - * Note this message includes a tag, the pid, and the string given as the name. - * Names should be kept short to get the most use of the trace buffer. - */ -#define ATRACE_MESSAGE_LENGTH 1024 - -/** - * Opens the trace file for writing and reads the property for initial tags. - * The atrace.tags.enableflags property sets the tags to trace. - * This function should not be explicitly called, the first call to any normal - * trace function will cause it to be run safely. - */ -void atrace_setup(); - -/** - * If tracing is ready, set atrace_enabled_tags to the system property - * debug.atrace.tags.enableflags. Can be used as a sysprop change callback. - */ -void atrace_update_tags(); - -/** - * Set whether the process is debuggable. By default the process is not - * considered debuggable. If the process is not debuggable then application- - * level tracing is not allowed unless the ro.debuggable system property is - * set to '1'. - */ -void atrace_set_debuggable(bool debuggable); - -/** - * Set whether tracing is enabled for the current process. This is used to - * prevent tracing within the Zygote process. - */ -void atrace_set_tracing_enabled(bool enabled); - -/** - * Flag indicating whether setup has been completed, initialized to 0. - * Nonzero indicates setup has completed. - * Note: This does NOT indicate whether or not setup was successful. - */ -extern volatile int32_t atrace_is_ready; - -/** - * Set of ATRACE_TAG flags to trace for, initialized to ATRACE_TAG_NOT_READY. - * A value of zero indicates setup has failed. - * Any other nonzero value indicates setup has succeeded, and tracing is on. - */ -extern uint64_t atrace_enabled_tags; - -/** - * Handle to the kernel's trace buffer, initialized to -1. - * Any other value indicates setup has succeeded, and is a valid fd for tracing. - */ -extern int atrace_marker_fd; - -/** - * atrace_init readies the process for tracing by opening the trace_marker file. - * Calling any trace function causes this to be run, so calling it is optional. - * This can be explicitly run to avoid setup delay on first trace function. - */ -#define ATRACE_INIT() atrace_init() -static inline void atrace_init() -{ - if (CC_UNLIKELY(!android_atomic_acquire_load(&atrace_is_ready))) { - atrace_setup(); - } -} - -/** - * Get the mask of all tags currently enabled. - * It can be used as a guard condition around more expensive trace calculations. - * Every trace function calls this, which ensures atrace_init is run. - */ -#define ATRACE_GET_ENABLED_TAGS() atrace_get_enabled_tags() -static inline uint64_t atrace_get_enabled_tags() -{ - atrace_init(); - return atrace_enabled_tags; -} - -/** - * Test if a given tag is currently enabled. - * Returns nonzero if the tag is enabled, otherwise zero. - * It can be used as a guard condition around more expensive trace calculations. - */ -#define ATRACE_ENABLED() atrace_is_tag_enabled(ATRACE_TAG) -static inline uint64_t atrace_is_tag_enabled(uint64_t tag) -{ - return atrace_get_enabled_tags() & tag; -} - -/** - * Trace the beginning of a context. name is used to identify the context. - * This is often used to time function execution. - */ -#define ATRACE_BEGIN(name) atrace_begin(ATRACE_TAG, name) -static inline void atrace_begin(uint64_t tag, const char* name) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "B|%d|%s", getpid(), name); - write(atrace_marker_fd, buf, len); - } -} - -/** - * Trace the end of a context. - * This should match up (and occur after) a corresponding ATRACE_BEGIN. - */ -#define ATRACE_END() atrace_end(ATRACE_TAG) -static inline void atrace_end(uint64_t tag) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char c = 'E'; - write(atrace_marker_fd, &c, 1); - } -} - -/** - * Trace the beginning of an asynchronous event. Unlike ATRACE_BEGIN/ATRACE_END - * contexts, asynchronous events do not need to be nested. The name describes - * the event, and the cookie provides a unique identifier for distinguishing - * simultaneous events. The name and cookie used to begin an event must be - * used to end it. - */ -#define ATRACE_ASYNC_BEGIN(name, cookie) \ - atrace_async_begin(ATRACE_TAG, name, cookie) -static inline void atrace_async_begin(uint64_t tag, const char* name, - int32_t cookie) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "S|%d|%s|%d", getpid(), - name, cookie); - write(atrace_marker_fd, buf, len); - } -} - -/** - * Trace the end of an asynchronous event. - * This should have a corresponding ATRACE_ASYNC_BEGIN. - */ -#define ATRACE_ASYNC_END(name, cookie) atrace_async_end(ATRACE_TAG, name, cookie) -static inline void atrace_async_end(uint64_t tag, const char* name, - int32_t cookie) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "F|%d|%s|%d", getpid(), - name, cookie); - write(atrace_marker_fd, buf, len); - } -} - - -/** - * Traces an integer counter value. name is used to identify the counter. - * This can be used to track how a value changes over time. - */ -#define ATRACE_INT(name, value) atrace_int(ATRACE_TAG, name, value) -static inline void atrace_int(uint64_t tag, const char* name, int32_t value) -{ - if (CC_UNLIKELY(atrace_is_tag_enabled(tag))) { - char buf[ATRACE_MESSAGE_LENGTH]; - size_t len; - - len = snprintf(buf, ATRACE_MESSAGE_LENGTH, "C|%d|%s|%d", - getpid(), name, value); - write(atrace_marker_fd, buf, len); - } -} - -#else // not HAVE_ANDROID_OS - -#define ATRACE_INIT() -#define ATRACE_GET_ENABLED_TAGS() -#define ATRACE_ENABLED() -#define ATRACE_BEGIN(name) -#define ATRACE_END() -#define ATRACE_ASYNC_BEGIN(name, cookie) -#define ATRACE_ASYNC_END(name, cookie) -#define ATRACE_INT(name, value) - -#endif // not HAVE_ANDROID_OS - -__END_DECLS - -#endif // _LIBS_CUTILS_TRACE_H diff --git a/widget/gonk/libui/linux_input.h b/widget/gonk/libui/linux_input.h deleted file mode 100644 index 2ba14973f..000000000 --- a/widget/gonk/libui/linux_input.h +++ /dev/null @@ -1,1029 +0,0 @@ -/**************************************************************************** - **************************************************************************** - *** - *** This header was automatically generated from a Linux kernel header - *** of the same name, to make information necessary for userspace to - *** call into the kernel available to libc. It contains only constants, - *** structures, and macros generated from the original header, and thus, - *** contains no copyrightable information. - *** - *** To edit the content of this header, modify the corresponding - *** source file (e.g. under external/kernel-headers/original/) then - *** run bionic/libc/kernel/tools/update_all.py - *** - *** Any manual change here will be lost the next time this script will - *** be run. You've been warned! - *** - **************************************************************************** - ****************************************************************************/ -#ifndef _INPUT_H -#define _INPUT_H -#include -#include -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#include -#include -struct input_event { - struct timeval time; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 type; - __u16 code; - __s32 value; -}; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_VERSION 0x010001 -struct input_id { - __u16 bustype; - __u16 vendor; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 product; - __u16 version; -}; -struct input_absinfo { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __s32 value; - __s32 minimum; - __s32 maximum; - __s32 fuzz; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __s32 flat; - __s32 resolution; -}; -struct input_keymap_entry { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define INPUT_KEYMAP_BY_INDEX (1 << 0) - __u8 flags; - __u8 len; - __u16 index; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u32 keycode; - __u8 scancode[32]; -}; -#define EVIOCGVERSION _IOR('E', 0x01, int) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGID _IOR('E', 0x02, struct input_id) -#define EVIOCGREP _IOR('E', 0x03, unsigned int[2]) -#define EVIOCSREP _IOW('E', 0x03, unsigned int[2]) -#define EVIOCGKEYCODE _IOR('E', 0x04, unsigned int[2]) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGKEYCODE_V2 _IOR('E', 0x04, struct input_keymap_entry) -#define EVIOCSKEYCODE _IOW('E', 0x04, unsigned int[2]) -#define EVIOCSKEYCODE_V2 _IOW('E', 0x04, struct input_keymap_entry) -#define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) -#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) -#define EVIOCGPROP(len) _IOC(_IOC_READ, 'E', 0x09, len) -#define EVIOCGMTSLOTS(len) _IOC(_IOC_READ, 'E', 0x0a, len) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) -#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) -#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) -#define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) -#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) -#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) -#define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCRMFF _IOW('E', 0x81, int) -#define EVIOCGEFFECTS _IOR('E', 0x84, int) -#define EVIOCGRAB _IOW('E', 0x90, int) -#define EVIOCGSUSPENDBLOCK _IOR('E', 0x91, int) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EVIOCSSUSPENDBLOCK _IOW('E', 0x91, int) -#define EVIOCSCLOCKID _IOW('E', 0xa0, int) -#define INPUT_PROP_POINTER 0x00 -#define INPUT_PROP_DIRECT 0x01 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define INPUT_PROP_BUTTONPAD 0x02 -#define INPUT_PROP_SEMI_MT 0x03 -#define INPUT_PROP_MAX 0x1f -#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_SYN 0x00 -#define EV_KEY 0x01 -#define EV_REL 0x02 -#define EV_ABS 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_MSC 0x04 -#define EV_SW 0x05 -#define EV_LED 0x11 -#define EV_SND 0x12 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_REP 0x14 -#define EV_FF 0x15 -#define EV_PWR 0x16 -#define EV_FF_STATUS 0x17 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define EV_MAX 0x1f -#define EV_CNT (EV_MAX+1) -#define SYN_REPORT 0 -#define SYN_CONFIG 1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SYN_MT_REPORT 2 -#define SYN_DROPPED 3 -#define SYN_TIME_SEC 4 -#define SYN_TIME_NSEC 5 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RESERVED 0 -#define KEY_ESC 1 -#define KEY_1 2 -#define KEY_2 3 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_3 4 -#define KEY_4 5 -#define KEY_5 6 -#define KEY_6 7 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_7 8 -#define KEY_8 9 -#define KEY_9 10 -#define KEY_0 11 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MINUS 12 -#define KEY_EQUAL 13 -#define KEY_BACKSPACE 14 -#define KEY_TAB 15 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_Q 16 -#define KEY_W 17 -#define KEY_E 18 -#define KEY_R 19 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_T 20 -#define KEY_Y 21 -#define KEY_U 22 -#define KEY_I 23 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_O 24 -#define KEY_P 25 -#define KEY_LEFTBRACE 26 -#define KEY_RIGHTBRACE 27 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_ENTER 28 -#define KEY_LEFTCTRL 29 -#define KEY_A 30 -#define KEY_S 31 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_D 32 -#define KEY_F 33 -#define KEY_G 34 -#define KEY_H 35 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_J 36 -#define KEY_K 37 -#define KEY_L 38 -#define KEY_SEMICOLON 39 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_APOSTROPHE 40 -#define KEY_GRAVE 41 -#define KEY_LEFTSHIFT 42 -#define KEY_BACKSLASH 43 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_Z 44 -#define KEY_X 45 -#define KEY_C 46 -#define KEY_V 47 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_B 48 -#define KEY_N 49 -#define KEY_M 50 -#define KEY_COMMA 51 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DOT 52 -#define KEY_SLASH 53 -#define KEY_RIGHTSHIFT 54 -#define KEY_KPASTERISK 55 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_LEFTALT 56 -#define KEY_SPACE 57 -#define KEY_CAPSLOCK 58 -#define KEY_F1 59 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F2 60 -#define KEY_F3 61 -#define KEY_F4 62 -#define KEY_F5 63 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F6 64 -#define KEY_F7 65 -#define KEY_F8 66 -#define KEY_F9 67 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F10 68 -#define KEY_NUMLOCK 69 -#define KEY_SCROLLLOCK 70 -#define KEY_KP7 71 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KP8 72 -#define KEY_KP9 73 -#define KEY_KPMINUS 74 -#define KEY_KP4 75 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KP5 76 -#define KEY_KP6 77 -#define KEY_KPPLUS 78 -#define KEY_KP1 79 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KP2 80 -#define KEY_KP3 81 -#define KEY_KP0 82 -#define KEY_KPDOT 83 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_ZENKAKUHANKAKU 85 -#define KEY_102ND 86 -#define KEY_F11 87 -#define KEY_F12 88 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RO 89 -#define KEY_KATAKANA 90 -#define KEY_HIRAGANA 91 -#define KEY_HENKAN 92 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KATAKANAHIRAGANA 93 -#define KEY_MUHENKAN 94 -#define KEY_KPJPCOMMA 95 -#define KEY_KPENTER 96 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RIGHTCTRL 97 -#define KEY_KPSLASH 98 -#define KEY_SYSRQ 99 -#define KEY_RIGHTALT 100 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_LINEFEED 101 -#define KEY_HOME 102 -#define KEY_UP 103 -#define KEY_PAGEUP 104 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_LEFT 105 -#define KEY_RIGHT 106 -#define KEY_END 107 -#define KEY_DOWN 108 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PAGEDOWN 109 -#define KEY_INSERT 110 -#define KEY_DELETE 111 -#define KEY_MACRO 112 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MUTE 113 -#define KEY_VOLUMEDOWN 114 -#define KEY_VOLUMEUP 115 -#define KEY_POWER 116 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KPEQUAL 117 -#define KEY_KPPLUSMINUS 118 -#define KEY_PAUSE 119 -#define KEY_SCALE 120 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KPCOMMA 121 -#define KEY_HANGEUL 122 -#define KEY_HANGUEL KEY_HANGEUL -#define KEY_HANJA 123 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_YEN 124 -#define KEY_LEFTMETA 125 -#define KEY_RIGHTMETA 126 -#define KEY_COMPOSE 127 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_STOP 128 -#define KEY_AGAIN 129 -#define KEY_PROPS 130 -#define KEY_UNDO 131 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FRONT 132 -#define KEY_COPY 133 -#define KEY_OPEN 134 -#define KEY_PASTE 135 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FIND 136 -#define KEY_CUT 137 -#define KEY_HELP 138 -#define KEY_MENU 139 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CALC 140 -#define KEY_SETUP 141 -#define KEY_SLEEP 142 -#define KEY_WAKEUP 143 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FILE 144 -#define KEY_SENDFILE 145 -#define KEY_DELETEFILE 146 -#define KEY_XFER 147 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PROG1 148 -#define KEY_PROG2 149 -#define KEY_WWW 150 -#define KEY_MSDOS 151 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_COFFEE 152 -#define KEY_SCREENLOCK KEY_COFFEE -#define KEY_DIRECTION 153 -#define KEY_CYCLEWINDOWS 154 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MAIL 155 -#define KEY_BOOKMARKS 156 -#define KEY_COMPUTER 157 -#define KEY_BACK 158 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FORWARD 159 -#define KEY_CLOSECD 160 -#define KEY_EJECTCD 161 -#define KEY_EJECTCLOSECD 162 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NEXTSONG 163 -#define KEY_PLAYPAUSE 164 -#define KEY_PREVIOUSSONG 165 -#define KEY_STOPCD 166 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RECORD 167 -#define KEY_REWIND 168 -#define KEY_PHONE 169 -#define KEY_ISO 170 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CONFIG 171 -#define KEY_HOMEPAGE 172 -#define KEY_REFRESH 173 -#define KEY_EXIT 174 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MOVE 175 -#define KEY_EDIT 176 -#define KEY_SCROLLUP 177 -#define KEY_SCROLLDOWN 178 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KPLEFTPAREN 179 -#define KEY_KPRIGHTPAREN 180 -#define KEY_NEW 181 -#define KEY_REDO 182 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F13 183 -#define KEY_F14 184 -#define KEY_F15 185 -#define KEY_F16 186 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F17 187 -#define KEY_F18 188 -#define KEY_F19 189 -#define KEY_F20 190 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_F21 191 -#define KEY_F22 192 -#define KEY_F23 193 -#define KEY_F24 194 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PLAYCD 200 -#define KEY_PAUSECD 201 -#define KEY_PROG3 202 -#define KEY_PROG4 203 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DASHBOARD 204 -#define KEY_SUSPEND 205 -#define KEY_CLOSE 206 -#define KEY_PLAY 207 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FASTFORWARD 208 -#define KEY_BASSBOOST 209 -#define KEY_PRINT 210 -#define KEY_HP 211 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CAMERA 212 -#define KEY_SOUND 213 -#define KEY_QUESTION 214 -#define KEY_EMAIL 215 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CHAT 216 -#define KEY_SEARCH 217 -#define KEY_CONNECT 218 -#define KEY_FINANCE 219 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SPORT 220 -#define KEY_SHOP 221 -#define KEY_ALTERASE 222 -#define KEY_CANCEL 223 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRIGHTNESSDOWN 224 -#define KEY_BRIGHTNESSUP 225 -#define KEY_MEDIA 226 -#define KEY_SWITCHVIDEOMODE 227 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KBDILLUMTOGGLE 228 -#define KEY_KBDILLUMDOWN 229 -#define KEY_KBDILLUMUP 230 -#define KEY_SEND 231 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_REPLY 232 -#define KEY_FORWARDMAIL 233 -#define KEY_SAVE 234 -#define KEY_DOCUMENTS 235 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BATTERY 236 -#define KEY_BLUETOOTH 237 -#define KEY_WLAN 238 -#define KEY_UWB 239 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_UNKNOWN 240 -#define KEY_VIDEO_NEXT 241 -#define KEY_VIDEO_PREV 242 -#define KEY_BRIGHTNESS_CYCLE 243 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRIGHTNESS_ZERO 244 -#define KEY_DISPLAY_OFF 245 -#define KEY_WIMAX 246 -#define KEY_RFKILL 247 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MICMUTE 248 -#define BTN_MISC 0x100 -#define BTN_0 0x100 -#define BTN_1 0x101 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_2 0x102 -#define BTN_3 0x103 -#define BTN_4 0x104 -#define BTN_5 0x105 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_6 0x106 -#define BTN_7 0x107 -#define BTN_8 0x108 -#define BTN_9 0x109 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_MOUSE 0x110 -#define BTN_LEFT 0x110 -#define BTN_RIGHT 0x111 -#define BTN_MIDDLE 0x112 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_SIDE 0x113 -#define BTN_EXTRA 0x114 -#define BTN_FORWARD 0x115 -#define BTN_BACK 0x116 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TASK 0x117 -#define BTN_JOYSTICK 0x120 -#define BTN_TRIGGER 0x120 -#define BTN_THUMB 0x121 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_THUMB2 0x122 -#define BTN_TOP 0x123 -#define BTN_TOP2 0x124 -#define BTN_PINKIE 0x125 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_BASE 0x126 -#define BTN_BASE2 0x127 -#define BTN_BASE3 0x128 -#define BTN_BASE4 0x129 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_BASE5 0x12a -#define BTN_BASE6 0x12b -#define BTN_DEAD 0x12f -#define BTN_GAMEPAD 0x130 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_A 0x130 -#define BTN_B 0x131 -#define BTN_C 0x132 -#define BTN_X 0x133 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_Y 0x134 -#define BTN_Z 0x135 -#define BTN_TL 0x136 -#define BTN_TR 0x137 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TL2 0x138 -#define BTN_TR2 0x139 -#define BTN_SELECT 0x13a -#define BTN_START 0x13b -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_MODE 0x13c -#define BTN_THUMBL 0x13d -#define BTN_THUMBR 0x13e -#define BTN_DIGI 0x140 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_PEN 0x140 -#define BTN_TOOL_RUBBER 0x141 -#define BTN_TOOL_BRUSH 0x142 -#define BTN_TOOL_PENCIL 0x143 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_AIRBRUSH 0x144 -#define BTN_TOOL_FINGER 0x145 -#define BTN_TOOL_MOUSE 0x146 -#define BTN_TOOL_LENS 0x147 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_QUINTTAP 0x148 -#define BTN_TOUCH 0x14a -#define BTN_STYLUS 0x14b -#define BTN_STYLUS2 0x14c -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TOOL_DOUBLETAP 0x14d -#define BTN_TOOL_TRIPLETAP 0x14e -#define BTN_TOOL_QUADTAP 0x14f -#define BTN_WHEEL 0x150 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_GEAR_DOWN 0x150 -#define BTN_GEAR_UP 0x151 -#define KEY_OK 0x160 -#define KEY_SELECT 0x161 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_GOTO 0x162 -#define KEY_CLEAR 0x163 -#define KEY_POWER2 0x164 -#define KEY_OPTION 0x165 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_INFO 0x166 -#define KEY_TIME 0x167 -#define KEY_VENDOR 0x168 -#define KEY_ARCHIVE 0x169 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PROGRAM 0x16a -#define KEY_CHANNEL 0x16b -#define KEY_FAVORITES 0x16c -#define KEY_EPG 0x16d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_PVR 0x16e -#define KEY_MHP 0x16f -#define KEY_LANGUAGE 0x170 -#define KEY_TITLE 0x171 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SUBTITLE 0x172 -#define KEY_ANGLE 0x173 -#define KEY_ZOOM 0x174 -#define KEY_MODE 0x175 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_KEYBOARD 0x176 -#define KEY_SCREEN 0x177 -#define KEY_PC 0x178 -#define KEY_TV 0x179 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TV2 0x17a -#define KEY_VCR 0x17b -#define KEY_VCR2 0x17c -#define KEY_SAT 0x17d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SAT2 0x17e -#define KEY_CD 0x17f -#define KEY_TAPE 0x180 -#define KEY_RADIO 0x181 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TUNER 0x182 -#define KEY_PLAYER 0x183 -#define KEY_TEXT 0x184 -#define KEY_DVD 0x185 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_AUX 0x186 -#define KEY_MP3 0x187 -#define KEY_AUDIO 0x188 -#define KEY_VIDEO 0x189 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DIRECTORY 0x18a -#define KEY_LIST 0x18b -#define KEY_MEMO 0x18c -#define KEY_CALENDAR 0x18d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_RED 0x18e -#define KEY_GREEN 0x18f -#define KEY_YELLOW 0x190 -#define KEY_BLUE 0x191 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CHANNELUP 0x192 -#define KEY_CHANNELDOWN 0x193 -#define KEY_FIRST 0x194 -#define KEY_LAST 0x195 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_AB 0x196 -#define KEY_NEXT 0x197 -#define KEY_RESTART 0x198 -#define KEY_SLOW 0x199 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_SHUFFLE 0x19a -#define KEY_BREAK 0x19b -#define KEY_PREVIOUS 0x19c -#define KEY_DIGITS 0x19d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TEEN 0x19e -#define KEY_TWEN 0x19f -#define KEY_VIDEOPHONE 0x1a0 -#define KEY_GAMES 0x1a1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_ZOOMIN 0x1a2 -#define KEY_ZOOMOUT 0x1a3 -#define KEY_ZOOMRESET 0x1a4 -#define KEY_WORDPROCESSOR 0x1a5 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_EDITOR 0x1a6 -#define KEY_SPREADSHEET 0x1a7 -#define KEY_GRAPHICSEDITOR 0x1a8 -#define KEY_PRESENTATION 0x1a9 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DATABASE 0x1aa -#define KEY_NEWS 0x1ab -#define KEY_VOICEMAIL 0x1ac -#define KEY_ADDRESSBOOK 0x1ad -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_MESSENGER 0x1ae -#define KEY_DISPLAYTOGGLE 0x1af -#define KEY_SPELLCHECK 0x1b0 -#define KEY_LOGOFF 0x1b1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DOLLAR 0x1b2 -#define KEY_EURO 0x1b3 -#define KEY_FRAMEBACK 0x1b4 -#define KEY_FRAMEFORWARD 0x1b5 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CONTEXT_MENU 0x1b6 -#define KEY_MEDIA_REPEAT 0x1b7 -#define KEY_10CHANNELSUP 0x1b8 -#define KEY_10CHANNELSDOWN 0x1b9 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_IMAGES 0x1ba -#define KEY_DEL_EOL 0x1c0 -#define KEY_DEL_EOS 0x1c1 -#define KEY_INS_LINE 0x1c2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_DEL_LINE 0x1c3 -#define KEY_FN 0x1d0 -#define KEY_FN_ESC 0x1d1 -#define KEY_FN_F1 0x1d2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_F2 0x1d3 -#define KEY_FN_F3 0x1d4 -#define KEY_FN_F4 0x1d5 -#define KEY_FN_F5 0x1d6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_F6 0x1d7 -#define KEY_FN_F7 0x1d8 -#define KEY_FN_F8 0x1d9 -#define KEY_FN_F9 0x1da -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_F10 0x1db -#define KEY_FN_F11 0x1dc -#define KEY_FN_F12 0x1dd -#define KEY_FN_1 0x1de -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_2 0x1df -#define KEY_FN_D 0x1e0 -#define KEY_FN_E 0x1e1 -#define KEY_FN_F 0x1e2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_FN_S 0x1e3 -#define KEY_FN_B 0x1e4 -#define KEY_BRL_DOT1 0x1f1 -#define KEY_BRL_DOT2 0x1f2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRL_DOT3 0x1f3 -#define KEY_BRL_DOT4 0x1f4 -#define KEY_BRL_DOT5 0x1f5 -#define KEY_BRL_DOT6 0x1f6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_BRL_DOT7 0x1f7 -#define KEY_BRL_DOT8 0x1f8 -#define KEY_BRL_DOT9 0x1f9 -#define KEY_BRL_DOT10 0x1fa -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NUMERIC_0 0x200 -#define KEY_NUMERIC_1 0x201 -#define KEY_NUMERIC_2 0x202 -#define KEY_NUMERIC_3 0x203 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NUMERIC_4 0x204 -#define KEY_NUMERIC_5 0x205 -#define KEY_NUMERIC_6 0x206 -#define KEY_NUMERIC_7 0x207 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_NUMERIC_8 0x208 -#define KEY_NUMERIC_9 0x209 -#define KEY_NUMERIC_STAR 0x20a -#define KEY_NUMERIC_POUND 0x20b -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CAMERA_SNAPSHOT 0x2fe -#define KEY_CAMERA_FOCUS 0x210 -#define KEY_WPS_BUTTON 0x211 -#define KEY_TOUCHPAD_TOGGLE 0x212 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_TOUCHPAD_ON 0x213 -#define KEY_TOUCHPAD_OFF 0x214 -#define KEY_CAMERA_ZOOMIN 0x215 -#define KEY_CAMERA_ZOOMOUT 0x216 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define KEY_CAMERA_UP 0x217 -#define KEY_CAMERA_DOWN 0x218 -#define KEY_CAMERA_LEFT 0x219 -#define KEY_CAMERA_RIGHT 0x21a -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY 0x2c0 -#define BTN_TRIGGER_HAPPY1 0x2c0 -#define BTN_TRIGGER_HAPPY2 0x2c1 -#define BTN_TRIGGER_HAPPY3 0x2c2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY4 0x2c3 -#define BTN_TRIGGER_HAPPY5 0x2c4 -#define BTN_TRIGGER_HAPPY6 0x2c5 -#define BTN_TRIGGER_HAPPY7 0x2c6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY8 0x2c7 -#define BTN_TRIGGER_HAPPY9 0x2c8 -#define BTN_TRIGGER_HAPPY10 0x2c9 -#define BTN_TRIGGER_HAPPY11 0x2ca -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY12 0x2cb -#define BTN_TRIGGER_HAPPY13 0x2cc -#define BTN_TRIGGER_HAPPY14 0x2cd -#define BTN_TRIGGER_HAPPY15 0x2ce -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY16 0x2cf -#define BTN_TRIGGER_HAPPY17 0x2d0 -#define BTN_TRIGGER_HAPPY18 0x2d1 -#define BTN_TRIGGER_HAPPY19 0x2d2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY20 0x2d3 -#define BTN_TRIGGER_HAPPY21 0x2d4 -#define BTN_TRIGGER_HAPPY22 0x2d5 -#define BTN_TRIGGER_HAPPY23 0x2d6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY24 0x2d7 -#define BTN_TRIGGER_HAPPY25 0x2d8 -#define BTN_TRIGGER_HAPPY26 0x2d9 -#define BTN_TRIGGER_HAPPY27 0x2da -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY28 0x2db -#define BTN_TRIGGER_HAPPY29 0x2dc -#define BTN_TRIGGER_HAPPY30 0x2dd -#define BTN_TRIGGER_HAPPY31 0x2de -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY32 0x2df -#define BTN_TRIGGER_HAPPY33 0x2e0 -#define BTN_TRIGGER_HAPPY34 0x2e1 -#define BTN_TRIGGER_HAPPY35 0x2e2 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY36 0x2e3 -#define BTN_TRIGGER_HAPPY37 0x2e4 -#define BTN_TRIGGER_HAPPY38 0x2e5 -#define BTN_TRIGGER_HAPPY39 0x2e6 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BTN_TRIGGER_HAPPY40 0x2e7 -#define KEY_MIN_INTERESTING KEY_MUTE -#define KEY_MAX 0x2ff -#define KEY_CNT (KEY_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REL_X 0x00 -#define REL_Y 0x01 -#define REL_Z 0x02 -#define REL_RX 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REL_RY 0x04 -#define REL_RZ 0x05 -#define REL_HWHEEL 0x06 -#define REL_DIAL 0x07 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REL_WHEEL 0x08 -#define REL_MISC 0x09 -#define REL_MAX 0x0f -#define REL_CNT (REL_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_X 0x00 -#define ABS_Y 0x01 -#define ABS_Z 0x02 -#define ABS_RX 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_RY 0x04 -#define ABS_RZ 0x05 -#define ABS_THROTTLE 0x06 -#define ABS_RUDDER 0x07 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_WHEEL 0x08 -#define ABS_GAS 0x09 -#define ABS_BRAKE 0x0a -#define ABS_HAT0X 0x10 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_HAT0Y 0x11 -#define ABS_HAT1X 0x12 -#define ABS_HAT1Y 0x13 -#define ABS_HAT2X 0x14 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_HAT2Y 0x15 -#define ABS_HAT3X 0x16 -#define ABS_HAT3Y 0x17 -#define ABS_PRESSURE 0x18 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_DISTANCE 0x19 -#define ABS_TILT_X 0x1a -#define ABS_TILT_Y 0x1b -#define ABS_TOOL_WIDTH 0x1c -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_VOLUME 0x20 -#define ABS_MISC 0x28 -#define ABS_MT_SLOT 0x2f -#define ABS_MT_TOUCH_MAJOR 0x30 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_MT_TOUCH_MINOR 0x31 -#define ABS_MT_WIDTH_MAJOR 0x32 -#define ABS_MT_WIDTH_MINOR 0x33 -#define ABS_MT_ORIENTATION 0x34 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_MT_POSITION_X 0x35 -#define ABS_MT_POSITION_Y 0x36 -#define ABS_MT_TOOL_TYPE 0x37 -#define ABS_MT_BLOB_ID 0x38 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_MT_TRACKING_ID 0x39 -#define ABS_MT_PRESSURE 0x3a -#define ABS_MT_DISTANCE 0x3b -#define ABS_MAX 0x3f -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ABS_CNT (ABS_MAX+1) -#define SW_LID 0x00 -#define SW_TABLET_MODE 0x01 -#define SW_HEADPHONE_INSERT 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_RFKILL_ALL 0x03 -#define SW_RADIO SW_RFKILL_ALL -#define SW_MICROPHONE_INSERT 0x04 -#define SW_DOCK 0x05 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_LINEOUT_INSERT 0x06 -#define SW_JACK_PHYSICAL_INSERT 0x07 -#define SW_VIDEOOUT_INSERT 0x08 -#define SW_CAMERA_LENS_COVER 0x09 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_KEYPAD_SLIDE 0x0a -#define SW_FRONT_PROXIMITY 0x0b -#define SW_ROTATE_LOCK 0x0c -#define SW_LINEIN_INSERT 0x0d -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_HPHL_OVERCURRENT 0x0e -#define SW_HPHR_OVERCURRENT 0x0f -#define SW_UNSUPPORT_INSERT 0x10 -#define SW_MAX 0x20 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SW_CNT (SW_MAX+1) -#define MSC_SERIAL 0x00 -#define MSC_PULSELED 0x01 -#define MSC_GESTURE 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define MSC_RAW 0x03 -#define MSC_SCAN 0x04 -#define MSC_MAX 0x07 -#define MSC_CNT (MSC_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_NUML 0x00 -#define LED_CAPSL 0x01 -#define LED_SCROLLL 0x02 -#define LED_COMPOSE 0x03 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_KANA 0x04 -#define LED_SLEEP 0x05 -#define LED_SUSPEND 0x06 -#define LED_MUTE 0x07 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_MISC 0x08 -#define LED_MAIL 0x09 -#define LED_CHARGING 0x0a -#define LED_MAX 0x0f -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define LED_CNT (LED_MAX+1) -#define REP_DELAY 0x00 -#define REP_PERIOD 0x01 -#define REP_MAX 0x01 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define REP_CNT (REP_MAX+1) -#define SND_CLICK 0x00 -#define SND_BELL 0x01 -#define SND_TONE 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define SND_MAX 0x07 -#define SND_CNT (SND_MAX+1) -#define ID_BUS 0 -#define ID_VENDOR 1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define ID_PRODUCT 2 -#define ID_VERSION 3 -#define BUS_PCI 0x01 -#define BUS_ISAPNP 0x02 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_USB 0x03 -#define BUS_HIL 0x04 -#define BUS_BLUETOOTH 0x05 -#define BUS_VIRTUAL 0x06 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_ISA 0x10 -#define BUS_I8042 0x11 -#define BUS_XTKBD 0x12 -#define BUS_RS232 0x13 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_GAMEPORT 0x14 -#define BUS_PARPORT 0x15 -#define BUS_AMIGA 0x16 -#define BUS_ADB 0x17 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_I2C 0x18 -#define BUS_HOST 0x19 -#define BUS_GSC 0x1A -#define BUS_ATARI 0x1B -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define BUS_SPI 0x1C -#define MT_TOOL_FINGER 0 -#define MT_TOOL_PEN 1 -#define MT_TOOL_MAX 1 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_STATUS_STOPPED 0x00 -#define FF_STATUS_PLAYING 0x01 -#define FF_STATUS_MAX 0x01 -struct ff_replay { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 length; - __u16 delay; -}; -struct ff_trigger { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 button; - __u16 interval; -}; -struct ff_envelope { -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 attack_length; - __u16 attack_level; - __u16 fade_length; - __u16 fade_level; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -}; -struct ff_constant_effect { - __s16 level; - struct ff_envelope envelope; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -}; -struct ff_ramp_effect { - __s16 start_level; - __s16 end_level; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_envelope envelope; -}; -struct ff_condition_effect { - __u16 right_saturation; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 left_saturation; - __s16 right_coeff; - __s16 left_coeff; - __u16 deadband; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __s16 center; -}; -struct ff_periodic_effect { - __u16 waveform; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - __u16 period; - __s16 magnitude; - __s16 offset; - __u16 phase; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_envelope envelope; - __u32 custom_len; - __s16 __user *custom_data; -}; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -struct ff_rumble_effect { - __u16 strong_magnitude; - __u16 weak_magnitude; -}; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -struct ff_effect { - __u16 type; - __s16 id; - __u16 direction; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_trigger trigger; - struct ff_replay replay; - union { - struct ff_constant_effect constant; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - struct ff_ramp_effect ramp; - struct ff_periodic_effect periodic; - struct ff_condition_effect condition[2]; - struct ff_rumble_effect rumble; -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ - } u; -}; -#define FF_RUMBLE 0x50 -#define FF_PERIODIC 0x51 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_CONSTANT 0x52 -#define FF_SPRING 0x53 -#define FF_FRICTION 0x54 -#define FF_DAMPER 0x55 -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_INERTIA 0x56 -#define FF_RAMP 0x57 -#define FF_EFFECT_MIN FF_RUMBLE -#define FF_EFFECT_MAX FF_RAMP -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_SQUARE 0x58 -#define FF_TRIANGLE 0x59 -#define FF_SINE 0x5a -#define FF_SAW_UP 0x5b -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_SAW_DOWN 0x5c -#define FF_CUSTOM 0x5d -#define FF_WAVEFORM_MIN FF_SQUARE -#define FF_WAVEFORM_MAX FF_CUSTOM -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#define FF_GAIN 0x60 -#define FF_AUTOCENTER 0x61 -#define FF_MAX 0x7f -#define FF_CNT (FF_MAX+1) -/* WARNING: DO NOT EDIT, AUTO-GENERATED CODE - SEE TOP FOR INSTRUCTIONS */ -#endif diff --git a/widget/gonk/libui/sha1.c b/widget/gonk/libui/sha1.c deleted file mode 100644 index 40a4ecaa3..000000000 --- a/widget/gonk/libui/sha1.c +++ /dev/null @@ -1,289 +0,0 @@ -/* $NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $ */ -/* $OpenBSD: sha1.c,v 1.9 1997/07/23 21:12:32 kstailey Exp $ */ - -/* - * SHA-1 in C - * By Steve Reid - * 100% Public Domain - * - * Test Vectors (from FIPS PUB 180-1) - * "abc" - * A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D - * "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" - * 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 - * A million repetitions of "a" - * 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F - */ - -#define SHA1HANDSOFF /* Copies data before messing with it. */ - -#include - -#if defined(_KERNEL) || defined(_STANDALONE) -__KERNEL_RCSID(0, "$NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $"); - -#include - -#else - -#if defined(LIBC_SCCS) && !defined(lint) -__RCSID("$NetBSD: sha1.c,v 1.6 2009/11/06 20:31:18 joerg Exp $"); -#endif /* LIBC_SCCS and not lint */ - -#include -#include - -#endif - -#include -#include "sha1.h" - -#define _DIAGASSERT assert - -#if HAVE_NBTOOL_CONFIG_H -#include "nbtool_config.h" -#endif - -#if !HAVE_SHA1_H - -#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) - -/* - * blk0() and blk() perform the initial expand. - * I got the idea of expanding during the round function from SSLeay - */ -#if BYTE_ORDER == LITTLE_ENDIAN -# define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ - |(rol(block->l[i],8)&0x00FF00FF)) -#else -# define blk0(i) block->l[i] -#endif -#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ - ^block->l[(i+2)&15]^block->l[i&15],1)) - -/* - * (R0+R1), R2, R3, R4 are the different operations (rounds) used in SHA1 - */ -#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); -#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); -#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); -#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); - - -#if !defined(_KERNEL) && !defined(_STANDALONE) -#if defined(__weak_alias) -__weak_alias(SHA1Transform,_SHA1Transform) -__weak_alias(SHA1Init,_SHA1Init) -__weak_alias(SHA1Update,_SHA1Update) -__weak_alias(SHA1Final,_SHA1Final) -#endif -#endif - -typedef union { - uint8_t c[64]; - uint32_t l[16]; -} CHAR64LONG16; - -/* old sparc64 gcc could not compile this */ -#undef SPARC64_GCC_WORKAROUND -#if defined(__sparc64__) && defined(__GNUC__) && __GNUC__ < 3 -#define SPARC64_GCC_WORKAROUND -#endif - -#ifdef SPARC64_GCC_WORKAROUND -void do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); -void do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); -void do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); -void do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *); - -#define nR0(v,w,x,y,z,i) R0(*v,*w,*x,*y,*z,i) -#define nR1(v,w,x,y,z,i) R1(*v,*w,*x,*y,*z,i) -#define nR2(v,w,x,y,z,i) R2(*v,*w,*x,*y,*z,i) -#define nR3(v,w,x,y,z,i) R3(*v,*w,*x,*y,*z,i) -#define nR4(v,w,x,y,z,i) R4(*v,*w,*x,*y,*z,i) - -void -do_R01(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR0(a,b,c,d,e, 0); nR0(e,a,b,c,d, 1); nR0(d,e,a,b,c, 2); nR0(c,d,e,a,b, 3); - nR0(b,c,d,e,a, 4); nR0(a,b,c,d,e, 5); nR0(e,a,b,c,d, 6); nR0(d,e,a,b,c, 7); - nR0(c,d,e,a,b, 8); nR0(b,c,d,e,a, 9); nR0(a,b,c,d,e,10); nR0(e,a,b,c,d,11); - nR0(d,e,a,b,c,12); nR0(c,d,e,a,b,13); nR0(b,c,d,e,a,14); nR0(a,b,c,d,e,15); - nR1(e,a,b,c,d,16); nR1(d,e,a,b,c,17); nR1(c,d,e,a,b,18); nR1(b,c,d,e,a,19); -} - -void -do_R2(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR2(a,b,c,d,e,20); nR2(e,a,b,c,d,21); nR2(d,e,a,b,c,22); nR2(c,d,e,a,b,23); - nR2(b,c,d,e,a,24); nR2(a,b,c,d,e,25); nR2(e,a,b,c,d,26); nR2(d,e,a,b,c,27); - nR2(c,d,e,a,b,28); nR2(b,c,d,e,a,29); nR2(a,b,c,d,e,30); nR2(e,a,b,c,d,31); - nR2(d,e,a,b,c,32); nR2(c,d,e,a,b,33); nR2(b,c,d,e,a,34); nR2(a,b,c,d,e,35); - nR2(e,a,b,c,d,36); nR2(d,e,a,b,c,37); nR2(c,d,e,a,b,38); nR2(b,c,d,e,a,39); -} - -void -do_R3(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR3(a,b,c,d,e,40); nR3(e,a,b,c,d,41); nR3(d,e,a,b,c,42); nR3(c,d,e,a,b,43); - nR3(b,c,d,e,a,44); nR3(a,b,c,d,e,45); nR3(e,a,b,c,d,46); nR3(d,e,a,b,c,47); - nR3(c,d,e,a,b,48); nR3(b,c,d,e,a,49); nR3(a,b,c,d,e,50); nR3(e,a,b,c,d,51); - nR3(d,e,a,b,c,52); nR3(c,d,e,a,b,53); nR3(b,c,d,e,a,54); nR3(a,b,c,d,e,55); - nR3(e,a,b,c,d,56); nR3(d,e,a,b,c,57); nR3(c,d,e,a,b,58); nR3(b,c,d,e,a,59); -} - -void -do_R4(uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d, uint32_t *e, CHAR64LONG16 *block) -{ - nR4(a,b,c,d,e,60); nR4(e,a,b,c,d,61); nR4(d,e,a,b,c,62); nR4(c,d,e,a,b,63); - nR4(b,c,d,e,a,64); nR4(a,b,c,d,e,65); nR4(e,a,b,c,d,66); nR4(d,e,a,b,c,67); - nR4(c,d,e,a,b,68); nR4(b,c,d,e,a,69); nR4(a,b,c,d,e,70); nR4(e,a,b,c,d,71); - nR4(d,e,a,b,c,72); nR4(c,d,e,a,b,73); nR4(b,c,d,e,a,74); nR4(a,b,c,d,e,75); - nR4(e,a,b,c,d,76); nR4(d,e,a,b,c,77); nR4(c,d,e,a,b,78); nR4(b,c,d,e,a,79); -} -#endif - -/* - * Hash a single 512-bit block. This is the core of the algorithm. - */ -void SHA1Transform(uint32_t state[5], const uint8_t buffer[64]) -{ - uint32_t a, b, c, d, e; - CHAR64LONG16 *block; - -#ifdef SHA1HANDSOFF - CHAR64LONG16 workspace; -#endif - - _DIAGASSERT(buffer != 0); - _DIAGASSERT(state != 0); - -#ifdef SHA1HANDSOFF - block = &workspace; - (void)memcpy(block, buffer, 64); -#else - block = (CHAR64LONG16 *)(void *)buffer; -#endif - - /* Copy context->state[] to working vars */ - a = state[0]; - b = state[1]; - c = state[2]; - d = state[3]; - e = state[4]; - -#ifdef SPARC64_GCC_WORKAROUND - do_R01(&a, &b, &c, &d, &e, block); - do_R2(&a, &b, &c, &d, &e, block); - do_R3(&a, &b, &c, &d, &e, block); - do_R4(&a, &b, &c, &d, &e, block); -#else - /* 4 rounds of 20 operations each. Loop unrolled. */ - R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); - R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); - R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); - R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); - R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); - R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); - R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); - R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); - R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); - R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); - R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); - R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); - R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); - R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); - R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); - R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); - R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); - R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); - R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); - R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); -#endif - - /* Add the working vars back into context.state[] */ - state[0] += a; - state[1] += b; - state[2] += c; - state[3] += d; - state[4] += e; - - /* Wipe variables */ - a = b = c = d = e = 0; -} - - -/* - * SHA1Init - Initialize new context - */ -void SHA1Init(SHA1_CTX *context) -{ - - _DIAGASSERT(context != 0); - - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} - - -/* - * Run your data through this. - */ -void SHA1Update(SHA1_CTX *context, const uint8_t *data, unsigned int len) -{ - unsigned int i, j; - - _DIAGASSERT(context != 0); - _DIAGASSERT(data != 0); - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1] += (len>>29)+1; - j = (j >> 3) & 63; - if ((j + len) > 63) { - (void)memcpy(&context->buffer[j], data, (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) - SHA1Transform(context->state, &data[i]); - j = 0; - } else { - i = 0; - } - (void)memcpy(&context->buffer[j], &data[i], len - i); -} - - -/* - * Add padding and return the message digest. - */ -void SHA1Final(uint8_t digest[20], SHA1_CTX *context) -{ - unsigned int i; - uint8_t finalcount[8]; - - _DIAGASSERT(digest != 0); - _DIAGASSERT(context != 0); - - for (i = 0; i < 8; i++) { - finalcount[i] = (uint8_t)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (const uint8_t *)"\200", 1); - while ((context->count[0] & 504) != 448) - SHA1Update(context, (const uint8_t *)"\0", 1); - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - - if (digest) { - for (i = 0; i < 20; i++) - digest[i] = (uint8_t) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } -} - -#endif /* HAVE_SHA1_H */ diff --git a/widget/gonk/libui/sha1.h b/widget/gonk/libui/sha1.h deleted file mode 100644 index f7ada46a5..000000000 --- a/widget/gonk/libui/sha1.h +++ /dev/null @@ -1,31 +0,0 @@ -/* $NetBSD: sha1.h,v 1.13 2005/12/26 18:41:36 perry Exp $ */ - -/* - * SHA-1 in C - * By Steve Reid - * 100% Public Domain - */ - -#ifndef _SYS_SHA1_H_ -#define _SYS_SHA1_H_ - -#include -#include - -#define SHA1_DIGEST_LENGTH 20 -#define SHA1_DIGEST_STRING_LENGTH 41 - -typedef struct { - uint32_t state[5]; - uint32_t count[2]; - u_char buffer[64]; -} SHA1_CTX; - -__BEGIN_DECLS -void SHA1Transform(uint32_t[5], const u_char[64]); -void SHA1Init(SHA1_CTX *); -void SHA1Update(SHA1_CTX *, const u_char *, u_int); -void SHA1Final(u_char[SHA1_DIGEST_LENGTH], SHA1_CTX *); -__END_DECLS - -#endif /* _SYS_SHA1_H_ */ diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build deleted file mode 100644 index d539dd9a0..000000000 --- a/widget/gonk/moz.build +++ /dev/null @@ -1,96 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -EXPORTS += [ - 'GeckoTouchDispatcher.h', - 'GonkPermission.h', - 'OrientationObserver.h', -] - -DIRS += ['libdisplay', 'nativewindow'] - -# libui files -SOURCES += ['libui/' + src for src in [ - 'EventHub.cpp', - 'Input.cpp', - 'InputApplication.cpp', - 'InputDevice.cpp', - 'InputDispatcher.cpp', - 'InputListener.cpp', - 'InputReader.cpp', - 'InputTransport.cpp', - 'InputWindow.cpp', - 'Keyboard.cpp', - 'KeyCharacterMap.cpp', - 'KeyLayoutMap.cpp', - 'PointerController.cpp', - 'sha1.c', - 'SpriteController.cpp', - 'Tokenizer.cpp', - 'VelocityControl.cpp', - 'VelocityTracker.cpp', - 'VirtualKeyMap.cpp', -]] - -# HwcHAL files -if CONFIG['ANDROID_VERSION'] >= '17': - SOURCES += [ - 'hwchal/HwcHAL.cpp', - ] - -SOURCES += [ - 'GeckoTouchDispatcher.cpp', - 'GfxInfo.cpp', - 'GonkClipboardData.cpp', - 'GonkMemoryPressureMonitoring.cpp', - 'GonkPermission.cpp', - 'HwcComposer2D.cpp', - 'HwcUtils.cpp', - 'nsAppShell.cpp', - 'nsClipboard.cpp', - 'nsIdleServiceGonk.cpp', - 'nsLookAndFeel.cpp', - 'nsScreenManagerGonk.cpp', - 'nsWidgetFactory.cpp', - 'nsWindow.cpp', - 'OrientationObserver.cpp', - 'ProcessOrientation.cpp', - 'WidgetTraceEvent.cpp' -] - -include('/ipc/chromium/chromium-config.mozbuild') - -FINAL_LIBRARY = 'xul' - -LOCAL_INCLUDES += [ - '/dom/system/android', - '/gfx/skia/skia/include/config', - '/gfx/skia/skia/include/core', - '/image', - '/widget', -] - -DEFINES['HAVE_OFF64_T'] = True -DEFINES['SK_BUILD_FOR_ANDROID_NDK'] = True -DEFINES['HAVE_POSIX_CLOCKS'] = True - -LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include', - 'hardware/libhardware/include', - 'hardware/libhardware_legacy/include', - ] -] diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp b/widget/gonk/nativewindow/FakeSurfaceComposer.cpp deleted file mode 100644 index 7e4a2a9d8..000000000 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.cpp +++ /dev/null @@ -1,703 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "FakeSurfaceComposer" -//#define LOG_NDEBUG 0 - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#if ANDROID_VERSION >= 21 -#include -#endif - -#include "../libdisplay/GonkDisplay.h" -#include "../nsScreenManagerGonk.h" -#include "FakeSurfaceComposer.h" -#include "gfxPrefs.h" -#include "MainThreadUtils.h" -#include "mozilla/Assertions.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/CompositorThread.h" -#include "nsProxyRelease.h" -#include "nsThreadUtils.h" - -using namespace mozilla; - -namespace android { - -/* static */ -void FakeSurfaceComposer::instantiate() { - defaultServiceManager()->addService( - String16("SurfaceFlinger"), new FakeSurfaceComposer()); -} - -FakeSurfaceComposer::FakeSurfaceComposer() - : BnSurfaceComposer() -{ -} - -FakeSurfaceComposer::~FakeSurfaceComposer() -{ -} - -status_t FakeSurfaceComposer::onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags) -{ - switch (code) { - case CREATE_CONNECTION: - case CREATE_DISPLAY: - case SET_TRANSACTION_STATE: - case CAPTURE_SCREEN: - { - // codes that require permission check - IPCThreadState* ipc = IPCThreadState::self(); - const int pid = ipc->getCallingPid(); - const int uid = ipc->getCallingUid(); - // Accept request only when uid is root. - if (uid != AID_ROOT) { - ALOGE("Permission Denial: " - "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); - return PERMISSION_DENIED; - } - break; - } - } - - return BnSurfaceComposer::onTransact(code, data, reply, flags); -} - -sp FakeSurfaceComposer::createConnection() -{ - return nullptr; -} - -sp FakeSurfaceComposer::createGraphicBufferAlloc() -{ - sp gba(new GraphicBufferAlloc()); - return gba; -} - -class DestroyDisplayRunnable : public Runnable { -public: - DestroyDisplayRunnable(FakeSurfaceComposer* aComposer, ssize_t aIndex) - : mComposer(aComposer), mIndex(aIndex) { } - NS_IMETHOD Run() override { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - Mutex::Autolock _l(mComposer->mStateLock); - RefPtr screenManager = - nsScreenManagerGonk::GetInstance(); - screenManager->RemoveScreen(GonkDisplay::DISPLAY_VIRTUAL); - mComposer->mDisplays.removeItemsAt(mIndex); - return NS_OK; - } - sp mComposer; - ssize_t mIndex; -}; - -sp FakeSurfaceComposer::createDisplay(const String8& displayName, - bool secure) -{ -#if ANDROID_VERSION >= 19 - class DisplayToken : public BBinder { - sp composer; - virtual ~DisplayToken() { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - // no more references, this display must be terminated - Mutex::Autolock _l(composer->mStateLock); - ssize_t idx = composer->mDisplays.indexOfKey(this); - if (idx >= 0) { - nsCOMPtr task(new DestroyDisplayRunnable(composer.get(), idx)); - NS_DispatchToMainThread(task); - } - } - public: - DisplayToken(const sp& composer) - : composer(composer) { - } - }; - - sp token = new DisplayToken(this); - - Mutex::Autolock _l(mStateLock); - DisplayDeviceState info(HWC_DISPLAY_VIRTUAL); - info.displayName = displayName; - info.displayId = GonkDisplay::DISPLAY_VIRTUAL; - info.isSecure = secure; - mDisplays.add(token, info); - return token; -#else - return nullptr; -#endif -} - -#if ANDROID_VERSION >= 19 -void FakeSurfaceComposer::destroyDisplay(const sp& display) -{ - Mutex::Autolock _l(mStateLock); - - ssize_t idx = mDisplays.indexOfKey(display); - if (idx < 0) { - ALOGW("destroyDisplay: invalid display token"); - return; - } - - nsCOMPtr task(new DestroyDisplayRunnable(this, idx)); - NS_DispatchToMainThread(task); -} -#endif - -sp FakeSurfaceComposer::getBuiltInDisplay(int32_t id) -{ - // support only primary display - if (uint32_t(id) != HWC_DISPLAY_PRIMARY) { - return NULL; - } - - if (!mPrimaryDisplay.get()) { - mPrimaryDisplay = new BBinder(); - } - return mPrimaryDisplay; -} - -void FakeSurfaceComposer::setTransactionState( - const Vector& state, - const Vector& displays, - uint32_t flags) -{ - Mutex::Autolock _l(mStateLock); - size_t count = displays.size(); - for (size_t i=0 ; iasBinder() != s.surface->asBinder()) { - disp.surface = s.surface; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eLayerStackChanged) { - if (disp.layerStack != s.layerStack) { - disp.layerStack = s.layerStack; - flags |= eDisplayTransactionNeeded; - } - } - if (what & DisplayState::eDisplayProjectionChanged) { - if (disp.orientation != s.orientation) { - disp.orientation = s.orientation; - flags |= eDisplayTransactionNeeded; - } - if (disp.frame != s.frame) { - disp.frame = s.frame; - flags |= eDisplayTransactionNeeded; - } - if (disp.viewport != s.viewport) { - disp.viewport = s.viewport; - flags |= eDisplayTransactionNeeded; - } - } -#if ANDROID_VERSION >= 21 - if (what & DisplayState::eDisplaySizeChanged) { - if (disp.width != s.width) { - disp.width = s.width; - flags |= eDisplayTransactionNeeded; - } - if (disp.height != s.height) { - disp.height = s.height; - flags |= eDisplayTransactionNeeded; - } - } -#endif - - if (what & DisplayState::eSurfaceChanged) { - nsCOMPtr runnable = - NS_NewRunnableFunction([&]() { - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - RefPtr screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->AddScreen(GonkDisplay::DISPLAY_VIRTUAL, disp.surface.get()); - }); - NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); - } - - return flags; -} - -void FakeSurfaceComposer::bootFinished() -{ -} - -bool FakeSurfaceComposer::authenticateSurfaceTexture( - const sp& bufferProducer) const { - return false; -} - -sp FakeSurfaceComposer::createDisplayEventConnection() { - return nullptr; -} - -// --------------------------------------------------------------------------- -// Capture screen into an IGraphiBufferProducer -// --------------------------------------------------------------------------- - -class Barrier { -public: - inline Barrier() : state(CLOSED) { } - inline ~Barrier() { } - - // Release any threads waiting at the Barrier. - // Provides release semantics: preceding loads and stores will be visible - // to other threads before they wake up. - void open() { - Mutex::Autolock _l(lock); - state = OPENED; - cv.broadcast(); - } - - // Reset the Barrier, so wait() will block until open() has been called. - void close() { - Mutex::Autolock _l(lock); - state = CLOSED; - } - - // Wait until the Barrier is OPEN. - // Provides acquire semantics: no subsequent loads or stores will occur - // until wait() returns. - void wait() const { - Mutex::Autolock _l(lock); - while (state == CLOSED) { - cv.wait(lock); - } - } -private: - enum { OPENED, CLOSED }; - mutable Mutex lock; - mutable Condition cv; - volatile int state; -}; - -/* The code below is here to handle b/8734824 - * - * We create a IGraphicBufferProducer wrapper that forwards all calls - * to the calling binder thread, where they are executed. This allows - * the calling thread to be reused (on the other side) and not - * depend on having "enough" binder threads to handle the requests. - * - */ - -class GraphicProducerWrapper : public BBinder, public MessageHandler { - sp impl; - sp looper; - status_t result; - bool exitPending; - bool exitRequested; - mutable Barrier barrier; - volatile int32_t memoryBarrier; - uint32_t code; - Parcel const* data; - Parcel* reply; - - enum { - MSG_API_CALL, - MSG_EXIT - }; - - /* - * this is called by our "fake" BpGraphicBufferProducer. We package the - * data and reply Parcel and forward them to the calling thread. - */ - virtual status_t transact(uint32_t code, - const Parcel& data, Parcel* reply, uint32_t flags) { - this->code = code; - this->data = &data; - this->reply = reply; - android_atomic_acquire_store(0, &memoryBarrier); - if (exitPending) { - // if we've exited, we run the message synchronously right here - handleMessage(Message(MSG_API_CALL)); - } else { - barrier.close(); - looper->sendMessage(this, Message(MSG_API_CALL)); - barrier.wait(); - } - return NO_ERROR; - } - - /* - * here we run on the binder calling thread. All we've got to do is - * call the real BpGraphicBufferProducer. - */ - virtual void handleMessage(const Message& message) { - android_atomic_release_load(&memoryBarrier); - if (message.what == MSG_API_CALL) { - impl->asBinder()->transact(code, data[0], reply); - barrier.open(); - } else if (message.what == MSG_EXIT) { - exitRequested = true; - } - } - -public: - GraphicProducerWrapper(const sp& impl) : - impl(impl), looper(new Looper(true)), result(NO_ERROR), - exitPending(false), exitRequested(false) { - } - - status_t waitForResponse() { - do { - looper->pollOnce(-1); - } while (!exitRequested); - return result; - } - - void exit(status_t result) { - this->result = result; - exitPending = true; - looper->sendMessage(this, Message(MSG_EXIT)); - } -}; - -status_t -FakeSurfaceComposer::captureScreen(const sp& display - , const sp& producer -#if ANDROID_VERSION >= 21 - , Rect sourceCrop -#endif - , uint32_t reqWidth - , uint32_t reqHeight - , uint32_t minLayerZ - , uint32_t maxLayerZ -#if ANDROID_VERSION >= 21 - , bool useIdentityTransform - , Rotation rotation -#elif ANDROID_VERSION < 19 - , bool isCpuConsumer -#endif - ) -{ - if (display == 0 || producer == 0) { - return BAD_VALUE; - } - - // Limit only to primary display - if (display != mPrimaryDisplay) { - return BAD_VALUE; - } - - // this creates a "fake" BBinder which will serve as a "fake" remote - // binder to receive the marshaled calls and forward them to the - // real remote (a BpGraphicBufferProducer) - sp wrapper = new GraphicProducerWrapper(producer); - // the asInterface() call below creates our "fake" BpGraphicBufferProducer - // which does the marshaling work forwards to our "fake remote" above. - sp fakeProducer = IGraphicBufferProducer::asInterface(wrapper); - - nsCOMPtr runnable = - NS_NewRunnableFunction([&]() { - captureScreenImp(fakeProducer, reqWidth, reqHeight, wrapper.get()); - }); - NS_DispatchToMainThread(runnable); - - status_t result = wrapper->waitForResponse(); - - return result; -} - -class RunnableCallTask final : public Runnable -{ -public: - explicit RunnableCallTask(nsIRunnable* aRunnable) - : mRunnable(aRunnable) {} - - NS_IMETHOD Run() override - { - return mRunnable->Run(); - } -protected: - nsCOMPtr mRunnable; -}; - -void -FakeSurfaceComposer::captureScreenImp(const sp& producer, - uint32_t reqWidth, - uint32_t reqHeight, - const sp& wrapper) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(wrapper.get()); - - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - - // get screen geometry - nsIntRect screenBounds = screen->GetNaturalBounds().ToUnknownRect(); - const uint32_t hw_w = screenBounds.width; - const uint32_t hw_h = screenBounds.height; - - if (reqWidth > hw_w || reqHeight > hw_h) { - ALOGE("size mismatch (%d, %d) > (%d, %d)", - reqWidth, reqHeight, hw_w, hw_h); - static_cast(producer->asBinder().get())->exit(BAD_VALUE); - return; - } - - reqWidth = (!reqWidth) ? hw_w : reqWidth; - reqHeight = (!reqHeight) ? hw_h : reqHeight; - - nsCOMPtr runnable = - NS_NewRunnableFunction([screen, reqWidth, reqHeight, producer, wrapper]() { - // create a surface (because we're a producer, and we need to - // dequeue/queue a buffer) - sp sur = new Surface(producer); - ANativeWindow* window = sur.get(); - // The closure makes screen const and we can't call forget() on it. - RefPtr screenAlias = screen; - - if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != NO_ERROR) { - static_cast(producer->asBinder().get())->exit(BAD_VALUE); - NS_ReleaseOnMainThread(screenAlias.forget()); - return; - } - uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_TEXTURE; - - int err = 0; - err = native_window_set_buffers_dimensions(window, reqWidth, reqHeight); - err |= native_window_set_scaling_mode(window, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - err |= native_window_set_buffers_format(window, HAL_PIXEL_FORMAT_RGBA_8888); - err |= native_window_set_usage(window, usage); - - status_t result = NO_ERROR; - if (err == NO_ERROR) { - ANativeWindowBuffer* buffer; - result = native_window_dequeue_buffer_and_wait(window, &buffer); - if (result == NO_ERROR) { - nsresult rv = screen->MakeSnapshot(buffer); - if (rv != NS_OK) { - result = INVALID_OPERATION; - } - window->queueBuffer(window, buffer, -1); - } - } else { - result = BAD_VALUE; - } - native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL); - static_cast(producer->asBinder().get())->exit(result); - NS_ReleaseOnMainThread(screenAlias.forget()); - }); - - layers::CompositorThreadHolder::Loop()->PostTask( - MakeAndAddRef(runnable)); -} - -#if ANDROID_VERSION >= 21 -void -FakeSurfaceComposer::setPowerMode(const sp& display, int mode) -{ -} - -status_t -FakeSurfaceComposer::getDisplayConfigs(const sp& display, Vector* configs) -{ - if (configs == NULL) { - return BAD_VALUE; - } - - // Limit DisplayConfigs only to primary display - if (!display.get() || display != mPrimaryDisplay) { - return NAME_NOT_FOUND; - } - - configs->clear(); - DisplayInfo info = DisplayInfo(); - - nsCOMPtr runnable = - NS_NewRunnableFunction([&]() { - MOZ_ASSERT(NS_IsMainThread()); - getPrimaryDisplayInfo(&info); - }); - NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); - - configs->push_back(info); - return NO_ERROR; -} - -status_t -FakeSurfaceComposer::getDisplayStats(const sp& display, DisplayStatInfo* stats) -{ - return INVALID_OPERATION; -} - -int -FakeSurfaceComposer::getActiveConfig(const sp& display) -{ - // Only support primary display. - if (display.get() && (display == mPrimaryDisplay)) { - return 0; - } - return INVALID_OPERATION; -} - -status_t -FakeSurfaceComposer::setActiveConfig(const sp& display, int id) -{ - return INVALID_OPERATION; -} - -status_t -FakeSurfaceComposer::clearAnimationFrameStats() -{ - return INVALID_OPERATION; -} - -status_t -FakeSurfaceComposer::getAnimationFrameStats(FrameStats* outStats) const -{ - return INVALID_OPERATION; -} -#else -void -FakeSurfaceComposer::blank(const sp& display) -{ -} - -void -FakeSurfaceComposer::unblank(const sp& display) -{ -} - -status_t -FakeSurfaceComposer::getDisplayInfo(const sp& display, DisplayInfo* info) -{ - if (info == NULL) { - return BAD_VALUE; - } - - // Limit DisplayConfigs only to primary display - if (!display.get() || display != mPrimaryDisplay) { - return NAME_NOT_FOUND; - } - - nsCOMPtr runnable = - NS_NewRunnableFunction([&]() { - MOZ_ASSERT(NS_IsMainThread()); - getPrimaryDisplayInfo(info); - }); - NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); - - return NO_ERROR; -} -#endif - -#define VSYNC_EVENT_PHASE_OFFSET_NS 0 -#define SF_VSYNC_EVENT_PHASE_OFFSET_NS 0 - -void -FakeSurfaceComposer::getPrimaryDisplayInfo(DisplayInfo* info) -{ - MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); - - // Implementation mimic android SurfaceFlinger::getDisplayConfigs(). - - class Density { - static int getDensityFromProperty(char const* propName) { - char property[PROPERTY_VALUE_MAX]; - int density = 0; - if (property_get(propName, property, NULL) > 0) { - density = atoi(property); - } - return density; - } - public: - static int getEmuDensity() { - return getDensityFromProperty("qemu.sf.lcd_density"); } - static int getBuildDensity() { - return getDensityFromProperty("ro.sf.lcd_density"); } - }; - - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - - float xdpi = screen->GetDpi(); - float ydpi = screen->GetDpi(); - int fps = 60; // XXX set a value from hwc hal - nsIntRect screenBounds = screen->GetNaturalBounds().ToUnknownRect(); - - // The density of the device is provided by a build property - float density = Density::getBuildDensity() / 160.0f; - if (density == 0) { - // the build doesn't provide a density -- this is wrong! - // use xdpi instead - ALOGE("ro.sf.lcd_density must be defined as a build property"); - density = xdpi / 160.0f; - } - info->density = density; - info->orientation = screen->EffectiveScreenRotation(); - - info->w = screenBounds.width; - info->h = screenBounds.height; - info->xdpi = xdpi; - info->ydpi = ydpi; - info->fps = fps; -#if ANDROID_VERSION >= 21 - info->appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS; - - // This is how far in advance a buffer must be queued for - // presentation at a given time. If you want a buffer to appear - // on the screen at time N, you must submit the buffer before - // (N - presentationDeadline). - // - // Normally it's one full refresh period (to give SF a chance to - // latch the buffer), but this can be reduced by configuring a - // DispSync offset. Any additional delays introduced by the hardware - // composer or panel must be accounted for here. - // - // We add an additional 1ms to allow for processing time and - // differences between the ideal and actual refresh rate. - info->presentationDeadline = - (1e9 / fps) - SF_VSYNC_EVENT_PHASE_OFFSET_NS + 1000000; -#endif - // All non-virtual displays are currently considered secure. - info->secure = true; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/FakeSurfaceComposer.h b/widget/gonk/nativewindow/FakeSurfaceComposer.h deleted file mode 100644 index 97a717444..000000000 --- a/widget/gonk/nativewindow/FakeSurfaceComposer.h +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_FAKE_SURFACE_COMPOSER_H -#define NATIVEWINDOW_FAKE_SURFACE_COMPOSER_H - -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -class nsIWidget; - -namespace android { - -// --------------------------------------------------------------------------- - -class GraphicProducerWrapper; -class IGraphicBufferAlloc; - -enum { - eTransactionNeeded = 0x01, - eTraversalNeeded = 0x02, - eDisplayTransactionNeeded = 0x04, - eTransactionMask = 0x07 -}; - -class FakeSurfaceComposer : public BinderService, - public BnSurfaceComposer -{ -public: - static char const* getServiceName() { - return "FakeSurfaceComposer"; - } - - // Instantiate FakeSurfaceComposer and register to service manager. - // If service manager is not present, wait until service manager becomes present. - static void instantiate(); - -#if ANDROID_VERSION >= 19 - virtual void destroyDisplay(const sp& display); -#endif - -#if ANDROID_VERSION >= 21 - virtual status_t captureScreen(const sp& display, - const sp& producer, - Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, - bool useIdentityTransform, - Rotation rotation = eRotateNone); -#elif ANDROID_VERSION >= 19 - virtual status_t captureScreen(const sp& display, - const sp& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ); -#else - virtual status_t captureScreen(const sp& display, - const sp& producer, - uint32_t reqWidth, uint32_t reqHeight, - uint32_t minLayerZ, uint32_t maxLayerZ, bool isCpuConsumer); -#endif - -private: - FakeSurfaceComposer(); - // We're reference counted, never destroy FakeSurfaceComposer directly - virtual ~FakeSurfaceComposer(); - - /* ------------------------------------------------------------------------ - * IBinder interface - */ - virtual status_t onTransact(uint32_t code, const Parcel& data, - Parcel* reply, uint32_t flags); - - /* ------------------------------------------------------------------------ - * ISurfaceComposer interface - */ - virtual sp createConnection(); - virtual sp createGraphicBufferAlloc(); - virtual sp createDisplay(const String8& displayName, bool secure); - virtual sp getBuiltInDisplay(int32_t id); - virtual void setTransactionState(const Vector& state, - const Vector& displays, uint32_t flags); - virtual void bootFinished(); - virtual bool authenticateSurfaceTexture( - const sp& bufferProducer) const; - virtual sp createDisplayEventConnection(); -#if ANDROID_VERSION >= 21 - virtual void setPowerMode(const sp& display, int mode); - virtual status_t getDisplayConfigs(const sp& display, Vector* configs); - virtual status_t getDisplayStats(const sp& display, DisplayStatInfo* stats); - virtual int getActiveConfig(const sp& display); - virtual status_t setActiveConfig(const sp& display, int id); - virtual status_t clearAnimationFrameStats(); - virtual status_t getAnimationFrameStats(FrameStats* outStats) const; -#elif ANDROID_VERSION >= 17 - // called when screen needs to turn off - virtual void blank(const sp& display); - // called when screen is turning back on - virtual void unblank(const sp& display); - virtual status_t getDisplayInfo(const sp& display, DisplayInfo* info); -#endif - void getPrimaryDisplayInfo(DisplayInfo* info); - - /* ------------------------------------------------------------------------ - * Transactions - */ - uint32_t setDisplayStateLocked(const DisplayState& s); - - void captureScreenImp(const sp& producer, - uint32_t reqWidth, - uint32_t reqHeight, - const sp& wrapper); - - sp mPrimaryDisplay; - - struct DisplayDeviceState { - enum { - NO_LAYER_STACK = 0xFFFFFFFF, - }; - DisplayDeviceState() - : type(-1), displayId(-1), width(0), height(0) { - } - DisplayDeviceState(int type) - : type(type), displayId(-1), layerStack(NO_LAYER_STACK), orientation(0), width(0), height(0) { - viewport.makeInvalid(); - frame.makeInvalid(); - } - bool isValid() const { return type >= 0; } - int type; - int displayId; - sp surface; - uint32_t layerStack; - Rect viewport; - Rect frame; - uint8_t orientation; - uint32_t width, height; - String8 displayName; - bool isSecure; - }; - - // access must be protected by mStateLock - mutable Mutex mStateLock; - DefaultKeyedVector, DisplayDeviceState> mDisplays; - - friend class DestroyDisplayRunnable; -}; - -// --------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_FAKE_SURFACE_COMPOSER_H diff --git a/widget/gonk/nativewindow/GonkBufferQueue.h b/widget/gonk/nativewindow/GonkBufferQueue.h deleted file mode 100644 index defdb0ae2..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueue.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "GonkBufferQueueLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "GonkBufferQueueKK.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 -# include "GonkBufferQueueJB.h" -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp b/widget/gonk/nativewindow/GonkBufferQueueJB.cpp deleted file mode 100644 index 81502f81e..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueJB.cpp +++ /dev/null @@ -1,1036 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" - -#include "GonkBufferQueueJB.h" - -// Macros for including the GonkBufferQueue name in log messages -#define ST_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#define ST_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define ST_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define ST_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define ST_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - -#define ATRACE_BUFFER_INDEX(index) - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -static const char* scalingModeName(int scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode, - const sp& allocator) : - mDefaultWidth(1), - mDefaultHeight(1), - mMaxAcquiredBufferCount(1), - mDefaultMaxBufferCount(2), - mOverrideMaxBufferCount(0), - mSynchronousMode(true), - mAllowSynchronousMode(allowSynchronousMode), - mConnectedApi(NO_CONNECTED_API), - mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mConsumerUsageBits(0), - mTransformHint(0) -{ - // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - ST_LOGV("GonkBufferQueue"); -} - -GonkBufferQueue::~GonkBufferQueue() { - ST_LOGV("~GonkBufferQueue"); -} - -status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) { - if (count < 2 || count > NUM_BUFFER_SLOTS) - return BAD_VALUE; - - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -bool GonkBufferQueue::isSynchronousMode() const { - Mutex::Autolock lock(mMutex); - return mSynchronousMode; -} - -void GonkBufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock lock(mMutex); - mDefaultBufferFormat = defaultFormat; - return NO_ERROR; -} - -status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) { - Mutex::Autolock lock(mMutex); - mConsumerUsageBits = usage; - return NO_ERROR; -} - -status_t GonkBufferQueue::setTransformHint(uint32_t hint) { - ST_LOGV("setTransformHint: %02x", hint); - Mutex::Autolock lock(mMutex); - mTransformHint = hint; - return NO_ERROR; -} - -already_AddRefed -GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) -{ - Mutex::Autolock _l(mMutex); - if (buffer == NULL) { - ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return nullptr; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { - RefPtr client(mSlots[i].mTextureClient); - return client.forget(); - } - } - ST_LOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return nullptr; -} - -int GonkBufferQueue::getSlotFromTextureClientLocked( - TextureClient* client) const -{ - if (client == NULL) { - ST_LOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return BAD_VALUE; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mTextureClient == client) { - return i; - } - } - ST_LOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); - return BAD_VALUE; -} - - -status_t GonkBufferQueue::setBufferCount(int bufferCount) { - ST_LOGV("setBufferCount: count=%d", bufferCount); - - sp listener; - { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setBufferCount: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (bufferCount > NUM_BUFFER_SLOTS) { - ST_LOGE("setBufferCount: bufferCount too large (max %d)", - NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - // Error out if the user has dequeued buffers - int maxBufferCount = getMaxBufferCountLocked(); - for (int i=0 ; ionBuffersReleased(); - } - - return NO_ERROR; -} - -int GonkBufferQueue::query(int what, int* outValue) -{ - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("query: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mDefaultBufferFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = getMinUndequeuedBufferCountLocked(); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mQueue.size() >= 2); - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - -status_t GonkBufferQueue::requestBuffer(int slot, sp* buf) { - ST_LOGV("requestBuffer: slot=%d", slot); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("requestBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - int maxBufferCount = getMaxBufferCountLocked(); - if (slot < 0 || maxBufferCount <= slot) { - ST_LOGE("requestBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, slot); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - // XXX: I vaguely recall there was some reason this can be valid, but - // for the life of me I can't recall under what circumstances that's - // the case. - ST_LOGE("requestBuffer: slot %d is not owned by the client (state=%d)", - slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp* outFence, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); - - if ((w && !h) || (!w && h)) { - ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); - return BAD_VALUE; - } - - status_t returnFlags(OK); - int buf = INVALID_BUFFER_SLOT; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (format == 0) { - format = mDefaultBufferFormat; - } - // turn on usage bits the consumer requested - usage |= mConsumerUsageBits; - - int found = -1; - int dequeuedCount = 0; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ST_LOGE("dequeueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - const int maxBufferCount = getMaxBufferCountLocked(); - - // Free up any buffers that are in slots beyond the max buffer - // count. - //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - // assert(mSlots[i].mBufferState == BufferSlot::FREE); - // if (mSlots[i].mGraphicBuffer != NULL) { - // freeBufferLocked(i); - // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; - // } - //} - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - dequeuedCount = 0; - for (int i = 0; i < maxBufferCount; i++) { - const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; - } - - if (state == BufferSlot::FREE) { - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - if ((found < 0) || - mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { - found = i; - } - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mOverrideMaxBufferCount && dequeuedCount) { - ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below. - if (mBufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = getMinUndequeuedBufferCountLocked(); - if (newUndequeuedCount < minUndequeuedCount) { - ST_LOGE("dequeueBuffer: min undequeued buffer count (%d) " - "exceeded (dequeued=%d undequeudCount=%d)", - minUndequeuedCount, dequeuedCount, - newUndequeuedCount); - return -EBUSY; - } - } - - // If no buffer is found, wait for a buffer to be released or for - // the max buffer count to change. - tryAgain = found == INVALID_BUFFER_SLOT; - if (tryAgain) { - mDequeueCondition.wait(mMutex); - } - } - - - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ST_LOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - buf = found; - *outBuf = found; - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - mSlots[buf].mAcquireCalled = false; - mSlots[buf].mGraphicBuffer = NULL; - mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = Fence::NO_FENCE; - if (mSlots[buf].mTextureClient) { - mSlots[buf].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr task = - MakeAndAddRef(mSlots[buf].mTextureClient); - mSlots[buf].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; - } - - *outFence = mSlots[buf].mFence; - mSlots[buf].mFence = Fence::NO_FENCE; - } // end lock scope - - sp graphicBuffer; - if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - RefPtr allocator = ImageBridgeChild::GetSingleton(); - GrallocTextureData* texData = GrallocTextureData::Create(IntSize(w,h), format, - gfx::BackendType::NONE, usage, - allocator); - if (!texData) { - ST_LOGE("dequeueBuffer: failed to alloc gralloc buffer"); - return -ENOMEM; - } - RefPtr textureClient = new TextureClient(texData, TextureFlags::RECYCLE | TextureFlags::DEALLOCATE_CLIENT, allocator); - sp graphicBuffer = texData->GetGraphicBuffer(); - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - mSlots[buf].mGraphicBuffer = graphicBuffer; - mSlots[buf].mTextureClient = textureClient; - ST_LOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, - mSlots[buf].mGraphicBuffer->handle); - //mSlots[*outBuf].mGraphicBuffer = graphicBuffer; - } - } - - ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf, - mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t GonkBufferQueue::setSynchronousMode(bool enabled) { - ST_LOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mSynchronousMode != enabled) { - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return OK; -} - -status_t GonkBufferQueue::queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output) { - - Rect crop; - uint32_t transform; - int scalingMode; - int64_t timestamp; - sp fence; - - input.deflate(×tamp, &crop, &scalingMode, &transform, &fence); - -#if ANDROID_VERSION >= 18 - if (fence == NULL) { - ST_LOGE("queueBuffer: fence is NULL"); - return BAD_VALUE; - } -#endif - - ST_LOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " - "scale=%s", - buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - sp listener; - - { // scope for the lock - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ST_LOGE("queueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - int maxBufferCount = getMaxBufferCountLocked(); - if (buf < 0 || buf >= maxBufferCount) { - ST_LOGE("queueBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); - return -EINVAL; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("queueBuffer: slot %d is not owned by the client " - "(state=%d)", buf, mSlots[buf].mBufferState); - return -EINVAL; - } else if (!mSlots[buf].mRequestBufferCalled) { - ST_LOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", buf); - return -EINVAL; - } - - const sp& graphicBuffer(mSlots[buf].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedCrop; - crop.intersect(bufferRect, &croppedCrop); - if (croppedCrop != crop) { - ST_LOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", buf); - return -EINVAL; - } - - if (mSynchronousMode) { - // In synchronous mode we queue all buffers in a FIFO. - mQueue.push_back(buf); - } else { - // In asynchronous mode we only keep the most recent buffer. - if (mQueue.empty()) { - mQueue.push_back(buf); - } else { - Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; - // and we record the new buffer index in the queued list - *front = buf; - } - } - // always signals that an additional frame should be consumed - // to handle max acquired buffer count reached case. - listener = mConsumerListener; - - mSlots[buf].mTimestamp = timestamp; - mSlots[buf].mCrop = crop; - mSlots[buf].mTransform = transform; - mSlots[buf].mFence = fence; - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - break; - default: - ST_LOGE("unknown scaling mode: %d (ignoring)", scalingMode); - scalingMode = mSlots[buf].mScalingMode; - break; - } - - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mSlots[buf].mScalingMode = scalingMode; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - - mBufferHasBeenQueued = true; - mDequeueCondition.broadcast(); - - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - } // scope for the lock - - // call back without lock held - if (listener != 0) { - listener->onFrameAvailable(); - } - return NO_ERROR; -} - -#if ANDROID_VERSION == 17 -void GonkBufferQueue::cancelBuffer(int buf, sp fence) { -#else -void GonkBufferQueue::cancelBuffer(int buf, const sp& fence) { -#endif - - ST_LOGV("cancelBuffer: slot=%d", buf); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGW("cancelBuffer: GonkBufferQueue has been abandoned!"); - return; - } - - int maxBufferCount = getMaxBufferCountLocked(); - if (buf < 0 || buf >= maxBufferCount) { - ST_LOGE("cancelBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); - return; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ST_LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - buf, mSlots[buf].mBufferState); - return; -#if ANDROID_VERSION >= 18 - } else if (fence == NULL) { - ST_LOGE("cancelBuffer: fence is NULL"); - return; -#endif - } - mSlots[buf].mBufferState = BufferSlot::FREE; - mSlots[buf].mFrameNumber = 0; - mSlots[buf].mFence = fence; - mDequeueCondition.broadcast(); -} - -status_t GonkBufferQueue::connect(int api, QueueBufferOutput* output) { - ST_LOGV("connect: api=%d", api); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("connect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mConsumerListener == NULL) { - ST_LOGE("connect: GonkBufferQueue has no consumer!"); - return NO_INIT; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi != NO_CONNECTED_API) { - ST_LOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } else { - mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - } - break; - default: - err = -EINVAL; - break; - } - - mBufferHasBeenQueued = false; - - return err; -} - -status_t GonkBufferQueue::disconnect(int api) { - ST_LOGV("disconnect: api=%d", api); - - int err = NO_ERROR; - sp listener; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // it is not really an error to disconnect after the surface - // has been abandoned, it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - freeAllBuffersLocked(); - mConnectedApi = NO_CONNECTED_API; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } else { - ST_LOGE("disconnect: connected to another api (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } - break; - default: - ST_LOGE("disconnect: unknown API %d", api); - err = -EINVAL; - break; - } - } - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return err; -} - -void GonkBufferQueue::dumpToString(String8& result) const -{ - char buffer[1024]; - GonkBufferQueue::dumpToString(result, "", buffer, 1024); -} - -void GonkBufferQueue::dumpToString(String8& result, const char* prefix, - char* buffer, size_t SIZE) const -{ - Mutex::Autolock _l(mMutex); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } - - int maxBufferCount = getMaxBufferCountLocked(); - - snprintf(buffer, SIZE, - "%s-BufferQueue maxBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, maxBufferCount, mSynchronousMode, mDefaultWidth, - mDefaultHeight, mDefaultBufferFormat, mTransformHint, - fifoSize, fifo.string()); - result.append(buffer); - - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - for (int i=0 ; i":" ", i, - stateName(slot.mBufferState), - slot.mCrop.left, slot.mCrop.top, slot.mCrop.right, - slot.mCrop.bottom, slot.mTransform, slot.mTimestamp, - scalingModeName(slot.mScalingMode) - ); - result.append(buffer); - - const sp& buf(slot.mGraphicBuffer); - if (buf != NULL) { - snprintf(buffer, SIZE, - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - result.append(buffer); - } - result.append("\n"); - } -} - -void GonkBufferQueue::freeAllBuffersLocked() -{ - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].mGraphicBuffer = 0; - if (mSlots[i].mTextureClient) { - mSlots[i].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr task = - MakeAndAddRef(mSlots[i].mTextureClient); - mSlots[i].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - mSlots[i].mNeedsCleanupOnRelease = true; - } - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - // destroy fence as GonkBufferQueue now takes ownership - mSlots[i].mFence = Fence::NO_FENCE; - } -} - -status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer) { - Mutex::Autolock _l(mMutex); - - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer, so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - numAcquiredBuffers++; - } - } - if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) { - ST_LOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)", - numAcquiredBuffers, mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (!mQueue.empty()) { - Fifo::iterator front(mQueue.begin()); - int buf = *front; - - // In android, when the buffer is aquired by BufferConsumer, - // BufferQueue releases a reference to the buffer and - // it's ownership moves to the BufferConsumer. - // In b2g, GonkBufferQueue continues to have a buffer ownership. - // It is necessary to free buffer via ImageBridgeChild. - - //if (mSlots[buf].mAcquireCalled) { - // buffer->mGraphicBuffer = NULL; - //} else { - // buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - //} - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - buffer->mCrop = mSlots[buf].mCrop; - buffer->mTransform = mSlots[buf].mTransform; - buffer->mScalingMode = mSlots[buf].mScalingMode; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mTimestamp = mSlots[buf].mTimestamp; - buffer->mBuf = buf; - buffer->mFence = mSlots[buf].mFence; - - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; - - mQueue.erase(front); - mDequeueCondition.broadcast(); - } else { - return NO_BUFFER_AVAILABLE; - } - - return NO_ERROR; -} - -status_t GonkBufferQueue::releaseBuffer(int buf, const sp& fence) { - Mutex::Autolock _l(mMutex); - -#if ANDROID_VERSION == 17 - if (buf == INVALID_BUFFER_SLOT) { -#else - if (buf == INVALID_BUFFER_SLOT || fence == NULL) { -#endif - return BAD_VALUE; - } - - mSlots[buf].mFence = fence; - - // The buffer can now only be released if its in the acquired state - if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mBufferState = BufferSlot::FREE; - } else if (mSlots[buf].mNeedsCleanupOnRelease) { - ST_LOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); - mSlots[buf].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ST_LOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); - return -EINVAL; - } - - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerConnect(const sp& consumerListener) { - ST_LOGV("consumerConnect"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("consumerConnect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (consumerListener == NULL) { - ST_LOGE("consumerConnect: consumerListener may not be NULL"); - return BAD_VALUE; - } - - mConsumerListener = consumerListener; - - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerDisconnect() { - ST_LOGV("consumerDisconnect"); - Mutex::Autolock lock(mMutex); - - if (mConsumerListener == NULL) { - ST_LOGE("consumerDisconnect: No consumer is connected!"); - return -EINVAL; - } - - mAbandoned = true; - mConsumerListener = NULL; - mQueue.clear(); - freeAllBuffersLocked(); - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) { - ST_LOGV("getReleasedBuffers"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ST_LOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - uint32_t mask = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (!mSlots[i].mAcquireCalled) { - mask |= 1 << i; - } - } - *slotMask = mask; - - ST_LOGV("getReleasedBuffers: returning mask %#x", mask); - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) -{ - ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) { - Mutex::Autolock lock(mMutex); - return setDefaultMaxBufferCountLocked(bufferCount); -} - -status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Mutex::Autolock lock(mMutex); - if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) { - ST_LOGE("setMaxAcquiredBufferCount: invalid count specified: %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - if (mConnectedApi != NO_CONNECTED_API) { - return INVALID_OPERATION; - } - mMaxAcquiredBufferCount = maxAcquiredBuffers; - return NO_ERROR; -} - -int GonkBufferQueue::getMinMaxBufferCountLocked() const { - return getMinUndequeuedBufferCountLocked() + 1; -} - -int GonkBufferQueue::getMinUndequeuedBufferCountLocked() const { - return mSynchronousMode ? mMaxAcquiredBufferCount : - mMaxAcquiredBufferCount + 1; -} - -int GonkBufferQueue::getMaxBufferCountLocked() const { - int minMaxBufferCount = getMinMaxBufferCountLocked(); - - int maxBufferCount = mDefaultMaxBufferCount; - if (maxBufferCount < minMaxBufferCount) { - maxBufferCount = minMaxBufferCount; - } - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } - - // Any buffers that are dequeued by the producer or sitting in the queue - // waiting to be consumed need to have their slots preserved. Such - // buffers will temporarily keep the max buffer count up until the slots - // no longer need to be preserved. - for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - BufferSlot::BufferState state = mSlots[i].mBufferState; - if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { - maxBufferCount = i + 1; - } - } - - return maxBufferCount; -} - -GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp& consumerListener): - mConsumerListener(consumerListener) {} - -GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueJB.h b/widget/gonk/nativewindow/GonkBufferQueueJB.h deleted file mode 100644 index df0c4599f..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueJB.h +++ /dev/null @@ -1,653 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_JB_H -#define NATIVEWINDOW_GONKBUFFERQUEUE_JB_H - -#include -#if ANDROID_VERSION == 17 -#include -#else -#include -#endif - -#include -#include - -#include -#include -#include - -#include "mozilla/layers/LayersSurfaces.h" -#include "mozilla/layers/TextureClient.h" - -#if ANDROID_VERSION == 17 -#define IGraphicBufferProducer ISurfaceTexture -#endif - -namespace android { -// ---------------------------------------------------------------------------- - -#if ANDROID_VERSION == 17 -class GonkBufferQueue : public BnSurfaceTexture { -#else -class GonkBufferQueue : public BnGraphicBufferProducer { -#endif - typedef mozilla::layers::TextureClient TextureClient; - -public: - enum { MIN_UNDEQUEUED_BUFFERS = 2 }; - enum { NUM_BUFFER_SLOTS = 32 }; - enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; - enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE }; - - // When in async mode we reserve two slots in order to guarantee that the - // producer and consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - - // ConsumerListener is the interface through which the GonkBufferQueue notifies - // the consumer of events that the consumer may wish to react to. Because - // the consumer will generally have a mutex that is locked during calls from - // the consumer to the GonkBufferQueue, these calls from the GonkBufferQueue to the - // consumer *MUST* be called only when the GonkBufferQueue mutex is NOT locked. - struct ConsumerListener : public virtual RefBase { - // onFrameAvailable is called from queueBuffer each time an additional - // frame becomes available for consumption. This means that frames that - // are queued while in asynchronous mode only trigger the callback if no - // previous frames are pending. Frames queued while in synchronous mode - // always trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - - // onBuffersReleased is called to notify the buffer consumer that the - // GonkBufferQueue has released its references to one or more GraphicBuffers - // contained in its slots. The buffer consumer should then call - // GonkBufferQueue::getReleasedBuffers to retrieve the list of buffers - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onBuffersReleased() = 0; - }; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // GonkBufferQueue object and the consumer object. The reason this can't be a weak - // reference in the GonkBufferQueue class is because we're planning to expose the - // consumer side of a GonkBufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public GonkBufferQueue::ConsumerListener { - public: - - ProxyConsumerListener(const wp& consumerListener); - virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - private: - - // mConsumerListener is a weak reference to the ConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp mConsumerListener; - }; - - - // GonkBufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allowSynchronousMode specifies whether or not - // synchronous mode can be enabled by the producer. allocator is used to - // allocate all the needed gralloc buffers. - GonkBufferQueue(bool allowSynchronousMode = true, - const sp& allocator = NULL); - virtual ~GonkBufferQueue(); - - // Query native window attributes. The "what" values are enumerated in - // window.h (e.g. NATIVE_WINDOW_FORMAT). - virtual int query(int what, int* value); - - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the GonkBufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); - - // requestBuffer returns the GraphicBuffer for slot N. - // - // In normal operation, this is called the first time slot N is returned - // by dequeueBuffer. It must be called again if dequeueBuffer returns - // flags indicating that previously-returned buffers are no longer valid. - virtual status_t requestBuffer(int slot, sp* buf); - - // dequeueBuffer gets the next buffer slot index for the producer to use. - // If a buffer slot is available then that slot index is written to the - // location pointed to by the buf argument and a status of OK is returned. - // If no slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // - // The fence parameter will be updated to hold the fence associated with - // the buffer. The contents of the buffer must not be overwritten until the - // fence signals. If the fence is Fence::NO_FENCE, the buffer may be - // written immediately. - // - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. If width and height are both zero, the - // default values specified by setDefaultBufferSize() are used instead. - // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. - // - // The usage argument specifies gralloc buffer usage flags. The values - // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These - // will be merged with the usage flags specified by setConsumerUsageBits. - // - // The return value may be a negative error value or a non-negative - // collection of flags. If the flags are set, the return values are - // valid, but additional actions must be performed. - // - // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the - // producer must discard cached GraphicBuffer references for the slot - // returned in buf. - // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer - // must discard cached GraphicBuffer references for all slots. - // - // In both cases, the producer will need to call requestBuffer to get a - // GraphicBuffer handle for the returned slot. -#if ANDROID_VERSION == 17 - virtual status_t dequeueBuffer(int *buf, sp& fence, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { - return dequeueBuffer(buf, &fence, width, height, format, usage); - } -#endif - - virtual status_t dequeueBuffer(int *buf, sp* fence, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); - - // queueBuffer returns a filled buffer to the GonkBufferQueue. - // - // Additional data is provided in the QueueBufferInput struct. Notably, - // a timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are producer-specific and should be documented by the - // producer. - // - // The caller may provide a fence that signals when all rendering - // operations have completed. Alternatively, NO_FENCE may be used, - // indicating that the buffer is ready immediately. - // - // Some values are returned in the output struct: the current settings - // for default width and height, the current transform hint, and the - // number of queued buffers. - virtual status_t queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output); - - // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't - // queue it for use by the consumer. - // - // The buffer will not be overwritten until the fence signals. The fence - // will usually be the one obtained from dequeueBuffer. -#if ANDROID_VERSION == 17 - virtual void cancelBuffer(int buf, sp fence); -#else - virtual void cancelBuffer(int buf, const sp& fence); -#endif - - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is synchronous. - // This should be called only during initialization. - virtual status_t setSynchronousMode(bool enabled); - - // connect attempts to connect a producer API to the GonkBufferQueue. This - // must be called before any other IGraphicBufferProducer methods are - // called except for getAllocator. A consumer must already be connected. - // - // This method will fail if connect was previously called on the - // GonkBufferQueue and no corresponding disconnect call was made (i.e. if - // it's still connected to a producer). - // - // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(int api, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer API from the GonkBufferQueue. - // Calling this method will cause any subsequent calls to other - // IGraphicBufferProducer methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the GonkBufferQueue is not currently - // connected to the specified producer API. - virtual status_t disconnect(int api); - - // dump our state in a String - virtual void dumpToString(String8& result) const; - virtual void dumpToString(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - - // public facing structure for BufferSlot - struct BufferItem { - - BufferItem() - : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT) { - mCrop.makeInvalid(); - } - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp mGraphicBuffer; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer - int mBuf; - - // mFence is a fence that will signal when the buffer is idle. - sp mFence; - }; - - // The following public functions are the consumer-facing interface - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the GonkBufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - status_t acquireBuffer(BufferItem *buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // GonkBufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - status_t releaseBuffer(int buf, const sp& releaseFence); - - // consumerConnect connects a consumer to the GonkBufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // GonkBufferQueue is placed into the "abandoned" state, causing most - // interactions with the GonkBufferQueue by the producer to fail. - // - // consumer may not be NULL. - status_t consumerConnect(const sp& consumer); - - // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All - // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" - // state, causing most interactions with the GonkBufferQueue by the producer to - // fail. - status_t consumerDisconnect(); - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots have been released by the GonkBufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - status_t getReleasedBuffers(uint32_t* slotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - status_t setDefaultMaxBufferCount(int bufferCount); - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the GonkBufferQueue. - status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - - // isSynchronousMode returns whether the GonkBufferQueue is currently in - // synchronous mode. - bool isSynchronousMode() const; - - // setConsumerName sets the name used in logging - void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - status_t setTransformHint(uint32_t hint); - - already_AddRefed getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - int getSlotFromTextureClientLocked(TextureClient* client) const; - -private: - // freeBufferLocked frees the GraphicBuffer and sync resources for the - // given slot. - //void freeBufferLocked(int index); - - // freeAllBuffersLocked frees the GraphicBuffer and sync resources for - // all slots. - //void freeAllBuffersLocked(); - void freeAllBuffersLocked(); - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - // The initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); - - // getMinBufferCountLocked returns the minimum number of buffers allowed - // given the current GonkBufferQueue state. - int getMinMaxBufferCountLocked() const; - - // getMinUndequeuedBufferCountLocked returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. - int getMinUndequeuedBufferCountLocked() const; - - // getMaxBufferCountLocked returns the maximum number of buffers that can - // be allocated at once. This value depends upon the following member - // variables: - // - // mSynchronousMode - // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // - // Any time one of these member variables is changed while a producer is - // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked() const; - - struct BufferSlot { - - BufferSlot() - : mBufferState(BufferSlot::FREE), - mRequestBufferCalled(false), - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mFrameNumber(0), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false) { - mCrop.makeInvalid(); - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. - RefPtr mTextureClient; - - // BufferState represents the different states in which a buffer slot - // can be. All slots are initially FREE. - enum BufferState { - // FREE indicates that the buffer is available to be dequeued - // by the producer. The buffer may be in use by the consumer for - // a finite time, so the buffer must not be modified until the - // associated fence is signaled. - // - // The slot is "owned" by GonkBufferQueue. It transitions to DEQUEUED - // when dequeueBuffer is called. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // producer, but has not yet been queued or canceled. The - // producer may modify the buffer's contents as soon as the - // associated ready fence is signaled. - // - // The slot is "owned" by the producer. It can transition to - // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been filled by the - // producer and queued for use by the consumer. The buffer - // contents may continue to be modified for a finite time, so - // the contents must not be accessed until the associated fence - // is signaled. - // - // The slot is "owned" by GonkBufferQueue. It can transition to - // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is - // queued in asynchronous mode). - QUEUED = 2, - - // ACQUIRED indicates that the buffer has been acquired by the - // consumer. As with QUEUED, the contents must not be accessed - // by the consumer until the fence is signaled. - // - // The slot is "owned" by the consumer. It transitions to FREE - // when releaseBuffer is called. - ACQUIRED = 3 - }; - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the producer did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching producer bugs. - bool mRequestBufferCalled; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // (example: NATIVE_WINDOW_TRANSFORM_ROT_90) - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // (example: NATIVE_WINDOW_SCALING_MODE_FREEZE) - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. This - // is used to dequeue buffers in LRU order (useful because buffers - // may be released before their release fence is signaled). - uint64_t mFrameNumber; - - // mEglFence is the EGL sync object that must signal before the buffer - // associated with this buffer slot may be dequeued. It is initialized - // to EGL_NO_SYNC_KHR when the buffer is created and may be set to a - // new sync object in releaseBuffer. (This is deprecated in favor of - // mFence, below.) - //EGLSyncKHR mEglFence; - - // mFence is a fence which will signal when work initiated by the - // previous owner of the buffer is finished. When the buffer is FREE, - // the fence indicates when the consumer has finished reading - // from the buffer, or when the producer has finished writing if it - // called cancelBuffer after queueing some writes. When the buffer is - // QUEUED, it indicates when the producer has finished filling the - // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been - // passed to the consumer or producer along with ownership of the - // buffer, and mFence is set to NO_FENCE. - sp mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by the - // consumer. This is set when a buffer in ACQUIRED state is freed. - // It causes releaseBuffer to return STALE_BUFFER_SLOT. - bool mNeedsCleanupOnRelease; - }; - - // mSlots is the array of buffer slots that must be mirrored on the - // producer side. This allows buffer ownership to be transferred between - // the producer and consumer without sending a GraphicBuffer over binder. - // The entire array is initialized to NULL at construction time, and - // buffers are allocated for a slot when requestBuffer is called with - // that slot's index. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultHeight; - - // mMaxAcquiredBufferCount is the number of buffers that the consumer may - // acquire at one time. It defaults to 1 and can be changed by the - // consumer via the setMaxAcquiredBufferCount method, but this may only be - // done when no producer is connected to the GonkBufferQueue. - // - // This value is used to derive the value returned for the - // MIN_UNDEQUEUED_BUFFERS query by the producer. - int mMaxAcquiredBufferCount; - - // mDefaultMaxBufferCount is the default limit on the number of buffers - // that will be allocated at one time. This default limit is set by the - // consumer. The limit (as opposed to the default limit) may be - // overridden by the producer. - int mDefaultMaxBufferCount; - - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the image producer by - // calling setBufferCount. The default is zero, which means the producer - // doesn't care about the number of buffers in the pool. In that case - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - - // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to - // allocate new GraphicBuffer objects. - sp mGraphicBufferAlloc; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially set - // to NULL and is written by consumerConnect and consumerDisconnect. - sp mConsumerListener; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - // mAllowSynchronousMode whether we allow synchronous mode or not. Set - // when the GonkBufferQueue is created (by the consumer). - const bool mAllowSynchronousMode; - - // mConnectedApi indicates the producer API that is currently connected - // to this GonkBufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets - // updated by the connect and disconnect methods. - int mConnectedApi; - - // mDequeueCondition condition used for dequeueBuffer in synchronous mode - mutable Condition mDequeueCondition; - - // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector Fifo; - Fifo mQueue; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume image buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A GonkBufferQueue that has been abandoned will - // return the NO_INIT error from all IGraphicBufferProducer methods - // capable of returning an error. - bool mAbandoned; - - // mConsumerName is a string used to identify the GonkBufferQueue in log - // messages. It is set by the setConsumerName method. - String8 mConsumerName; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkBufferQueue objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call. - uint64_t mFrameCounter; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is - // reset when something causes all buffers to be freed (e.g. changing the - // buffer count). - bool mBufferHasBeenQueued; - - // mDefaultBufferFormat can be set so it will override - // the buffer format when it isn't specified in dequeueBuffer - uint32_t mDefaultBufferFormat; - - // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers - uint32_t mConsumerUsageBits; - - // mTransformHint is used to optimize for screen rotations - uint32_t mTransformHint; - -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp b/widget/gonk/nativewindow/GonkBufferQueueKK.cpp deleted file mode 100644 index 0c5cdfeb9..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueKK.cpp +++ /dev/null @@ -1,1265 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define GL_GLEXT_PROTOTYPES -#define EGL_EGLEXT_PROTOTYPES - -#include -#include -#include -#include - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "GonkBufferQueueKK.h" - -#define ATRACE_BUFFER_INDEX(index) - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -static const char* scalingModeName(int scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -GonkBufferQueue::GonkBufferQueue(bool allowSynchronousMode, - const sp& allocator) : - mDefaultWidth(1), - mDefaultHeight(1), - mMaxAcquiredBufferCount(1), - mDefaultMaxBufferCount(2), - mOverrideMaxBufferCount(0), - mSynchronousMode(true), - mConsumerControlledByApp(false), - mDequeueBufferCannotBlock(false), - mUseAsyncBuffer(true), - mConnectedApi(NO_CONNECTED_API), - mAbandoned(false), - mFrameCounter(0), - mBufferHasBeenQueued(false), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mConsumerUsageBits(0), - mTransformHint(0) -{ - // Choose a name using the PID and a process-unique ID. - mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - ALOGV("GonkBufferQueue"); -} - -GonkBufferQueue::~GonkBufferQueue() { - ALOGV("~GonkBufferQueue"); -} - -status_t GonkBufferQueue::setDefaultMaxBufferCountLocked(int count) { - if (count < 2 || count > NUM_BUFFER_SLOTS) - return BAD_VALUE; - - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -void GonkBufferQueue::setConsumerName(const String8& name) { - Mutex::Autolock lock(mMutex); - mConsumerName = name; -} - -status_t GonkBufferQueue::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock lock(mMutex); - mDefaultBufferFormat = defaultFormat; - return NO_ERROR; -} - -status_t GonkBufferQueue::setConsumerUsageBits(uint32_t usage) { - Mutex::Autolock lock(mMutex); - mConsumerUsageBits = usage; - return NO_ERROR; -} - -status_t GonkBufferQueue::setTransformHint(uint32_t hint) { - ALOGV("setTransformHint: %02x", hint); - Mutex::Autolock lock(mMutex); - mTransformHint = hint; - return NO_ERROR; -} - -already_AddRefed -GonkBufferQueue::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) -{ - Mutex::Autolock _l(mMutex); - if (buffer == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return nullptr; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { - RefPtr client(mSlots[i].mTextureClient); - return client.forget(); - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return nullptr; -} - -int GonkBufferQueue::getSlotFromTextureClientLocked( - TextureClient* client) const -{ - if (client == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return BAD_VALUE; - } - - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mTextureClient == client) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); - return BAD_VALUE; -} - -status_t GonkBufferQueue::setBufferCount(int bufferCount) { - ALOGV("setBufferCount: count=%d", bufferCount); - - sp listener; - { - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("setBufferCount: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (bufferCount > NUM_BUFFER_SLOTS) { - ALOGE("setBufferCount: bufferCount too large (max %d)", - NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - // Error out if the user has dequeued buffers - for (int i=0 ; ionBuffersReleased(); - } - - return NO_ERROR; -} - -int GonkBufferQueue::query(int what, int* outValue) -{ - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("query: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mDefaultBufferFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = getMinUndequeuedBufferCount(false); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mQueue.size() >= 2); - break; - case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - value = mConsumerUsageBits; - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - -status_t GonkBufferQueue::requestBuffer(int slot, sp* buf) { - ATRACE_CALL(); - ALOGV("requestBuffer: slot=%d", slot); - Mutex::Autolock lock(mMutex); - if (mAbandoned) { - ALOGE("requestBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (slot < 0 || slot >= NUM_BUFFER_SLOTS) { - ALOGE("requestBuffer: slot index out of range [0, %d]: %d", - NUM_BUFFER_SLOTS, slot); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("requestBuffer: slot %d is not owned by the client (state=%d)", - slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t GonkBufferQueue::dequeueBuffer(int *outBuf, sp* outFence, bool async, - uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { - ATRACE_CALL(); - ALOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage); - - if ((w && !h) || (!w && h)) { - ALOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h); - return BAD_VALUE; - } - - status_t returnFlags(OK); - int buf = INVALID_BUFFER_SLOT; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (format == 0) { - format = mDefaultBufferFormat; - } - // turn on usage bits the consumer requested - usage |= mConsumerUsageBits; - - int found = -1; - bool tryAgain = true; - while (tryAgain) { - if (mAbandoned) { - ALOGE("dequeueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - const int maxBufferCount = getMaxBufferCountLocked(async); - if (async && mOverrideMaxBufferCount) { - // FIXME: some drivers are manually setting the buffer-count (which they - // shouldn't), so we do this extra test here to handle that case. - // This is TEMPORARY, until we get this fixed. - if (mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("dequeueBuffer: async mode is invalid with buffercount override"); - return BAD_VALUE; - } - } - - // Free up any buffers that are in slots beyond the max buffer - // count. - //for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - // assert(mSlots[i].mBufferState == BufferSlot::FREE); - // if (mSlots[i].mGraphicBuffer != NULL) { - // freeBufferLocked(i); - // returnFlags |= IGraphicBufferProducer::RELEASE_ALL_BUFFERS; - // } - //} - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - int dequeuedCount = 0; - int acquiredCount = 0; - for (int i = 0; i < maxBufferCount; i++) { - const int state = mSlots[i].mBufferState; - switch (state) { - case BufferSlot::DEQUEUED: - dequeuedCount++; - break; - case BufferSlot::ACQUIRED: - acquiredCount++; - break; - case BufferSlot::FREE: - /* We return the oldest of the free buffers to avoid - * stalling the producer if possible. This is because - * the consumer may still have pending reads of the - * buffers in flight. - */ - if ((found < 0) || - mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) { - found = i; - } - break; - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mOverrideMaxBufferCount && dequeuedCount) { - ALOGE("dequeueBuffer: can't dequeue multiple buffers without " - "setting the buffer count"); - return -EINVAL; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below. - if (mBufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int newUndequeuedCount = maxBufferCount - (dequeuedCount+1); - const int minUndequeuedCount = getMinUndequeuedBufferCount(async); - if (newUndequeuedCount < minUndequeuedCount) { - ALOGE("dequeueBuffer: min undequeued buffer count (%d) " - "exceeded (dequeued=%d undequeudCount=%d)", - minUndequeuedCount, dequeuedCount, - newUndequeuedCount); - return -EBUSY; - } - } - - // If no buffer is found, wait for a buffer to be released or for - // the max buffer count to change. - tryAgain = found == INVALID_BUFFER_SLOT; - if (tryAgain) { - // return an error if we're in "cannot block" mode (producer and consumer - // are controlled by the application) -- however, the consumer is allowed - // to acquire briefly an extra buffer (which could cause us to have to wait here) - // and that's okay because we know the wait will be brief (it happens - // if we dequeue a buffer while the consumer has acquired one but not released - // the old one yet -- for e.g.: see GLConsumer::updateTexImage()). - if (mDequeueBufferCannotBlock && (acquiredCount <= mMaxAcquiredBufferCount)) { - ALOGE("dequeueBuffer: would block! returning an error instead."); - return WOULD_BLOCK; - } - mDequeueCondition.wait(mMutex); - } - } - - - if (found == INVALID_BUFFER_SLOT) { - // This should not happen. - ALOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - buf = found; - *outBuf = found; - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - mSlots[buf].mBufferState = BufferSlot::DEQUEUED; - - const sp& buffer(mSlots[buf].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) - { - mSlots[buf].mAcquireCalled = false; - mSlots[buf].mGraphicBuffer = NULL; - mSlots[buf].mRequestBufferCalled = false; - mSlots[buf].mFence = Fence::NO_FENCE; - if (mSlots[buf].mTextureClient) { - mSlots[buf].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr task = - MakeAndAddRef(mSlots[buf].mTextureClient); - mSlots[buf].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - returnFlags |= IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION; - } - - - if (CC_UNLIKELY(mSlots[buf].mFence == NULL)) { - ALOGE("dequeueBuffer: about to return a NULL fence from mSlot. " - "buf=%d, w=%d, h=%d, format=%d", - buf, buffer->width, buffer->height, buffer->format); - } - *outFence = mSlots[buf].mFence; - mSlots[buf].mFence = Fence::NO_FENCE; - } // end lock scope - - if (returnFlags & IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) { - - RefPtr allocator = ImageBridgeChild::GetSingleton(); - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - GrallocTextureData* texData = GrallocTextureData::Create(IntSize(w, h), format, - gfx::BackendType::NONE, usage, - allocator); - if (!texData) { - return -ENOMEM; - } - - RefPtr textureClient = new TextureClient(texData, TextureFlags::RECYCLE | TextureFlags::DEALLOCATE_CLIENT, allocator); - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("dequeueBuffer: SurfaceTexture has been abandoned!"); - return NO_INIT; - } - - mSlots[buf].mGraphicBuffer = texData->GetGraphicBuffer(); - mSlots[buf].mTextureClient = textureClient; - ALOGD("dequeueBuffer: returning slot=%d buf=%p ", buf, - mSlots[buf].mGraphicBuffer->handle); - - } - - } - - ALOGV("dequeueBuffer: returning slot=%d/%llu buf=%p flags=%#x", *outBuf, - mSlots[*outBuf].mFrameNumber, - mSlots[*outBuf].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t GonkBufferQueue::setSynchronousMode(bool enabled) { - ALOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mSynchronousMode != enabled) { - mSynchronousMode = enabled; - mDequeueCondition.broadcast(); - } - return OK; -} - -status_t GonkBufferQueue::queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output) { - ATRACE_CALL(); - - Rect crop; - uint32_t transform; - int scalingMode; - int64_t timestamp; - bool isAutoTimestamp; - bool async; - sp fence; - - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence); - - if (fence == NULL) { - ALOGE("queueBuffer: fence is NULL"); - return BAD_VALUE; - } - - ALOGV("queueBuffer: slot=%d time=%#llx crop=[%d,%d,%d,%d] tr=%#x " - "scale=%s", - buf, timestamp, crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: - break; - default: - ALOGE("unknown scaling mode: %d", scalingMode); - return -EINVAL; - } - - sp listener; - - { // scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("queueBuffer: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - const int maxBufferCount = getMaxBufferCountLocked(async); - if (async && mOverrideMaxBufferCount) { - // FIXME: some drivers are manually setting the buffer-count (which they - // shouldn't), so we do this extra test here to handle that case. - // This is TEMPORARY, until we get this fixed. - if (mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("queueBuffer: async mode is invalid with buffercount override"); - return BAD_VALUE; - } - } - if (buf < 0 || buf >= maxBufferCount) { - ALOGE("queueBuffer: slot index out of range [0, %d]: %d", - maxBufferCount, buf); - return -EINVAL; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("queueBuffer: slot %d is not owned by the client " - "(state=%d)", buf, mSlots[buf].mBufferState); - return -EINVAL; - } else if (!mSlots[buf].mRequestBufferCalled) { - ALOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", buf); - return -EINVAL; - } - - ALOGV("queueBuffer: slot=%d/%llu time=%#llx crop=[%d,%d,%d,%d] " - "tr=%#x scale=%s", - buf, mFrameCounter + 1, timestamp, - crop.left, crop.top, crop.right, crop.bottom, - transform, scalingModeName(scalingMode)); - - const sp& graphicBuffer(mSlots[buf].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedCrop; - crop.intersect(bufferRect, &croppedCrop); - if (croppedCrop != crop) { - ALOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", buf); - return -EINVAL; - } - - mSlots[buf].mFence = fence; - mSlots[buf].mBufferState = BufferSlot::QUEUED; - mFrameCounter++; - mSlots[buf].mFrameNumber = mFrameCounter; - - BufferItem item; - item.mAcquireCalled = mSlots[buf].mAcquireCalled; - item.mGraphicBuffer = mSlots[buf].mGraphicBuffer; - item.mCrop = crop; - item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; - item.mTransformToDisplayInverse = bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); - item.mScalingMode = scalingMode; - item.mTimestamp = timestamp; - item.mIsAutoTimestamp = isAutoTimestamp; - item.mFrameNumber = mFrameCounter; - item.mBuf = buf; - item.mFence = fence; - item.mIsDroppable = mDequeueBufferCannotBlock || async; - - if (mQueue.empty()) { - // when the queue is empty, we can ignore "mDequeueBufferCannotBlock", and - // simply queue this buffer. - mQueue.push_back(item); - } else { - // when the queue is not empty, we need to look at the front buffer - // state and see if we need to replace it. - Fifo::iterator front(mQueue.begin()); - if (front->mIsDroppable || !mSynchronousMode) { - // buffer slot currently queued is marked free if still tracked - if (stillTracking(front)) { - mSlots[front->mBuf].mBufferState = BufferSlot::FREE; - // reset the frame number of the freed buffer so that it is the first in - // line to be dequeued again. - mSlots[front->mBuf].mFrameNumber = 0; - } - // and we record the new buffer in the queued list - *front = item; - } else { - mQueue.push_back(item); - } - } - // always signals that an additional frame should be consumed - // to handle max acquired buffer count reached case. - listener = mConsumerListener; - - mBufferHasBeenQueued = true; - mDequeueCondition.broadcast(); - - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, - mQueue.size()); - - } // scope for the lock - - // call back without lock held - if (listener != 0) { - listener->onFrameAvailable(); - } - return NO_ERROR; -} - -void GonkBufferQueue::cancelBuffer(int buf, const sp& fence) { - ATRACE_CALL(); - ALOGV("cancelBuffer: slot=%d", buf); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGW("cancelBuffer: GonkBufferQueue has been abandoned!"); - return; - } - - if (buf < 0 || buf >= NUM_BUFFER_SLOTS) { - ALOGE("cancelBuffer: slot index out of range [0, %d]: %d", - NUM_BUFFER_SLOTS, buf); - return; - } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - buf, mSlots[buf].mBufferState); - return; - } else if (fence == NULL) { - ALOGE("cancelBuffer: fence is NULL"); - return; - } - mSlots[buf].mBufferState = BufferSlot::FREE; - mSlots[buf].mFrameNumber = 0; - mSlots[buf].mFence = fence; - mDequeueCondition.broadcast(); -} - - -status_t GonkBufferQueue::connect(const sp& token, - int api, bool producerControlledByApp, QueueBufferOutput* output) { - ATRACE_CALL(); - ALOGV("connect: api=%d producerControlledByApp=%s", api, - producerControlledByApp ? "true" : "false"); - Mutex::Autolock lock(mMutex); - -retry: - if (mAbandoned) { - ALOGE("connect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mConsumerListener == NULL) { - ALOGE("connect: GonkBufferQueue has no consumer!"); - return NO_INIT; - } - - if (mConnectedApi != NO_CONNECTED_API) { - ALOGE("connect: already connected (cur=%d, req=%d)", - mConnectedApi, api); - return -EINVAL; - } - - // If we disconnect and reconnect quickly, we can be in a state where our slots are - // empty but we have many buffers in the queue. This can cause us to run out of - // memory if we outrun the consumer. Wait here if it looks like we have too many - // buffers queued up. - int maxBufferCount = getMaxBufferCountLocked(false); // worst-case, i.e. largest value - if (mQueue.size() > (size_t) maxBufferCount) { - // TODO: make this bound tighter? - ALOGV("queue size is %d, waiting", mQueue.size()); - mDequeueCondition.wait(mMutex); - goto retry; - } - - int err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - mConnectedApi = api; - output->inflate(mDefaultWidth, mDefaultHeight, mTransformHint, mQueue.size()); - - // set-up a death notification so that we can disconnect - // automatically when/if the remote producer dies. - if (token != NULL && token->remoteBinder() != NULL) { - status_t err = token->linkToDeath(static_cast(this)); - if (err == NO_ERROR) { - mConnectedProducerToken = token; - } else { - ALOGE("linkToDeath failed: %s (%d)", strerror(-err), err); - } - } - break; - default: - err = -EINVAL; - break; - } - - mBufferHasBeenQueued = false; - mDequeueBufferCannotBlock = mConsumerControlledByApp && producerControlledByApp; - - return err; -} - -void GonkBufferQueue::binderDied(const wp& who) { - // If we're here, it means that a producer we were connected to died. - // We're GUARANTEED that we still are connected to it because it has no other way - // to get disconnected -- or -- we wouldn't be here because we're removing this - // callback upon disconnect. Therefore, it's okay to read mConnectedApi without - // synchronization here. - int api = mConnectedApi; - this->disconnect(api); -} - -status_t GonkBufferQueue::disconnect(int api) { - ATRACE_CALL(); - ALOGV("disconnect: api=%d", api); - - int err = NO_ERROR; - sp listener; - - { // Scope for the lock - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - // it is not really an error to disconnect after the surface - // has been abandoned, it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - freeAllBuffersLocked(); - mConnectedApi = NO_CONNECTED_API; - mDequeueCondition.broadcast(); - listener = mConsumerListener; - } else { - ALOGE("disconnect: connected to another api (cur=%d, req=%d)", - mConnectedApi, api); - err = -EINVAL; - } - break; - default: - ALOGE("disconnect: unknown API %d", api); - err = -EINVAL; - break; - } - } - - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return err; -} - -void GonkBufferQueue::dumpToString(String8& result, const char* prefix) const { - Mutex::Autolock _l(mMutex); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#llx, scale=%s\n", - i->mBuf, i->mGraphicBuffer.get(), - i->mCrop.left, i->mCrop.top, i->mCrop.right, - i->mCrop.bottom, i->mTransform, i->mTimestamp, - scalingModeName(i->mScalingMode) - ); - i++; - fifoSize++; - } - - - result.appendFormat( - "%s-BufferQueue mMaxAcquiredBufferCount=%d, mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%d)={%s}\n", - prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, mDefaultWidth, - mDefaultHeight, mDefaultBufferFormat, mTransformHint, - fifoSize, fifo.string()); - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - case BufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } - } - } stateName; - - // just trim the free buffers to not spam the dump - int maxBufferCount = 0; - for (int i=NUM_BUFFER_SLOTS-1 ; i>=0 ; i--) { - const BufferSlot& slot(mSlots[i]); - if ((slot.mBufferState != BufferSlot::FREE) || (slot.mGraphicBuffer != NULL)) { - maxBufferCount = i+1; - break; - } - } - - for (int i=0 ; i& buf(slot.mGraphicBuffer); - result.appendFormat( - "%s%s[%02d:%p] state=%-8s", - prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i, buf.get(), - stateName(slot.mBufferState) - ); - - if (buf != NULL) { - result.appendFormat( - ", %p [%4ux%4u:%4u,%3X]", - buf->handle, buf->width, buf->height, buf->stride, - buf->format); - } - result.append("\n"); - } -} - -void GonkBufferQueue::freeAllBuffersLocked() -{ - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].mGraphicBuffer = 0; - if (mSlots[i].mTextureClient) { - mSlots[i].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr task = - MakeAndAddRef(mSlots[i].mTextureClient); - mSlots[i].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - mSlots[i].mNeedsCleanupOnRelease = true; - } - mSlots[i].mBufferState = BufferSlot::FREE; - mSlots[i].mFrameNumber = 0; - mSlots[i].mAcquireCalled = false; - // destroy fence as GonkBufferQueue now takes ownership - mSlots[i].mFence = Fence::NO_FENCE; - } -} - -status_t GonkBufferQueue::acquireBuffer(BufferItem *buffer, nsecs_t expectedPresent) { - ATRACE_CALL(); - Mutex::Autolock _l(mMutex); - - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer, so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mBufferState == BufferSlot::ACQUIRED) { - numAcquiredBuffers++; - } - } - if (numAcquiredBuffers >= mMaxAcquiredBufferCount+1) { - ALOGE("acquireBuffer: max acquired buffer count reached: %d (max=%d)", - numAcquiredBuffers, mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - - // check if queue is empty - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - if (mQueue.empty()) { - return NO_BUFFER_AVAILABLE; - } - - Fifo::iterator front(mQueue.begin()); - - // If expectedPresent is specified, we may not want to return a buffer yet. - // If it's specified and there's more than one buffer queued, we may - // want to drop a buffer. - if (expectedPresent != 0) { - const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second - - // The "expectedPresent" argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired-present time - // is earlier (less) than expectedPresent, meaning it'll be displayed - // on time or possibly late if we show it ASAP, we acquire and return - // it. If we don't want to display it until after the expectedPresent - // time, we return PRESENT_LATER without acquiring it. - // - // To be safe, we don't defer acquisition if expectedPresent is - // more than one second in the future beyond the desired present time - // (i.e. we'd be holding the buffer for a long time). - // - // NOTE: code assumes monotonic time values from the system clock are - // positive. - - // Start by checking to see if we can drop frames. We skip this check - // if the timestamps are being auto-generated by Surface -- if the - // app isn't generating timestamps explicitly, they probably don't - // want frames to be discarded based on them. - while (mQueue.size() > 1 && !mQueue[0].mIsAutoTimestamp) { - // If entry[1] is timely, drop entry[0] (and repeat). We apply - // an additional criteria here: we only drop the earlier buffer if - // our desiredPresent falls within +/- 1 second of the expected - // present. Otherwise, bogus desiredPresent times (e.g. 0 or - // a small relative timestamp), which normally mean "ignore the - // timestamp and acquire immediately", would cause us to drop - // frames. - // - // We may want to add an additional criteria: don't drop the - // earlier buffer if entry[1]'s fence hasn't signaled yet. - // - // (Vector front is [0], back is [size()-1]) - const BufferItem& bi(mQueue[1]); - nsecs_t desiredPresent = bi.mTimestamp; - if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || - desiredPresent > expectedPresent) { - // This buffer is set to display in the near future, or - // desiredPresent is garbage. Either way we don't want to - // drop the previous buffer just to get this on screen sooner. - ALOGV("pts nodrop: des=%lld expect=%lld (%lld) now=%lld", - desiredPresent, expectedPresent, desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - break; - } - ALOGV("pts drop: queue1des=%lld expect=%lld size=%d", - desiredPresent, expectedPresent, mQueue.size()); - if (stillTracking(front)) { - // front buffer is still in mSlots, so mark the slot as free - mSlots[front->mBuf].mBufferState = BufferSlot::FREE; - } - mQueue.erase(front); - front = mQueue.begin(); - } - - // See if the front buffer is due. - nsecs_t desiredPresent = front->mTimestamp; - if (desiredPresent > expectedPresent && - desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - ALOGV("pts defer: des=%lld expect=%lld (%lld) now=%lld", - desiredPresent, expectedPresent, desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; - } - - ALOGV("pts accept: des=%lld expect=%lld (%lld) now=%lld", - desiredPresent, expectedPresent, desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - } - - int buf = front->mBuf; - buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer; - buffer->mFrameNumber = mSlots[buf].mFrameNumber; - buffer->mBuf = buf; - buffer->mFence = mSlots[buf].mFence; - ATRACE_BUFFER_INDEX(buf); - - ALOGV("acquireBuffer: acquiring { slot=%d/%llu, buffer=%p }", - front->mBuf, front->mFrameNumber, - front->mGraphicBuffer->handle); - // if front buffer still being tracked update slot state - if (stillTracking(front)) { - mSlots[buf].mAcquireCalled = true; - mSlots[buf].mNeedsCleanupOnRelease = false; - mSlots[buf].mBufferState = BufferSlot::ACQUIRED; - mSlots[buf].mFence = Fence::NO_FENCE; - } - - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this - // buffer on the consumer side. - //if (buffer->mAcquireCalled) { - // buffer->mGraphicBuffer = NULL; - //} - - mQueue.erase(front); - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueue::releaseBuffer(int buf, uint64_t frameNumber, const sp& fence) { - ATRACE_CALL(); - - if (buf == INVALID_BUFFER_SLOT || fence == NULL) { - return BAD_VALUE; - } - - Mutex::Autolock _l(mMutex); - - // If the frame number has changed because buffer has been reallocated, - // we can ignore this releaseBuffer for the old buffer. - //if (frameNumber != mSlots[buf].mFrameNumber) { - // return STALE_BUFFER_SLOT; - //} - - - // Internal state consistency checks: - // Make sure this buffers hasn't been queued while we were owning it (acquired) - Fifo::iterator front(mQueue.begin()); - Fifo::const_iterator const end(mQueue.end()); - while (front != end) { - if (front->mBuf == buf) { - LOG_ALWAYS_FATAL("[%s] received new buffer(#%lld) on slot #%d that has not yet been " - "acquired", mConsumerName.string(), frameNumber, buf); - break; // never reached - } - front++; - } - - // The buffer can now only be released if its in the acquired state - if (mSlots[buf].mBufferState == BufferSlot::ACQUIRED) { - mSlots[buf].mFence = fence; - mSlots[buf].mBufferState = BufferSlot::FREE; - } else if (mSlots[buf].mNeedsCleanupOnRelease) { - ALOGV("releasing a stale buf %d its state was %d", buf, mSlots[buf].mBufferState); - mSlots[buf].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ALOGE("attempted to release buf %d but its state was %d", buf, mSlots[buf].mBufferState); - return -EINVAL; - } - - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerConnect(const sp& consumerListener, - bool controlledByApp) { - ALOGV("consumerConnect controlledByApp=%s", - controlledByApp ? "true" : "false"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("consumerConnect: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - if (consumerListener == NULL) { - ALOGE("consumerConnect: consumerListener may not be NULL"); - return BAD_VALUE; - } - - mConsumerListener = consumerListener; - mConsumerControlledByApp = controlledByApp; - - return NO_ERROR; -} - -status_t GonkBufferQueue::consumerDisconnect() { - ALOGV("consumerDisconnect"); - Mutex::Autolock lock(mMutex); - - if (mConsumerListener == NULL) { - ALOGE("consumerDisconnect: No consumer is connected!"); - return -EINVAL; - } - - mAbandoned = true; - mConsumerListener = NULL; - mQueue.clear(); - freeAllBuffersLocked(); - mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueue::getReleasedBuffers(uint32_t* slotMask) { - ALOGV("getReleasedBuffers"); - Mutex::Autolock lock(mMutex); - - if (mAbandoned) { - ALOGE("getReleasedBuffers: GonkBufferQueue has been abandoned!"); - return NO_INIT; - } - - uint32_t mask = 0; - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - if (!mSlots[i].mAcquireCalled) { - mask |= 1 << i; - } - } - - // Remove buffers in flight (on the queue) from the mask where acquire has - // been called, as the consumer will not receive the buffer address, so - // it should not free these slots. - Fifo::iterator front(mQueue.begin()); - while (front != mQueue.end()) { - if (front->mAcquireCalled) - mask &= ~(1 << front->mBuf); - front++; - } - - *slotMask = mask; - - ALOGV("getReleasedBuffers: returning mask %#x", mask); - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h) { - ALOGV("setDefaultBufferSize: w=%d, h=%d", w, h); - if (!w || !h) { - ALOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)", - w, h); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - mDefaultWidth = w; - mDefaultHeight = h; - return NO_ERROR; -} - -status_t GonkBufferQueue::setDefaultMaxBufferCount(int bufferCount) { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - return setDefaultMaxBufferCountLocked(bufferCount); -} - -status_t GonkBufferQueue::disableAsyncBuffer() { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - if (mConsumerListener != NULL) { - ALOGE("disableAsyncBuffer: consumer already connected!"); - return INVALID_OPERATION; - } - mUseAsyncBuffer = false; - return NO_ERROR; -} - -status_t GonkBufferQueue::setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - ATRACE_CALL(); - Mutex::Autolock lock(mMutex); - if (maxAcquiredBuffers < 1 || maxAcquiredBuffers > MAX_MAX_ACQUIRED_BUFFERS) { - ALOGE("setMaxAcquiredBufferCount: invalid count specified: %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - if (mConnectedApi != NO_CONNECTED_API) { - return INVALID_OPERATION; - } - mMaxAcquiredBufferCount = maxAcquiredBuffers; - return NO_ERROR; -} - -int GonkBufferQueue::getMinUndequeuedBufferCount(bool async) const { - // if dequeueBuffer is allowed to error out, we don't have to - // add an extra buffer. - if (!mUseAsyncBuffer) - return mMaxAcquiredBufferCount; - - // we're in async mode, or we want to prevent the app to - // deadlock itself, we throw-in an extra buffer to guarantee it. - if (mDequeueBufferCannotBlock || async || !mSynchronousMode) - return mMaxAcquiredBufferCount + 1; - - return mMaxAcquiredBufferCount; -} - -int GonkBufferQueue::getMinMaxBufferCountLocked(bool async) const { - return getMinUndequeuedBufferCount(async) + 1; -} - -int GonkBufferQueue::getMaxBufferCountLocked(bool async) const { - int minMaxBufferCount = getMinMaxBufferCountLocked(async); - - int maxBufferCount = mDefaultMaxBufferCount; - if (maxBufferCount < minMaxBufferCount) { - maxBufferCount = minMaxBufferCount; - } - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } - - // Any buffers that are dequeued by the producer or sitting in the queue - // waiting to be consumed need to have their slots preserved. Such - // buffers will temporarily keep the max buffer count up until the slots - // no longer need to be preserved. - for (int i = maxBufferCount; i < NUM_BUFFER_SLOTS; i++) { - BufferSlot::BufferState state = mSlots[i].mBufferState; - if (state == BufferSlot::QUEUED || state == BufferSlot::DEQUEUED) { - maxBufferCount = i + 1; - } - } - - return maxBufferCount; -} - -bool GonkBufferQueue::stillTracking(const BufferItem *item) const { - const BufferSlot &slot = mSlots[item->mBuf]; - - ALOGV("stillTracking?: item: { slot=%d/%llu, buffer=%p }, " - "slot: { slot=%d/%llu, buffer=%p }", - item->mBuf, item->mFrameNumber, - (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), - item->mBuf, slot.mFrameNumber, - (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); - - // Compare item with its original buffer slot. We can check the slot - // as the buffer would not be moved to a different slot by the producer. - return (slot.mGraphicBuffer != NULL && - item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); -} - -GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp& consumerListener): - mConsumerListener(consumerListener) {} - -GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueKK.h b/widget/gonk/nativewindow/GonkBufferQueueKK.h deleted file mode 100644 index 01905427d..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueKK.h +++ /dev/null @@ -1,583 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_KK_H -#define NATIVEWINDOW_GONKBUFFERQUEUE_KK_H - -#include -#include -#include -#include "IGonkGraphicBufferConsumer.h" - -#include -#include - -#include -#include -#include - -#include "mozilla/layers/LayersSurfaces.h" -#include "mozilla/layers/TextureClient.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class GonkBufferQueue : public BnGraphicBufferProducer, - public BnGonkGraphicBufferConsumer, - private IBinder::DeathRecipient -{ - typedef mozilla::layers::TextureClient TextureClient; - -public: - enum { MIN_UNDEQUEUED_BUFFERS = 2 }; - enum { NUM_BUFFER_SLOTS = 32 }; - enum { NO_CONNECTED_API = 0 }; - enum { INVALID_BUFFER_SLOT = -1 }; - enum { STALE_BUFFER_SLOT = 1, NO_BUFFER_AVAILABLE, PRESENT_LATER }; - - // When in async mode we reserve two slots in order to guarantee that the - // producer and consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - - // for backward source compatibility - typedef ::android::ConsumerListener ConsumerListener; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // GonkBufferQueue object and the consumer object. The reason this can't be a weak - // reference in the GonkBufferQueue class is because we're planning to expose the - // consumer side of a GonkBufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public BnConsumerListener { - public: - ProxyConsumerListener(const wp& consumerListener); - virtual ~ProxyConsumerListener(); - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - private: - // mConsumerListener is a weak reference to the IConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp mConsumerListener; - }; - - - // BufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allocator is used to allocate all the - // needed gralloc buffers. - GonkBufferQueue(bool allowSynchronousMode = true, - const sp& allocator = NULL); - virtual ~GonkBufferQueue(); - - /* - * IBinder::DeathRecipient interface - */ - - virtual void binderDied(const wp& who); - - /* - * IGraphicBufferProducer interface - */ - - // Query native window attributes. The "what" values are enumerated in - // window.h (e.g. NATIVE_WINDOW_FORMAT). - virtual int query(int what, int* value); - - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the GonkBufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); - - // requestBuffer returns the GraphicBuffer for slot N. - // - // In normal operation, this is called the first time slot N is returned - // by dequeueBuffer. It must be called again if dequeueBuffer returns - // flags indicating that previously-returned buffers are no longer valid. - virtual status_t requestBuffer(int slot, sp* buf); - - // dequeueBuffer gets the next buffer slot index for the producer to use. - // If a buffer slot is available then that slot index is written to the - // location pointed to by the buf argument and a status of OK is returned. - // If no slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // - // The fence parameter will be updated to hold the fence associated with - // the buffer. The contents of the buffer must not be overwritten until the - // fence signals. If the fence is Fence::NO_FENCE, the buffer may be - // written immediately. - // - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. If width and height are both zero, the - // default values specified by setDefaultBufferSize() are used instead. - // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. - // - // The usage argument specifies gralloc buffer usage flags. The values - // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These - // will be merged with the usage flags specified by setConsumerUsageBits. - // - // The return value may be a negative error value or a non-negative - // collection of flags. If the flags are set, the return values are - // valid, but additional actions must be performed. - // - // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the - // producer must discard cached GraphicBuffer references for the slot - // returned in buf. - // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer - // must discard cached GraphicBuffer references for all slots. - // - // In both cases, the producer will need to call requestBuffer to get a - // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *buf, sp* fence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); - - // queueBuffer returns a filled buffer to the GonkBufferQueue. - // - // Additional data is provided in the QueueBufferInput struct. Notably, - // a timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are producer-specific and should be documented by the - // producer. - // - // The caller may provide a fence that signals when all rendering - // operations have completed. Alternatively, NO_FENCE may be used, - // indicating that the buffer is ready immediately. - // - // Some values are returned in the output struct: the current settings - // for default width and height, the current transform hint, and the - // number of queued buffers. - virtual status_t queueBuffer(int buf, - const QueueBufferInput& input, QueueBufferOutput* output); - - // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't - // queue it for use by the consumer. - // - // The buffer will not be overwritten until the fence signals. The fence - // will usually be the one obtained from dequeueBuffer. - virtual void cancelBuffer(int buf, const sp& fence); - - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is synchronous. - // This should be called only during initialization. - virtual status_t setSynchronousMode(bool enabled); - - // connect attempts to connect a producer API to the GonkBufferQueue. This - // must be called before any other IGraphicBufferProducer methods are - // called except for getAllocator. A consumer must already be connected. - // - // This method will fail if connect was previously called on the - // GonkBufferQueue and no corresponding disconnect call was made (i.e. if - // it's still connected to a producer). - // - // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(const sp& token, - int api, bool producerControlledByApp, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer API from the GonkBufferQueue. - // Calling this method will cause any subsequent calls to other - // IGraphicBufferProducer methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the GonkBufferQueue is not currently - // connected to the specified producer API. - virtual status_t disconnect(int api); - - /* - * IGraphicBufferConsumer interface - */ - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the GonkBufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - // - // If presentWhen is nonzero, it indicates the time when the buffer will - // be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen); - - // releaseBuffer releases a buffer slot from the consumer back to the - // GonkBufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - const sp& releaseFence); - - // consumerConnect connects a consumer to the GonkBufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // GonkBufferQueue is placed into the "abandoned" state, causing most - // interactions with the GonkBufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumer may not be NULL. - virtual status_t consumerConnect(const sp& consumer, bool controlledByApp); - - // consumerDisconnect disconnects a consumer from the GonkBufferQueue. All - // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" - // state, causing most interactions with the GonkBufferQueue by the producer to - // fail. - virtual status_t consumerDisconnect(); - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots have been released by the GonkBufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - virtual status_t getReleasedBuffers(uint32_t* slotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount); - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - virtual status_t disableAsyncBuffer(); - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the GonkBufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - virtual status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - virtual status_t setTransformHint(uint32_t hint); - - // dump our state in a String - virtual void dumpToString(String8& result, const char* prefix) const; - - already_AddRefed getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - int getSlotFromTextureClientLocked(TextureClient* client) const; - -private: - // freeBufferLocked frees the GraphicBuffer and sync resources for the - // given slot. - //void freeBufferLocked(int index); - - // freeAllBuffersLocked frees the GraphicBuffer and sync resources for - // all slots. - void freeAllBuffersLocked(); - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - // The initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); - - // getMinUndequeuedBufferCount returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. - // The async parameter tells whether we're in asynchronous mode. - int getMinUndequeuedBufferCount(bool async) const; - - // getMinBufferCountLocked returns the minimum number of buffers allowed - // given the current GonkBufferQueue state. - // The async parameter tells whether we're in asynchronous mode. - int getMinMaxBufferCountLocked(bool async) const; - - // getMaxBufferCountLocked returns the maximum number of buffers that can - // be allocated at once. This value depends upon the following member - // variables: - // - // mDequeueBufferCannotBlock - // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // async parameter - // - // Any time one of these member variables is changed while a producer is - // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked(bool async) const; - - // stillTracking returns true iff the buffer item is still being tracked - // in one of the slots. - bool stillTracking(const BufferItem *item) const; - - struct BufferSlot { - - BufferSlot() - : mBufferState(BufferSlot::FREE), - mRequestBufferCalled(false), - mFrameNumber(0), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false) { - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. - RefPtr mTextureClient; - - // BufferState represents the different states in which a buffer slot - // can be. All slots are initially FREE. - enum BufferState { - // FREE indicates that the buffer is available to be dequeued - // by the producer. The buffer may be in use by the consumer for - // a finite time, so the buffer must not be modified until the - // associated fence is signaled. - // - // The slot is "owned" by GonkBufferQueue. It transitions to DEQUEUED - // when dequeueBuffer is called. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // producer, but has not yet been queued or canceled. The - // producer may modify the buffer's contents as soon as the - // associated ready fence is signaled. - // - // The slot is "owned" by the producer. It can transition to - // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been filled by the - // producer and queued for use by the consumer. The buffer - // contents may continue to be modified for a finite time, so - // the contents must not be accessed until the associated fence - // is signaled. - // - // The slot is "owned" by GonkBufferQueue. It can transition to - // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is - // queued in asynchronous mode). - QUEUED = 2, - - // ACQUIRED indicates that the buffer has been acquired by the - // consumer. As with QUEUED, the contents must not be accessed - // by the consumer until the fence is signaled. - // - // The slot is "owned" by the consumer. It transitions to FREE - // when releaseBuffer is called. - ACQUIRED = 3 - }; - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the producer did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching producer bugs. - bool mRequestBufferCalled; - - // mFrameNumber is the number of the queued frame for this slot. This - // is used to dequeue buffers in LRU order (useful because buffers - // may be released before their release fence is signaled). - uint64_t mFrameNumber; - - // mFence is a fence which will signal when work initiated by the - // previous owner of the buffer is finished. When the buffer is FREE, - // the fence indicates when the consumer has finished reading - // from the buffer, or when the producer has finished writing if it - // called cancelBuffer after queueing some writes. When the buffer is - // QUEUED, it indicates when the producer has finished filling the - // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been - // passed to the consumer or producer along with ownership of the - // buffer, and mFence is set to NO_FENCE. - sp mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by the - // consumer. This is set when a buffer in ACQUIRED state is freed. - // It causes releaseBuffer to return STALE_BUFFER_SLOT. - bool mNeedsCleanupOnRelease; - }; - - // mSlots is the array of buffer slots that must be mirrored on the - // producer side. This allows buffer ownership to be transferred between - // the producer and consumer without sending a GraphicBuffer over binder. - // The entire array is initialized to NULL at construction time, and - // buffers are allocated for a slot when requestBuffer is called with - // that slot's index. - BufferSlot mSlots[NUM_BUFFER_SLOTS]; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in dequeueBuffer() if a width and height of zero is specified. - uint32_t mDefaultHeight; - - // mMaxAcquiredBufferCount is the number of buffers that the consumer may - // acquire at one time. It defaults to 1 and can be changed by the - // consumer via the setMaxAcquiredBufferCount method, but this may only be - // done when no producer is connected to the GonkBufferQueue. - // - // This value is used to derive the value returned for the - // MIN_UNDEQUEUED_BUFFERS query by the producer. - int mMaxAcquiredBufferCount; - - // mDefaultMaxBufferCount is the default limit on the number of buffers - // that will be allocated at one time. This default limit is set by the - // consumer. The limit (as opposed to the default limit) may be - // overridden by the producer. - int mDefaultMaxBufferCount; - - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the image producer by - // calling setBufferCount. The default is zero, which means the producer - // doesn't care about the number of buffers in the pool. In that case - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - - // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to - // allocate new GraphicBuffer objects. - sp mGraphicBufferAlloc; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially set - // to NULL and is written by consumerConnect and consumerDisconnect. - sp mConsumerListener; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - // mConsumerControlledByApp whether the connected consumer is controlled by the - // application. - bool mConsumerControlledByApp; - - // mDequeueBufferCannotBlock whether dequeueBuffer() isn't allowed to block. - // this flag is set during connect() when both consumer and producer are controlled - // by the application. - bool mDequeueBufferCannotBlock; - - // mUseAsyncBuffer whether an extra buffer is used in async mode to prevent - // dequeueBuffer() from ever blocking. - bool mUseAsyncBuffer; - - // mConnectedApi indicates the producer API that is currently connected - // to this GonkBufferQueue. It defaults to NO_CONNECTED_API (= 0), and gets - // updated by the connect and disconnect methods. - int mConnectedApi; - - // mDequeueCondition condition used for dequeueBuffer in synchronous mode - mutable Condition mDequeueCondition; - - // mQueue is a FIFO of queued buffers used in synchronous mode - typedef Vector Fifo; - Fifo mQueue; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume image buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A GonkBufferQueue that has been abandoned will - // return the NO_INIT error from all IGraphicBufferProducer methods - // capable of returning an error. - bool mAbandoned; - - // mConsumerName is a string used to identify the GonkBufferQueue in log - // messages. It is set by the setConsumerName method. - String8 mConsumerName; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkBufferQueue objects. It must be locked whenever the - // member variables are accessed. - mutable Mutex mMutex; - - // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call, and buffer allocation. - uint64_t mFrameCounter; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is - // reset when something causes all buffers to be freed (e.g. changing the - // buffer count). - bool mBufferHasBeenQueued; - - // mDefaultBufferFormat can be set so it will override - // the buffer format when it isn't specified in dequeueBuffer - uint32_t mDefaultBufferFormat; - - // mConsumerUsageBits contains flags the consumer wants for GraphicBuffers - uint32_t mConsumerUsageBits; - - // mTransformHint is used to optimize for screen rotations - uint32_t mTransformHint; - - // mConnectedProducerToken is used to set a binder death notification on the producer - sp mConnectedProducerToken; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_BUFFERQUEUE_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp deleted file mode 100644 index 7df72bf68..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include "GonkBufferItem.h" - -#include -#include - -#include - -namespace android { - -GonkBufferItem::GonkBufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mSlot(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -GonkBufferItem::operator IGonkGraphicBufferConsumer::BufferItem() const { - IGonkGraphicBufferConsumer::BufferItem bufferItem; - bufferItem.mGraphicBuffer = mGraphicBuffer; - bufferItem.mFence = mFence; - bufferItem.mCrop = mCrop; - bufferItem.mTransform = mTransform; - bufferItem.mScalingMode = mScalingMode; - bufferItem.mTimestamp = mTimestamp; - bufferItem.mIsAutoTimestamp = mIsAutoTimestamp; - bufferItem.mFrameNumber = mFrameNumber; - bufferItem.mBuf = mSlot; - bufferItem.mIsDroppable = mIsDroppable; - bufferItem.mAcquireCalled = mAcquireCalled; - bufferItem.mTransformToDisplayInverse = mTransformToDisplayInverse; - return bufferItem; -} - -size_t GonkBufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mSlot) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t GonkBufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t GonkBufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -status_t GonkBufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (count < GonkBufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mSlot); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t GonkBufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mSlot); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -const char* GonkBufferItem::scalingModeName(uint32_t scalingMode) { - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: return "FREEZE"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: return "SCALE_TO_WINDOW"; - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: return "SCALE_CROP"; - default: return "Unknown"; - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h deleted file mode 100644 index b2d6d3068..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferItem.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERITEM_LL_H -#define NATIVEWINDOW_GONKBUFFERITEM_LL_H - -#include "IGonkGraphicBufferConsumerLL.h" - -#include - -#include -#include - -namespace android { - -class Fence; -class GraphicBuffer; - -class GonkBufferItem : public Flattenable { - friend class Flattenable; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - // The default value of mBuf, used to indicate this doesn't correspond to a slot. - enum { INVALID_BUFFER_SLOT = -1 }; - GonkBufferItem(); - operator IGonkGraphicBufferConsumer::BufferItem() const; - - static const char* scalingModeName(uint32_t scalingMode); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // refer to NATIVE_WINDOW_TRANSFORM_* in - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // refer to NATIVE_WINDOW_SCALING_* in - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. This value - // is guaranteed to be monotonically increasing for each newly - // acquired buffer. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mSlot is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mSlot; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; -}; - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp deleted file mode 100644 index 1d7eb2702..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.cpp +++ /dev/null @@ -1,559 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include - -#define LOG_TAG "GonkBufferQueueConsumer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "GonkBufferItem.h" -#include "GonkBufferQueueConsumer.h" -#include "GonkBufferQueueCore.h" -#include -#include - -namespace android { - -GonkBufferQueueConsumer::GonkBufferQueueConsumer(const sp& core) : - mCore(core), - mSlots(core->mSlots), - mConsumerName() {} - -GonkBufferQueueConsumer::~GonkBufferQueueConsumer() {} - -status_t GonkBufferQueueConsumer::acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - - // Check that the consumer doesn't currently have the maximum number of - // buffers acquired. We allow the max buffer count to be exceeded by one - // buffer so that the consumer can successfully set up the newly acquired - // buffer before releasing the old one. - int numAcquiredBuffers = 0; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::ACQUIRED) { - ++numAcquiredBuffers; - } - } - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - ALOGE("acquireBuffer: max acquired buffer count reached: %d (max %d)", - numAcquiredBuffers, mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - - // Check if the queue is empty. - // In asynchronous mode the list is guaranteed to be one buffer deep, - // while in synchronous mode we use the oldest buffer. - if (mCore->mQueue.empty()) { - return NO_BUFFER_AVAILABLE; - } - - GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - - // If expectedPresent is specified, we may not want to return a buffer yet. - // If it's specified and there's more than one buffer queued, we may want - // to drop a buffer. - if (expectedPresent != 0) { - const int MAX_REASONABLE_NSEC = 1000000000ULL; // 1 second - - // The 'expectedPresent' argument indicates when the buffer is expected - // to be presented on-screen. If the buffer's desired present time is - // earlier (less) than expectedPresent -- meaning it will be displayed - // on time or possibly late if we show it as soon as possible -- we - // acquire and return it. If we don't want to display it until after the - // expectedPresent time, we return PRESENT_LATER without acquiring it. - // - // To be safe, we don't defer acquisition if expectedPresent is more - // than one second in the future beyond the desired present time - // (i.e., we'd be holding the buffer for a long time). - // - // NOTE: Code assumes monotonic time values from the system clock - // are positive. - - // Start by checking to see if we can drop frames. We skip this check if - // the timestamps are being auto-generated by Surface. If the app isn't - // generating timestamps explicitly, it probably doesn't want frames to - // be discarded based on them. - while (mCore->mQueue.size() > 1 && !mCore->mQueue[0].mIsAutoTimestamp) { - // If entry[1] is timely, drop entry[0] (and repeat). We apply an - // additional criterion here: we only drop the earlier buffer if our - // desiredPresent falls within +/- 1 second of the expected present. - // Otherwise, bogus desiredPresent times (e.g., 0 or a small - // relative timestamp), which normally mean "ignore the timestamp - // and acquire immediately", would cause us to drop frames. - // - // We may want to add an additional criterion: don't drop the - // earlier buffer if entry[1]'s fence hasn't signaled yet. - const BufferItem& bufferItem(mCore->mQueue[1]); - nsecs_t desiredPresent = bufferItem.mTimestamp; - if (desiredPresent < expectedPresent - MAX_REASONABLE_NSEC || - desiredPresent > expectedPresent) { - // This buffer is set to display in the near future, or - // desiredPresent is garbage. Either way we don't want to drop - // the previous buffer just to get this on the screen sooner. - ALOGV("acquireBuffer: nodrop desire=%" PRId64 " expect=%" - PRId64 " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - break; - } - - ALOGV("acquireBuffer: drop desire=%" PRId64 " expect=%" PRId64 - " size=%zu", - desiredPresent, expectedPresent, mCore->mQueue.size()); - if (mCore->stillTracking(front)) { - // Front buffer is still in mSlots, so mark the slot as free - mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE; - } - mCore->mQueue.erase(front); - front = mCore->mQueue.begin(); - } - - // See if the front buffer is due - nsecs_t desiredPresent = front->mTimestamp; - if (desiredPresent > expectedPresent && - desiredPresent < expectedPresent + MAX_REASONABLE_NSEC) { - ALOGV("acquireBuffer: defer desire=%" PRId64 " expect=%" PRId64 - " (%" PRId64 ") now=%" PRId64, - desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - return PRESENT_LATER; - } - - ALOGV("acquireBuffer: accept desire=%" PRId64 " expect=%" PRId64 " " - "(%" PRId64 ") now=%" PRId64, desiredPresent, expectedPresent, - desiredPresent - expectedPresent, - systemTime(CLOCK_MONOTONIC)); - } - - int slot = front->mSlot; - //*outBuffer = *front; - outBuffer->mGraphicBuffer = mSlots[slot].mGraphicBuffer; - outBuffer->mFrameNumber = mSlots[slot].mFrameNumber; - outBuffer->mBuf = slot; - outBuffer->mFence = mSlots[slot].mFence; - - ATRACE_BUFFER_INDEX(slot); - - ALOGV("acquireBuffer: acquiring { slot=%d/%" PRIu64 " buffer=%p }", - slot, front->mFrameNumber, front->mGraphicBuffer->handle); - // If the front buffer is still being tracked, update its slot state - if (mCore->stillTracking(front)) { - mSlots[slot].mAcquireCalled = true; - mSlots[slot].mNeedsCleanupOnRelease = false; - mSlots[slot].mBufferState = GonkBufferSlot::ACQUIRED; - mSlots[slot].mFence = Fence::NO_FENCE; - } - - // If the buffer has previously been acquired by the consumer, set - // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer - // on the consumer side - //if (outBuffer->mAcquireCalled) { - // outBuffer->mGraphicBuffer = NULL; - //} - - mCore->mQueue.erase(front); - - // We might have freed a slot while dropping old buffers, or the producer - // may be blocked waiting for the number of buffers in the queue to - // decrease. - mCore->mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::detachBuffer(int slot) { - ATRACE_CALL(); - ATRACE_BUFFER_INDEX(slot); - ALOGV("detachBuffer(C): slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("detachBuffer(C): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("detachBuffer(C): slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::ACQUIRED) { - ALOGE("detachBuffer(C): slot %d is not owned by the consumer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - - mCore->freeBufferLocked(slot); - mCore->mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::attachBuffer(int* outSlot, - const sp& buffer) { - ATRACE_CALL(); - - if (outSlot == NULL) { - ALOGE("attachBuffer(P): outSlot must not be NULL"); - return BAD_VALUE; - } else if (buffer == NULL) { - ALOGE("attachBuffer(P): cannot attach NULL buffer"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - - // Make sure we don't have too many acquired buffers and find a free slot - // to put the buffer into (the oldest if there are multiple). - int numAcquiredBuffers = 0; - int found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::ACQUIRED) { - ++numAcquiredBuffers; - } else if (mSlots[s].mBufferState == GonkBufferSlot::FREE) { - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } - } - } - - if (numAcquiredBuffers >= mCore->mMaxAcquiredBufferCount + 1) { - ALOGE("attachBuffer(P): max acquired buffer count reached: %d " - "(max %d)", numAcquiredBuffers, - mCore->mMaxAcquiredBufferCount); - return INVALID_OPERATION; - } - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - ALOGE("attachBuffer(P): could not find free buffer slot"); - return NO_MEMORY; - } - - *outSlot = found; - ATRACE_BUFFER_INDEX(*outSlot); - ALOGV("attachBuffer(C): returning slot %d", *outSlot); - - mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState = GonkBufferSlot::ACQUIRED; - mSlots[*outSlot].mAttachedByConsumer = true; - mSlots[*outSlot].mNeedsCleanupOnRelease = false; - mSlots[*outSlot].mFence = Fence::NO_FENCE; - mSlots[*outSlot].mFrameNumber = 0; - - // mAcquireCalled tells GonkBufferQueue that it doesn't need to send a valid - // GraphicBuffer pointer on the next acquireBuffer call, which decreases - // Binder traffic by not un/flattening the GraphicBuffer. However, it - // requires that the consumer maintain a cached copy of the slot <--> buffer - // mappings, which is why the consumer doesn't need the valid pointer on - // acquire. - // - // The StreamSplitter is one of the primary users of the attach/detach - // logic, and while it is running, all buffers it acquires are immediately - // detached, and all buffers it eventually releases are ones that were - // attached (as opposed to having been obtained from acquireBuffer), so it - // doesn't make sense to maintain the slot/buffer mappings, which would - // become invalid for every buffer during detach/attach. By setting this to - // false, the valid GraphicBuffer pointer will always be sent with acquire - // for attached buffers. - mSlots[*outSlot].mAcquireCalled = false; - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::releaseBuffer(int slot, uint64_t frameNumber, - const sp& releaseFence) { - ATRACE_CALL(); - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS || - releaseFence == NULL) { - return BAD_VALUE; - } - - sp listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - - // If the frame number has changed because the buffer has been reallocated, - // we can ignore this releaseBuffer for the old buffer - //if (frameNumber != mSlots[slot].mFrameNumber) { - // return STALE_BUFFER_SLOT; - //} - - // Make sure this buffer hasn't been queued while acquired by the consumer - GonkBufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); - while (current != mCore->mQueue.end()) { - if (current->mSlot == slot) { - ALOGE("releaseBuffer: buffer slot %d pending release is " - "currently queued", slot); - return BAD_VALUE; - } - ++current; - } - - if (mSlots[slot].mBufferState == GonkBufferSlot::ACQUIRED) { - mSlots[slot].mFence = releaseFence; - mSlots[slot].mBufferState = GonkBufferSlot::FREE; - listener = mCore->mConnectedProducerListener; - ALOGV("releaseBuffer: releasing slot %d", slot); - } else if (mSlots[slot].mNeedsCleanupOnRelease) { - ALOGV("releaseBuffer: releasing a stale buffer slot %d " - "(state = %d)", slot, mSlots[slot].mBufferState); - mSlots[slot].mNeedsCleanupOnRelease = false; - return STALE_BUFFER_SLOT; - } else { - ALOGV("releaseBuffer: attempted to release buffer slot %d " - "but its state was %d", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - - mCore->mDequeueCondition.broadcast(); - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { - listener->onBufferReleased(); - } - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::connect( - const sp& consumerListener, bool controlledByApp) { - ATRACE_CALL(); - - if (consumerListener == NULL) { - ALOGE("connect(C): consumerListener may not be NULL"); - return BAD_VALUE; - } - - ALOGV("connect(C): controlledByApp=%s", - controlledByApp ? "true" : "false"); - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("connect(C): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - mCore->mConsumerListener = consumerListener; - mCore->mConsumerControlledByApp = controlledByApp; - - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::disconnect() { - ATRACE_CALL(); - - ALOGV("disconnect(C)"); - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mConsumerListener == NULL) { - ALOGE("disconnect(C): no consumer is connected"); - return BAD_VALUE; - } - - mCore->mIsAbandoned = true; - mCore->mConsumerListener = NULL; - mCore->mQueue.clear(); - mCore->freeAllBuffersLocked(); - mCore->mDequeueCondition.broadcast(); - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) { - ATRACE_CALL(); - - if (outSlotMask == NULL) { - ALOGE("getReleasedBuffers: outSlotMask may not be NULL"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("getReleasedBuffers: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - uint64_t mask = 0; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (!mSlots[s].mAcquireCalled) { - mask |= (1ULL << s); - } - } - - // Remove from the mask queued buffers for which acquire has been called, - // since the consumer will not receive their buffer addresses and so must - // retain their cached information - GonkBufferQueueCore::Fifo::iterator current(mCore->mQueue.begin()); - while (current != mCore->mQueue.end()) { - if (current->mAcquireCalled) { - mask &= ~(1ULL << current->mSlot); - } - ++current; - } - - ALOGV("getReleasedBuffers: returning mask %#" PRIx64, mask); - *outSlotMask = mask; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setDefaultBufferSize(uint32_t width, - uint32_t height) { - ATRACE_CALL(); - - if (width == 0 || height == 0) { - ALOGV("setDefaultBufferSize: dimensions cannot be 0 (width=%u " - "height=%u)", width, height); - return BAD_VALUE; - } - - ALOGV("setDefaultBufferSize: width=%u height=%u", width, height); - - Mutex::Autolock lock(mCore->mMutex); - mCore->mDefaultWidth = width; - mCore->mDefaultHeight = height; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setDefaultMaxBufferCount(int bufferCount) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - return mCore->setDefaultMaxBufferCountLocked(bufferCount); -} - -status_t GonkBufferQueueConsumer::disableAsyncBuffer() { - ATRACE_CALL(); - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mConsumerListener != NULL) { - ALOGE("disableAsyncBuffer: consumer already connected"); - return INVALID_OPERATION; - } - - ALOGV("disableAsyncBuffer"); - mCore->mUseAsyncBuffer = false; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setMaxAcquiredBufferCount( - int maxAcquiredBuffers) { - ATRACE_CALL(); - - if (maxAcquiredBuffers < 1 || - maxAcquiredBuffers > GonkBufferQueueCore::MAX_MAX_ACQUIRED_BUFFERS) { - ALOGE("setMaxAcquiredBufferCount: invalid count %d", - maxAcquiredBuffers); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mConnectedApi != GonkBufferQueueCore::NO_CONNECTED_API) { - ALOGE("setMaxAcquiredBufferCount: producer is already connected"); - return INVALID_OPERATION; - } - - ALOGV("setMaxAcquiredBufferCount: %d", maxAcquiredBuffers); - mCore->mMaxAcquiredBufferCount = maxAcquiredBuffers; - return NO_ERROR; -} - -void GonkBufferQueueConsumer::setConsumerName(const String8& name) { - ATRACE_CALL(); - ALOGV("setConsumerName: '%s'", name.string()); - Mutex::Autolock lock(mCore->mMutex); - mCore->mConsumerName = name; - mConsumerName = name; -} - -status_t GonkBufferQueueConsumer::setDefaultBufferFormat(uint32_t defaultFormat) { - ATRACE_CALL(); - ALOGV("setDefaultBufferFormat: %u", defaultFormat); - Mutex::Autolock lock(mCore->mMutex); - mCore->mDefaultBufferFormat = defaultFormat; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setConsumerUsageBits(uint32_t usage) { - ATRACE_CALL(); - ALOGV("setConsumerUsageBits: %#x", usage); - Mutex::Autolock lock(mCore->mMutex); - mCore->mConsumerUsageBits = usage; - return NO_ERROR; -} - -status_t GonkBufferQueueConsumer::setTransformHint(uint32_t hint) { - ATRACE_CALL(); - ALOGV("setTransformHint: %#x", hint); - Mutex::Autolock lock(mCore->mMutex); - mCore->mTransformHint = hint; - return NO_ERROR; -} - -sp GonkBufferQueueConsumer::getSidebandStream() const { - return mCore->mSidebandStream; -} - -void GonkBufferQueueConsumer::dumpToString(String8& result, const char* prefix) const { - mCore->dump(result, prefix); -} - -already_AddRefed -GonkBufferQueueConsumer::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) -{ - Mutex::Autolock _l(mCore->mMutex); - if (buffer == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return nullptr; - } - - for (int i = 0; i < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mGraphicBuffer != NULL && mSlots[i].mGraphicBuffer->handle == buffer->handle) { - RefPtr client(mSlots[i].mTextureClient); - return client.forget(); - } - } - ALOGE("getSlotFromBufferLocked: unknown buffer: %p", buffer->handle); - return nullptr; -} - -int -GonkBufferQueueConsumer::getSlotFromTextureClientLocked(GonkBufferSlot::TextureClient* client) const -{ - if (client == NULL) { - ALOGE("getSlotFromBufferLocked: encountered NULL buffer"); - return BAD_VALUE; - } - - for (int i = 0; i < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; i++) { - if (mSlots[i].mTextureClient == client) { - return i; - } - } - ALOGE("getSlotFromBufferLocked: unknown TextureClient: %p", client); - return BAD_VALUE; -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h deleted file mode 100644 index a97cfab42..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueConsumer.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUECONSUMER_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUECONSUMER_LL_H - -#include "GonkBufferQueueDefs.h" -#include "IGonkGraphicBufferConsumerLL.h" - -namespace android { - -class GonkBufferQueueCore; - -class GonkBufferQueueConsumer : public BnGonkGraphicBufferConsumer { - -public: - GonkBufferQueueConsumer(const sp& core); - virtual ~GonkBufferQueueConsumer(); - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the GonkBufferQueue. If no buffer is pending then it returns - // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the - // information about the buffer is returned in BufferItem. If the buffer - // returned had previously been acquired then the BufferItem::mGraphicBuffer - // field of buffer is set to NULL and it is assumed that the consumer still - // holds a reference to the buffer. - // - // If expectedPresent is nonzero, it indicates the time when the buffer - // will be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - virtual status_t acquireBuffer(BufferItem* outBuffer, - nsecs_t expectedPresent); - - // See IGonkGraphicBufferConsumer::detachBuffer - virtual status_t detachBuffer(int slot); - - // See IGonkGraphicBufferConsumer::attachBuffer - virtual status_t attachBuffer(int* slot, const sp& buffer); - - // releaseBuffer releases a buffer slot from the consumer back to the - // GonkBufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - virtual status_t releaseBuffer(int slot, uint64_t frameNumber, - const sp& releaseFence); - - // connect connects a consumer to the GonkBufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // GonkBufferQueue is placed into the "abandoned" state, causing most - // interactions with the GonkBufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumerListener may not be NULL. - virtual status_t connect(const sp& consumerListener, - bool controlledByApp); - - // disconnect disconnects a consumer from the GonkBufferQueue. All - // buffers will be freed and the GonkBufferQueue is placed in the "abandoned" - // state, causing most interactions with the GonkBufferQueue by the producer to - // fail. - virtual status_t disconnect(); - - // getReleasedBuffers sets the value pointed to by outSlotMask to a bit mask - // indicating which buffer slots have been released by the GonkBufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - virtual status_t getReleasedBuffers(uint64_t* outSlotMask); - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - virtual status_t setDefaultBufferSize(uint32_t width, uint32_t height); - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount); - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before connect(). - virtual status_t disableAsyncBuffer(); - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the GonkBufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers); - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - virtual status_t setConsumerUsageBits(uint32_t usage); - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - virtual status_t setTransformHint(uint32_t hint); - - // Retrieve the sideband buffer stream, if any. - virtual sp getSidebandStream() const; - - // dump our state in a String - virtual void dumpToString(String8& result, const char* prefix) const; - - // Added by mozilla - virtual already_AddRefed getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - virtual int getSlotFromTextureClientLocked(GonkBufferSlot::TextureClient* client) const; - - // Functions required for backwards compatibility. - // These will be modified/renamed in IGonkGraphicBufferConsumer and will be - // removed from this class at that time. See b/13306289. - virtual status_t consumerConnect(const sp& consumer, - bool controlledByApp) { - return connect(consumer, controlledByApp); - } - - virtual status_t consumerDisconnect() { return disconnect(); } - - // End functions required for backwards compatibility - -private: - sp mCore; - - // This references mCore->mSlots. Lock mCore->mMutex while accessing. - GonkBufferQueueDefs::SlotsType& mSlots; - - // This is a cached copy of the name stored in the GonkBufferQueueCore. - // It's updated during setConsumerName. - String8 mConsumerName; - -}; // class GonkBufferQueueConsumer - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp deleted file mode 100644 index 9e8e337f6..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueueCore" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include - -#include "GonkBufferItem.h" -#include "GonkBufferQueueCore.h" -#include -#include -#include -#include -#include - -#include -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" - -template -static inline T max(T a, T b) { return a > b ? a : b; } - -namespace android { - -static String8 getUniqueName() { - static volatile int32_t counter = 0; - return String8::format("unnamed-%d-%d", getpid(), - android_atomic_inc(&counter)); -} - -GonkBufferQueueCore::GonkBufferQueueCore(const sp& allocator) : - mAllocator(allocator), - mMutex(), - mIsAbandoned(false), - mConsumerControlledByApp(false), - mConsumerName(getUniqueName()), - mConsumerListener(), - mConsumerUsageBits(0), - mConnectedApi(NO_CONNECTED_API), - mConnectedProducerListener(), - mSlots(), - mQueue(), - mOverrideMaxBufferCount(0), - mDequeueCondition(), - mUseAsyncBuffer(true), - mDequeueBufferCannotBlock(false), - mDefaultBufferFormat(PIXEL_FORMAT_RGBA_8888), - mDefaultWidth(1), - mDefaultHeight(1), - mDefaultMaxBufferCount(2), - mMaxAcquiredBufferCount(1), - mBufferHasBeenQueued(false), - mFrameCounter(0), - mTransformHint(0), - mIsAllocating(false), - mIsAllocatingCondition() -{ - ALOGV("GonkBufferQueueCore"); -} - -GonkBufferQueueCore::~GonkBufferQueueCore() {} - -void GonkBufferQueueCore::dump(String8& result, const char* prefix) const { - Mutex::Autolock lock(mMutex); - - String8 fifo; - Fifo::const_iterator current(mQueue.begin()); - while (current != mQueue.end()) { - fifo.appendFormat("%02d:%p crop=[%d,%d,%d,%d], " - "xform=0x%02x, time=%#" PRIx64 ", scale=%s\n", - current->mSlot, current->mGraphicBuffer.get(), - current->mCrop.left, current->mCrop.top, current->mCrop.right, - current->mCrop.bottom, current->mTransform, current->mTimestamp, - GonkBufferItem::scalingModeName(current->mScalingMode)); - ++current; - } - - result.appendFormat("%s-GonkBufferQueue mMaxAcquiredBufferCount=%d, " - "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], " - "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n", - prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock, - mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint, - mQueue.size(), fifo.string()); - - // Trim the free buffers so as to not spam the dump - int maxBufferCount = 0; - for (int s = GonkBufferQueueDefs::NUM_BUFFER_SLOTS - 1; s >= 0; --s) { - const GonkBufferSlot& slot(mSlots[s]); - if (slot.mBufferState != GonkBufferSlot::FREE || - slot.mGraphicBuffer != NULL) { - maxBufferCount = s + 1; - break; - } - } - - for (int s = 0; s < maxBufferCount; ++s) { - const GonkBufferSlot& slot(mSlots[s]); - const sp& buffer(slot.mGraphicBuffer); - result.appendFormat("%s%s[%02d:%p] state=%-8s", prefix, - (slot.mBufferState == GonkBufferSlot::ACQUIRED) ? ">" : " ", - s, buffer.get(), - GonkBufferSlot::bufferStateName(slot.mBufferState)); - - if (buffer != NULL) { - result.appendFormat(", %p [%4ux%4u:%4u,%3X]", buffer->handle, - buffer->width, buffer->height, buffer->stride, - buffer->format); - } - - result.append("\n"); - } -} - -int GonkBufferQueueCore::getMinUndequeuedBufferCountLocked(bool async) const { - // If dequeueBuffer is allowed to error out, we don't have to add an - // extra buffer. - if (!mUseAsyncBuffer) { - return mMaxAcquiredBufferCount; - } - - if (mDequeueBufferCannotBlock || async) { - return mMaxAcquiredBufferCount + 1; - } - - return mMaxAcquiredBufferCount; -} - -int GonkBufferQueueCore::getMinMaxBufferCountLocked(bool async) const { - return getMinUndequeuedBufferCountLocked(async) + 1; -} - -int GonkBufferQueueCore::getMaxBufferCountLocked(bool async) const { - int minMaxBufferCount = getMinMaxBufferCountLocked(async); - - int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount); - if (mOverrideMaxBufferCount != 0) { - assert(mOverrideMaxBufferCount >= minMaxBufferCount); - maxBufferCount = mOverrideMaxBufferCount; - } - - // Any buffers that are dequeued by the producer or sitting in the queue - // waiting to be consumed need to have their slots preserved. Such buffers - // will temporarily keep the max buffer count up until the slots no longer - // need to be preserved. - for (int s = maxBufferCount; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - GonkBufferSlot::BufferState state = mSlots[s].mBufferState; - if (state == GonkBufferSlot::QUEUED || state == GonkBufferSlot::DEQUEUED) { - maxBufferCount = s + 1; - } - } - - return maxBufferCount; -} - -status_t GonkBufferQueueCore::setDefaultMaxBufferCountLocked(int count) { - const int minBufferCount = 2; - if (count < minBufferCount || count > GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGV("setDefaultMaxBufferCount: invalid count %d, should be in " - "[%d, %d]", - count, minBufferCount, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - ALOGV("setDefaultMaxBufferCount: setting count to %d", count); - mDefaultMaxBufferCount = count; - mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -void GonkBufferQueueCore::freeBufferLocked(int slot) { - ALOGV("freeBufferLocked: slot %d", slot); - - if (mSlots[slot].mTextureClient) { - mSlots[slot].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr task = - MakeAndAddRef(mSlots[slot].mTextureClient); - mSlots[slot].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - mSlots[slot].mGraphicBuffer.clear(); - if (mSlots[slot].mBufferState == GonkBufferSlot::ACQUIRED) { - mSlots[slot].mNeedsCleanupOnRelease = true; - } - mSlots[slot].mBufferState = GonkBufferSlot::FREE; - mSlots[slot].mFrameNumber = UINT32_MAX; - mSlots[slot].mAcquireCalled = false; - - // Destroy fence as GonkBufferQueue now takes ownership - mSlots[slot].mFence = Fence::NO_FENCE; -} - -void GonkBufferQueueCore::freeAllBuffersLocked() { - ALOGW_IF(!mQueue.isEmpty(), - "freeAllBuffersLocked called but mQueue is not empty"); - mQueue.clear(); - mBufferHasBeenQueued = false; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - freeBufferLocked(s); - } -} - -bool GonkBufferQueueCore::stillTracking(const GonkBufferItem* item) const { - const GonkBufferSlot& slot = mSlots[item->mSlot]; - - ALOGV("stillTracking: item { slot=%d/%" PRIu64 " buffer=%p } " - "slot { slot=%d/%" PRIu64 " buffer=%p }", - item->mSlot, item->mFrameNumber, - (item->mGraphicBuffer.get() ? item->mGraphicBuffer->handle : 0), - item->mSlot, slot.mFrameNumber, - (slot.mGraphicBuffer.get() ? slot.mGraphicBuffer->handle : 0)); - - // Compare item with its original buffer slot. We can check the slot as - // the buffer would not be moved to a different slot by the producer. - return (slot.mGraphicBuffer != NULL) && - (item->mGraphicBuffer->handle == slot.mGraphicBuffer->handle); -} - -void GonkBufferQueueCore::waitWhileAllocatingLocked() const { - ATRACE_CALL(); - while (mIsAllocating) { - mIsAllocatingCondition.wait(mMutex); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h deleted file mode 100644 index 936e11686..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueCore.h +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUECORE_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUECORE_LL_H - -#include "GonkBufferQueueDefs.h" -#include "GonkBufferSlot.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "mozilla/layers/TextureClient.h" - -#define ATRACE_BUFFER_INDEX(index) - -using namespace mozilla; -using namespace mozilla::gfx; -using namespace mozilla::layers; - -namespace android { - -class GonkBufferItem; -class IConsumerListener; -class IGraphicBufferAlloc; -class IProducerListener; - -class GonkBufferQueueCore : public virtual RefBase { - - friend class GonkBufferQueueProducer; - friend class GonkBufferQueueConsumer; - -public: - // Used as a placeholder slot number when the value isn't pointing to an - // existing buffer. - enum { INVALID_BUFFER_SLOT = -1 }; // TODO: Extract from IGBC::BufferItem - - // We reserve two slots in order to guarantee that the producer and - // consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = GonkBufferQueueDefs::NUM_BUFFER_SLOTS - 2 }; - - // The default API number used to indicate that no producer is connected - enum { NO_CONNECTED_API = 0 }; - - typedef Vector Fifo; - typedef mozilla::layers::TextureClient TextureClient; - - // GonkBufferQueueCore manages a pool of gralloc memory slots to be used by - // producers and consumers. allocator is used to allocate all the needed - // gralloc buffers. - GonkBufferQueueCore(const sp& allocator = NULL); - virtual ~GonkBufferQueueCore(); - -private: - // Dump our state in a string - void dump(String8& result, const char* prefix) const; - - int getSlotFromTextureClientLocked(TextureClient* client) const; - - // getMinUndequeuedBufferCountLocked returns the minimum number of buffers - // that must remain in a state other than DEQUEUED. The async parameter - // tells whether we're in asynchronous mode. - int getMinUndequeuedBufferCountLocked(bool async) const; - - // getMinMaxBufferCountLocked returns the minimum number of buffers allowed - // given the current GonkBufferQueue state. The async parameter tells whether - // we're in asynchonous mode. - int getMinMaxBufferCountLocked(bool async) const; - - // getMaxBufferCountLocked returns the maximum number of buffers that can be - // allocated at once. This value depends on the following member variables: - // - // mDequeueBufferCannotBlock - // mMaxAcquiredBufferCount - // mDefaultMaxBufferCount - // mOverrideMaxBufferCount - // async parameter - // - // Any time one of these member variables is changed while a producer is - // connected, mDequeueCondition must be broadcast. - int getMaxBufferCountLocked(bool async) const; - - // setDefaultMaxBufferCountLocked sets the maximum number of buffer slots - // that will be used if the producer does not override the buffer slot - // count. The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. The - // initial default is 2. - status_t setDefaultMaxBufferCountLocked(int count); - - // freeBufferLocked frees the GraphicBuffer and sync resources for the - // given slot. - void freeBufferLocked(int slot); - - // freeAllBuffersLocked frees the GraphicBuffer and sync resources for - // all slots. - void freeAllBuffersLocked(); - - // stillTracking returns true iff the buffer item is still being tracked - // in one of the slots. - bool stillTracking(const GonkBufferItem* item) const; - - // waitWhileAllocatingLocked blocks until mIsAllocating is false. - void waitWhileAllocatingLocked() const; - - // mAllocator is the connection to SurfaceFlinger that is used to allocate - // new GraphicBuffer objects. - sp mAllocator; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkBufferQueueCore objects. It must be locked whenever any - // member variable is accessed. - mutable Mutex mMutex; - - // mIsAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume image buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the - // consumerDisconnect method. A GonkBufferQueue that is abandoned will return - // the NO_INIT error from all IGraphicBufferProducer methods capable of - // returning an error. - bool mIsAbandoned; - - // mConsumerControlledByApp indicates whether the connected consumer is - // controlled by the application. - bool mConsumerControlledByApp; - - // mConsumerName is a string used to identify the GonkBufferQueue in log - // messages. It is set by the IGraphicBufferConsumer::setConsumerName - // method. - String8 mConsumerName; - - // mConsumerListener is used to notify the connected consumer of - // asynchronous events that it may wish to react to. It is initially - // set to NULL and is written by consumerConnect and consumerDisconnect. - sp mConsumerListener; - - // mConsumerUsageBits contains flags that the consumer wants for - // GraphicBuffers. - uint32_t mConsumerUsageBits; - - // mConnectedApi indicates the producer API that is currently connected - // to this GonkBufferQueue. It defaults to NO_CONNECTED_API, and gets updated - // by the connect and disconnect methods. - int mConnectedApi; - - // mConnectedProducerToken is used to set a binder death notification on - // the producer. - sp mConnectedProducerListener; - - // mSlots is an array of buffer slots that must be mirrored on the producer - // side. This allows buffer ownership to be transferred between the producer - // and consumer without sending a GraphicBuffer over Binder. The entire - // array is initialized to NULL at construction time, and buffers are - // allocated for a slot when requestBuffer is called with that slot's index. - GonkBufferQueueDefs::SlotsType mSlots; - - // mQueue is a FIFO of queued buffers used in synchronous mode. - Fifo mQueue; - - // mOverrideMaxBufferCount is the limit on the number of buffers that will - // be allocated at one time. This value is set by the producer by calling - // setBufferCount. The default is 0, which means that the producer doesn't - // care about the number of buffers in the pool. In that case, - // mDefaultMaxBufferCount is used as the limit. - int mOverrideMaxBufferCount; - - // mDequeueCondition is a condition variable used for dequeueBuffer in - // synchronous mode. - mutable Condition mDequeueCondition; - - // mUseAsyncBuffer indicates whether an extra buffer is used in async mode - // to prevent dequeueBuffer from blocking. - bool mUseAsyncBuffer; - - // mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to - // block. This flag is set during connect when both the producer and - // consumer are controlled by the application. - bool mDequeueBufferCannotBlock; - - // mDefaultBufferFormat can be set so it will override the buffer format - // when it isn't specified in dequeueBuffer. - uint32_t mDefaultBufferFormat; - - // mDefaultWidth holds the default width of allocated buffers. It is used - // in dequeueBuffer if a width and height of 0 are specified. - int mDefaultWidth; - - // mDefaultHeight holds the default height of allocated buffers. It is used - // in dequeueBuffer if a width and height of 0 are specified. - int mDefaultHeight; - - // mDefaultMaxBufferCount is the default limit on the number of buffers that - // will be allocated at one time. This default limit is set by the consumer. - // The limit (as opposed to the default limit) may be overriden by the - // producer. - int mDefaultMaxBufferCount; - - // mMaxAcquiredBufferCount is the number of buffers that the consumer may - // acquire at one time. It defaults to 1, and can be changed by the consumer - // via setMaxAcquiredBufferCount, but this may only be done while no - // producer is connected to the GonkBufferQueue. This value is used to derive - // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer. - int mMaxAcquiredBufferCount; - - // mBufferHasBeenQueued is true once a buffer has been queued. It is reset - // when something causes all buffers to be freed (e.g., changing the buffer - // count). - bool mBufferHasBeenQueued; - - // mFrameCounter is the free running counter, incremented on every - // successful queueBuffer call and buffer allocation. - uint64_t mFrameCounter; - - // mTransformHint is used to optimize for screen rotations. - uint32_t mTransformHint; - - // mSidebandStream is a handle to the sideband buffer stream, if any - sp mSidebandStream; - - // mIsAllocating indicates whether a producer is currently trying to allocate buffers (which - // releases mMutex while doing the allocation proper). Producers should not modify any of the - // FREE slots while this is true. mIsAllocatingCondition is signaled when this value changes to - // false. - bool mIsAllocating; - - // mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating - // becomes false. - mutable Condition mIsAllocatingCondition; -}; // class GonkBufferQueueCore - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h deleted file mode 100644 index 60085706f..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueDefs.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_BUFFERQUEUECOREDEFS_H -#define NATIVEWINDOW_BUFFERQUEUECOREDEFS_H - -#include "GonkBufferSlot.h" - -namespace android { - class GonkBufferQueueCore; - - namespace GonkBufferQueueDefs { - // GonkBufferQueue will keep track of at most this value of buffers. - // Attempts at runtime to increase the number of buffers past this - // will fail. - enum { NUM_BUFFER_SLOTS = 64 }; - - typedef GonkBufferSlot SlotsType[NUM_BUFFER_SLOTS]; - } // namespace GonkBufferQueueDefs -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp deleted file mode 100644 index 649d06bee..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkBufferQueue" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#define LOG_NDEBUG 0 - -#include "GonkBufferQueue.h" -#include "GonkBufferQueueConsumer.h" -#include "GonkBufferQueueCore.h" -#include "GonkBufferQueueProducer.h" - -namespace android { - -GonkBufferQueue::ProxyConsumerListener::ProxyConsumerListener( - const wp& consumerListener): - mConsumerListener(consumerListener) {} - -GonkBufferQueue::ProxyConsumerListener::~ProxyConsumerListener() {} - -#if ANDROID_VERSION == 21 -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(); - } -} -#else -void GonkBufferQueue::ProxyConsumerListener::onFrameAvailable(const ::android::BufferItem& item) { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameAvailable(item); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onFrameReplaced(const ::android::BufferItem& item) { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onFrameReplaced(item); - } -} -#endif - -void GonkBufferQueue::ProxyConsumerListener::onBuffersReleased() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onBuffersReleased(); - } -} - -void GonkBufferQueue::ProxyConsumerListener::onSidebandStreamChanged() { - sp listener(mConsumerListener.promote()); - if (listener != NULL) { - listener->onSidebandStreamChanged(); - } -} - -void GonkBufferQueue::createBufferQueue(sp* outProducer, - sp* outConsumer, - const sp& allocator) { - LOG_ALWAYS_FATAL_IF(outProducer == NULL, - "GonkBufferQueue: outProducer must not be NULL"); - LOG_ALWAYS_FATAL_IF(outConsumer == NULL, - "GonkBufferQueue: outConsumer must not be NULL"); - - sp core(new GonkBufferQueueCore(allocator)); - LOG_ALWAYS_FATAL_IF(core == NULL, - "GonkBufferQueue: failed to create GonkBufferQueueCore"); - - sp producer(new GonkBufferQueueProducer(core)); - LOG_ALWAYS_FATAL_IF(producer == NULL, - "GonkBufferQueue: failed to create GonkBufferQueueProducer"); - - sp consumer(new GonkBufferQueueConsumer(core)); - LOG_ALWAYS_FATAL_IF(consumer == NULL, - "GonkBufferQueue: failed to create GonkBufferQueueConsumer"); - - *outProducer = producer; - *outConsumer = consumer; -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h deleted file mode 100644 index b1b4e06b5..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueLL.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUE_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUE_LL_H - -#include "GonkBufferQueueDefs.h" -#include "IGonkGraphicBufferConsumerLL.h" -#include -#include - -// These are only required to keep other parts of the framework with incomplete -// dependencies building successfully -#include - -namespace android { - -class GonkBufferQueue { -public: - // GonkBufferQueue will keep track of at most this value of buffers. - // Attempts at runtime to increase the number of buffers past this will fail. - enum { NUM_BUFFER_SLOTS = GonkBufferQueueDefs::NUM_BUFFER_SLOTS }; - // Used as a placeholder slot# when the value isn't pointing to an existing buffer. - enum { INVALID_BUFFER_SLOT = IGonkGraphicBufferConsumer::BufferItem::INVALID_BUFFER_SLOT }; - // Alias to -- please scope from there in future code! - enum { - NO_BUFFER_AVAILABLE = IGonkGraphicBufferConsumer::NO_BUFFER_AVAILABLE, - PRESENT_LATER = IGonkGraphicBufferConsumer::PRESENT_LATER, - }; - - // When in async mode we reserve two slots in order to guarantee that the - // producer and consumer can run asynchronously. - enum { MAX_MAX_ACQUIRED_BUFFERS = NUM_BUFFER_SLOTS - 2 }; - - // for backward source compatibility - typedef ::android::ConsumerListener ConsumerListener; - typedef IGonkGraphicBufferConsumer::BufferItem BufferItem; - - // ProxyConsumerListener is a ConsumerListener implementation that keeps a weak - // reference to the actual consumer object. It forwards all calls to that - // consumer object so long as it exists. - // - // This class exists to avoid having a circular reference between the - // GonkBufferQueue object and the consumer object. The reason this can't be a weak - // reference in the GonkBufferQueue class is because we're planning to expose the - // consumer side of a GonkBufferQueue as a binder interface, which doesn't support - // weak references. - class ProxyConsumerListener : public BnConsumerListener { - public: - ProxyConsumerListener(const wp& consumerListener); - virtual ~ProxyConsumerListener(); -#if ANDROID_VERSION == 21 - virtual void onFrameAvailable(); -#else - virtual void onFrameAvailable(const ::android::BufferItem& item); - virtual void onFrameReplaced(const ::android::BufferItem& item); -#endif - virtual void onBuffersReleased(); - virtual void onSidebandStreamChanged(); - private: - // mConsumerListener is a weak reference to the IConsumerListener. This is - // the raison d'etre of ProxyConsumerListener. - wp mConsumerListener; - }; - - // GonkBufferQueue manages a pool of gralloc memory slots to be used by - // producers and consumers. allocator is used to allocate all the - // needed gralloc buffers. - static void createBufferQueue(sp* outProducer, - sp* outConsumer, - const sp& allocator = NULL); - -private: - GonkBufferQueue(); // Create through createBufferQueue -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKBUFFERQUEUE_LL_H diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp deleted file mode 100644 index d3436756f..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.cpp +++ /dev/null @@ -1,886 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include - -#define LOG_TAG "GonkBufferQueueProducer" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#include "GonkBufferItem.h" -#include "GonkBufferQueueCore.h" -#include "GonkBufferQueueProducer.h" -#include -#include -#include - -#include -#include -#include - -#include "mozilla/layers/GrallocTextureClient.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/layers/TextureClient.h" - -namespace android { - -GonkBufferQueueProducer::GonkBufferQueueProducer(const sp& core) : - mCore(core), - mSlots(core->mSlots), - mConsumerName(), - mSynchronousMode(true), - mStickyTransform(0) {} - -GonkBufferQueueProducer::~GonkBufferQueueProducer() {} - -status_t GonkBufferQueueProducer::requestBuffer(int slot, sp* buf) { - ATRACE_CALL(); - ALOGV("requestBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("requestBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("requestBuffer: slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("requestBuffer: slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } - - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::setBufferCount(int bufferCount) { - ATRACE_CALL(); - ALOGV("setBufferCount: count = %d", bufferCount); - - sp listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (mCore->mIsAbandoned) { - ALOGE("setBufferCount: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (bufferCount > GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("setBufferCount: bufferCount %d too large (max %d)", - bufferCount, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } - - // There must be no dequeued buffers when changing the buffer count. - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::DEQUEUED) { - ALOGE("setBufferCount: buffer owned by producer"); - return BAD_VALUE; - } - } - - if (bufferCount == 0) { - mCore->mOverrideMaxBufferCount = 0; - mCore->mDequeueCondition.broadcast(); - return NO_ERROR; - } - - const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false); - if (bufferCount < minBufferSlots) { - ALOGE("setBufferCount: requested buffer count %d is less than " - "minimum %d", bufferCount, minBufferSlots); - return BAD_VALUE; - } - - // Here we are guaranteed that the producer doesn't have any dequeued - // buffers and will release all of its buffer references. We don't - // clear the queue, however, so that currently queued buffers still - // get displayed. - mCore->freeAllBuffersLocked(); - mCore->mOverrideMaxBufferCount = bufferCount; - mCore->mDequeueCondition.broadcast(); - listener = mCore->mConsumerListener; - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::waitForFreeSlotThenRelock(const char* caller, - bool async, int* found, status_t* returnFlags) const { - bool tryAgain = true; - while (tryAgain) { - if (mCore->mIsAbandoned) { - ALOGE("%s: GonkBufferQueue has been abandoned", caller); - return NO_INIT; - } - - const int maxBufferCount = mCore->getMaxBufferCountLocked(async); - if (async && mCore->mOverrideMaxBufferCount) { - // FIXME: Some drivers are manually setting the buffer count - // (which they shouldn't), so we do this extra test here to - // handle that case. This is TEMPORARY until we get this fixed. - if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("%s: async mode is invalid with buffer count override", - caller); - return BAD_VALUE; - } - } - - // Free up any buffers that are in slots beyond the max buffer count - //for (int s = maxBufferCount; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - // assert(mSlots[s].mBufferState == GonkBufferSlot::FREE); - // if (mSlots[s].mGraphicBuffer != NULL) { - // mCore->freeBufferLocked(s); - // *returnFlags |= RELEASE_ALL_BUFFERS; - // } - //} - - // Look for a free buffer to give to the client - *found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - int dequeuedCount = 0; - int acquiredCount = 0; - for (int s = 0; s < maxBufferCount; ++s) { - switch (mSlots[s].mBufferState) { - case GonkBufferSlot::DEQUEUED: - ++dequeuedCount; - break; - case GonkBufferSlot::ACQUIRED: - ++acquiredCount; - break; - case GonkBufferSlot::FREE: - // We return the oldest of the free buffers to avoid - // stalling the producer if possible, since the consumer - // may still have pending reads of in-flight buffers - if (*found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[*found].mFrameNumber) { - *found = s; - } - break; - default: - break; - } - } - - // Producers are not allowed to dequeue more than one buffer if they - // did not set a buffer count - if (!mCore->mOverrideMaxBufferCount && dequeuedCount) { - ALOGE("%s: can't dequeue multiple buffers without setting the " - "buffer count", caller); - return INVALID_OPERATION; - } - - // See whether a buffer has been queued since the last - // setBufferCount so we know whether to perform the min undequeued - // buffers check below - if (mCore->mBufferHasBeenQueued) { - // Make sure the producer is not trying to dequeue more buffers - // than allowed - const int newUndequeuedCount = - maxBufferCount - (dequeuedCount + 1); - const int minUndequeuedCount = - mCore->getMinUndequeuedBufferCountLocked(async); - if (newUndequeuedCount < minUndequeuedCount) { - ALOGE("%s: min undequeued buffer count (%d) exceeded " - "(dequeued=%d undequeued=%d)", - caller, minUndequeuedCount, - dequeuedCount, newUndequeuedCount); - return INVALID_OPERATION; - } - } - - // If we disconnect and reconnect quickly, we can be in a state where - // our slots are empty but we have many buffers in the queue. This can - // cause us to run out of memory if we outrun the consumer. Wait here if - // it looks like we have too many buffers queued up. - bool tooManyBuffers = mCore->mQueue.size() - > static_cast(maxBufferCount); - if (tooManyBuffers) { - ALOGV("%s: queue size is %zu, waiting", caller, - mCore->mQueue.size()); - } - - // If no buffer is found, or if the queue has too many buffers - // outstanding, wait for a buffer to be acquired or released, or for the - // max buffer count to change. - tryAgain = (*found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) || - tooManyBuffers; - if (tryAgain) { - // Return an error if we're in non-blocking mode (producer and - // consumer are controlled by the application). - // However, the consumer is allowed to briefly acquire an extra - // buffer (which could cause us to have to wait here), which is - // okay, since it is only used to implement an atomic acquire + - // release (e.g., in GLConsumer::updateTexImage()) - if (mCore->mDequeueBufferCannotBlock && - (acquiredCount <= mCore->mMaxAcquiredBufferCount)) { - return WOULD_BLOCK; - } - mCore->mDequeueCondition.wait(mCore->mMutex); - } - } // while (tryAgain) - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::dequeueBuffer(int *outSlot, - sp *outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage) { - ATRACE_CALL(); - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mConsumerName = mCore->mConsumerName; - } // Autolock scope - - ALOGV("dequeueBuffer: async=%s w=%u h=%u format=%#x, usage=%#x", - async ? "true" : "false", width, height, format, usage); - - if ((width && !height) || (!width && height)) { - ALOGE("dequeueBuffer: invalid size: w=%u h=%u", width, height); - return BAD_VALUE; - } - - status_t returnFlags = NO_ERROR; - // Reset slot - *outSlot = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - - bool attachedByConsumer = false; - - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (format == 0) { - format = mCore->mDefaultBufferFormat; - } - - // Enable the usage bits the consumer requested - usage |= mCore->mConsumerUsageBits; - - int found; - status_t status = waitForFreeSlotThenRelock("dequeueBuffer", async, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; - } - - // This should not happen - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - ALOGE("dequeueBuffer: no available buffer slots"); - return -EBUSY; - } - - *outSlot = found; - - attachedByConsumer = mSlots[found].mAttachedByConsumer; - - const bool useDefaultSize = !width && !height; - if (useDefaultSize) { - width = mCore->mDefaultWidth; - height = mCore->mDefaultHeight; - } - - mSlots[found].mBufferState = GonkBufferSlot::DEQUEUED; - - const sp& buffer(mSlots[found].mGraphicBuffer); - if ((buffer == NULL) || - (static_cast(buffer->width) != width) || - (static_cast(buffer->height) != height) || - (static_cast(buffer->format) != format) || - ((static_cast(buffer->usage) & usage) != usage)) - { - mSlots[found].mAcquireCalled = false; - mSlots[found].mGraphicBuffer = NULL; - mSlots[found].mRequestBufferCalled = false; - mSlots[found].mFence = Fence::NO_FENCE; - - if (mSlots[found].mTextureClient) { - mSlots[found].mTextureClient->ClearRecycleCallback(); - // release TextureClient in ImageBridge thread - RefPtr task = - MakeAndAddRef(mSlots[found].mTextureClient); - mSlots[found].mTextureClient = NULL; - ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask(task.forget()); - } - - returnFlags |= BUFFER_NEEDS_REALLOCATION; - } - - if (CC_UNLIKELY(mSlots[found].mFence == NULL)) { - ALOGE("dequeueBuffer: about to return a NULL fence - " - "slot=%d w=%d h=%d format=%u", - found, buffer->width, buffer->height, buffer->format); - } - - *outFence = mSlots[found].mFence; - mSlots[found].mFence = Fence::NO_FENCE; - } // Autolock scope - - if (returnFlags & BUFFER_NEEDS_REALLOCATION) { - RefPtr allocator = ImageBridgeChild::GetSingleton(); - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - GrallocTextureData* texData = GrallocTextureData::Create(IntSize(width,height), format, - gfx::BackendType::NONE, - usage, allocator); - if (!texData) { - ALOGE("dequeueBuffer: failed to alloc gralloc buffer"); - return -ENOMEM; - } - RefPtr textureClient = TextureClient::CreateWithData( - texData, TextureFlags::RECYCLE | TextureFlags::DEALLOCATE_CLIENT, allocator); - - sp graphicBuffer = texData->GetGraphicBuffer(); - - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("dequeueBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - mSlots[*outSlot].mFrameNumber = UINT32_MAX; - mSlots[*outSlot].mGraphicBuffer = graphicBuffer; - mSlots[*outSlot].mTextureClient = textureClient; - } // Autolock scope - } - - if (attachedByConsumer) { - returnFlags |= BUFFER_NEEDS_REALLOCATION; - } - - ALOGV("dequeueBuffer: returning slot=%d/%" PRIu64 " buf=%p flags=%#x", - *outSlot, - mSlots[*outSlot].mFrameNumber, - mSlots[*outSlot].mGraphicBuffer->handle, returnFlags); - - return returnFlags; -} - -status_t GonkBufferQueueProducer::detachBuffer(int slot) { - ATRACE_CALL(); - ATRACE_BUFFER_INDEX(slot); - ALOGV("detachBuffer(P): slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("detachBuffer(P): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("detachBuffer(P): slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("detachBuffer(P): slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } else if (!mSlots[slot].mRequestBufferCalled) { - ALOGE("detachBuffer(P): buffer in slot %d has not been requested", - slot); - return BAD_VALUE; - } - - mCore->freeBufferLocked(slot); - mCore->mDequeueCondition.broadcast(); - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::detachNextBuffer(sp* outBuffer, - sp* outFence) { - ATRACE_CALL(); - - if (outBuffer == NULL) { - ALOGE("detachNextBuffer: outBuffer must not be NULL"); - return BAD_VALUE; - } else if (outFence == NULL) { - ALOGE("detachNextBuffer: outFence must not be NULL"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (mCore->mIsAbandoned) { - ALOGE("detachNextBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - // Find the oldest valid slot - int found = GonkBufferQueueCore::INVALID_BUFFER_SLOT; - for (int s = 0; s < GonkBufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { - if (mSlots[s].mBufferState == GonkBufferSlot::FREE && - mSlots[s].mGraphicBuffer != NULL) { - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT || - mSlots[s].mFrameNumber < mSlots[found].mFrameNumber) { - found = s; - } - } - } - - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - return NO_MEMORY; - } - - ALOGV("detachNextBuffer detached slot %d", found); - - *outBuffer = mSlots[found].mGraphicBuffer; - *outFence = mSlots[found].mFence; - mCore->freeBufferLocked(found); - - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::attachBuffer(int* outSlot, - const sp& buffer) { - ATRACE_CALL(); - - if (outSlot == NULL) { - ALOGE("attachBuffer(P): outSlot must not be NULL"); - return BAD_VALUE; - } else if (buffer == NULL) { - ALOGE("attachBuffer(P): cannot attach NULL buffer"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - status_t returnFlags = NO_ERROR; - int found; - // TODO: Should we provide an async flag to attachBuffer? It seems - // unlikely that buffers which we are attaching to a GonkBufferQueue will - // be asynchronous (droppable), but it may not be impossible. - status_t status = waitForFreeSlotThenRelock("attachBuffer(P)", false, - &found, &returnFlags); - if (status != NO_ERROR) { - return status; - } - - // This should not happen - if (found == GonkBufferQueueCore::INVALID_BUFFER_SLOT) { - ALOGE("attachBuffer(P): no available buffer slots"); - return -EBUSY; - } - - *outSlot = found; - ATRACE_BUFFER_INDEX(*outSlot); - ALOGV("attachBuffer(P): returning slot %d flags=%#x", - *outSlot, returnFlags); - - mSlots[*outSlot].mGraphicBuffer = buffer; - mSlots[*outSlot].mBufferState = GonkBufferSlot::DEQUEUED; - mSlots[*outSlot].mFence = Fence::NO_FENCE; - mSlots[*outSlot].mRequestBufferCalled = true; - - return returnFlags; -} - -status_t GonkBufferQueueProducer::setSynchronousMode(bool enabled) { - ALOGV("setSynchronousMode: enabled=%d", enabled); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("setSynchronousMode: BufferQueue has been abandoned!"); - return NO_INIT; - } - - if (mSynchronousMode != enabled) { - mSynchronousMode = enabled; - mCore->mDequeueCondition.broadcast(); - } - return OK; -} - -status_t GonkBufferQueueProducer::queueBuffer(int slot, - const QueueBufferInput &input, QueueBufferOutput *output) { - ATRACE_CALL(); - - int64_t timestamp; - bool isAutoTimestamp; - Rect crop; - int scalingMode; - uint32_t transform; - uint32_t stickyTransform; - bool async; - sp fence; - input.deflate(×tamp, &isAutoTimestamp, &crop, &scalingMode, &transform, - &async, &fence, &stickyTransform); - - if (fence == NULL) { - ALOGE("queueBuffer: fence is NULL"); - // Temporary workaround for b/17946343: soldier-on instead of returning an error. This - // prevents the client from dying, at the risk of visible corruption due to hwcomposer - // reading the buffer before the producer is done rendering it. Unless the buffer is the - // last frame of an animation, the corruption will be transient. - fence = Fence::NO_FENCE; - // return BAD_VALUE; - } - - switch (scalingMode) { - case NATIVE_WINDOW_SCALING_MODE_FREEZE: - case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW: - case NATIVE_WINDOW_SCALING_MODE_SCALE_CROP: - case NATIVE_WINDOW_SCALING_MODE_NO_SCALE_CROP: - break; - default: - ALOGE("queueBuffer: unknown scaling mode %d", scalingMode); - return BAD_VALUE; - } - - GonkBufferItem item; - sp listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("queueBuffer: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - const int maxBufferCount = mCore->getMaxBufferCountLocked(async); - if (async && mCore->mOverrideMaxBufferCount) { - // FIXME: Some drivers are manually setting the buffer count - // (which they shouldn't), so we do this extra test here to - // handle that case. This is TEMPORARY until we get this fixed. - if (mCore->mOverrideMaxBufferCount < maxBufferCount) { - ALOGE("queueBuffer: async mode is invalid with " - "buffer count override"); - return BAD_VALUE; - } - } - - if (slot < 0 || slot >= maxBufferCount) { - ALOGE("queueBuffer: slot index %d out of range [0, %d)", - slot, maxBufferCount); - return BAD_VALUE; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("queueBuffer: slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return BAD_VALUE; - } else if (!mSlots[slot].mRequestBufferCalled) { - ALOGE("queueBuffer: slot %d was queued without requesting " - "a buffer", slot); - return BAD_VALUE; - } - - ALOGV("queueBuffer: slot=%d/%" PRIu64 " time=%" PRIu64 - " crop=[%d,%d,%d,%d] transform=%#x scale=%s", - slot, mCore->mFrameCounter + 1, timestamp, - crop.left, crop.top, crop.right, crop.bottom, - transform, GonkBufferItem::scalingModeName(scalingMode)); - - const sp& graphicBuffer(mSlots[slot].mGraphicBuffer); - Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight()); - Rect croppedRect; - crop.intersect(bufferRect, &croppedRect); - if (croppedRect != crop) { - ALOGE("queueBuffer: crop rect is not contained within the " - "buffer in slot %d", slot); - return BAD_VALUE; - } - - mSlots[slot].mFence = fence; - mSlots[slot].mBufferState = GonkBufferSlot::QUEUED; - ++mCore->mFrameCounter; - mSlots[slot].mFrameNumber = mCore->mFrameCounter; - - item.mAcquireCalled = mSlots[slot].mAcquireCalled; - item.mGraphicBuffer = mSlots[slot].mGraphicBuffer; - item.mCrop = crop; - item.mTransform = transform & ~NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY; - item.mTransformToDisplayInverse = - bool(transform & NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY); - item.mScalingMode = scalingMode; - item.mTimestamp = timestamp; - item.mIsAutoTimestamp = isAutoTimestamp; - item.mFrameNumber = mCore->mFrameCounter; - item.mSlot = slot; - item.mFence = fence; - item.mIsDroppable = mCore->mDequeueBufferCannotBlock || async; - - mStickyTransform = stickyTransform; - - if (mCore->mQueue.empty()) { - // When the queue is empty, we can ignore mDequeueBufferCannotBlock - // and simply queue this buffer - mCore->mQueue.push_back(item); - listener = mCore->mConsumerListener; - } else { - // When the queue is not empty, we need to look at the front buffer - // state to see if we need to replace it - GonkBufferQueueCore::Fifo::iterator front(mCore->mQueue.begin()); - if (front->mIsDroppable || !mSynchronousMode) { - // If the front queued buffer is still being tracked, we first - // mark it as freed - if (mCore->stillTracking(front)) { - mSlots[front->mSlot].mBufferState = GonkBufferSlot::FREE; - // Reset the frame number of the freed buffer so that it is - // the first in line to be dequeued again - mSlots[front->mSlot].mFrameNumber = 0; - } - // Overwrite the droppable buffer with the incoming one - *front = item; - listener = mCore->mConsumerListener; - } else { - mCore->mQueue.push_back(item); - listener = mCore->mConsumerListener; - } - } - - mCore->mBufferHasBeenQueued = true; - mCore->mDequeueCondition.broadcast(); - - output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); - - item.mGraphicBuffer.clear(); - item.mSlot = GonkBufferItem::INVALID_BUFFER_SLOT; - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { -#if ANDROID_VERSION == 21 - listener->onFrameAvailable(); -#else - listener->onFrameAvailable(reinterpret_cast<::android::BufferItem&>(item)); -#endif - } - - return NO_ERROR; -} - -void GonkBufferQueueProducer::cancelBuffer(int slot, const sp& fence) { - ATRACE_CALL(); - ALOGV("cancelBuffer: slot %d", slot); - Mutex::Autolock lock(mCore->mMutex); - - if (mCore->mIsAbandoned) { - ALOGE("cancelBuffer: GonkBufferQueue has been abandoned"); - return; - } - - if (slot < 0 || slot >= GonkBufferQueueDefs::NUM_BUFFER_SLOTS) { - ALOGE("cancelBuffer: slot index %d out of range [0, %d)", - slot, GonkBufferQueueDefs::NUM_BUFFER_SLOTS); - return; - } else if (mSlots[slot].mBufferState != GonkBufferSlot::DEQUEUED) { - ALOGE("cancelBuffer: slot %d is not owned by the producer " - "(state = %d)", slot, mSlots[slot].mBufferState); - return; - } else if (fence == NULL) { - ALOGE("cancelBuffer: fence is NULL"); - return; - } - - mSlots[slot].mBufferState = GonkBufferSlot::FREE; - mSlots[slot].mFrameNumber = 0; - mSlots[slot].mFence = fence; - mCore->mDequeueCondition.broadcast(); -} - -int GonkBufferQueueProducer::query(int what, int *outValue) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - - if (outValue == NULL) { - ALOGE("query: outValue was NULL"); - return BAD_VALUE; - } - - if (mCore->mIsAbandoned) { - ALOGE("query: GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mCore->mDefaultWidth; - break; - case NATIVE_WINDOW_HEIGHT: - value = mCore->mDefaultHeight; - break; - case NATIVE_WINDOW_FORMAT: - value = mCore->mDefaultBufferFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mCore->getMinUndequeuedBufferCountLocked(false); - break; - case NATIVE_WINDOW_STICKY_TRANSFORM: - value = static_cast(mStickyTransform); - break; - case NATIVE_WINDOW_CONSUMER_RUNNING_BEHIND: - value = (mCore->mQueue.size() > 1); - break; - case NATIVE_WINDOW_CONSUMER_USAGE_BITS: - value = mCore->mConsumerUsageBits; - break; - default: - return BAD_VALUE; - } - - ALOGV("query: %d? %d", what, value); - *outValue = value; - return NO_ERROR; -} - -status_t GonkBufferQueueProducer::connect(const sp& listener, - int api, bool producerControlledByApp, QueueBufferOutput *output) { - ATRACE_CALL(); - Mutex::Autolock lock(mCore->mMutex); - mConsumerName = mCore->mConsumerName; - ALOGV("connect(P): api=%d producerControlledByApp=%s", api, - producerControlledByApp ? "true" : "false"); - - if (mCore->mIsAbandoned) { - ALOGE("connect(P): GonkBufferQueue has been abandoned"); - return NO_INIT; - } - - if (mCore->mConsumerListener == NULL) { - ALOGE("connect(P): GonkBufferQueue has no consumer"); - return NO_INIT; - } - - if (output == NULL) { - ALOGE("connect(P): output was NULL"); - return BAD_VALUE; - } - - if (mCore->mConnectedApi != GonkBufferQueueCore::NO_CONNECTED_API) { - ALOGE("connect(P): already connected (cur=%d req=%d)", mCore->mConnectedApi, - api); - return BAD_VALUE; - } - - int status = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - mCore->mConnectedApi = api; - output->inflate(mCore->mDefaultWidth, mCore->mDefaultHeight, - mCore->mTransformHint, mCore->mQueue.size()); - - // Set up a death notification so that we can disconnect - // automatically if the remote producer dies - if (listener != NULL && - listener->asBinder()->remoteBinder() != NULL) { - status = listener->asBinder()->linkToDeath( - static_cast(this)); - if (status != NO_ERROR) { - ALOGE("connect(P): linkToDeath failed: %s (%d)", - strerror(-status), status); - } - } - mCore->mConnectedProducerListener = listener; - break; - default: - ALOGE("connect(P): unknown API %d", api); - status = BAD_VALUE; - break; - } - - mCore->mBufferHasBeenQueued = false; - mCore->mDequeueBufferCannotBlock = - mCore->mConsumerControlledByApp && producerControlledByApp; - - return status; -} - -status_t GonkBufferQueueProducer::disconnect(int api) { - ATRACE_CALL(); - ALOGV("disconnect(P): api %d", api); - - int status = NO_ERROR; - sp listener; - { // Autolock scope - Mutex::Autolock lock(mCore->mMutex); - mCore->waitWhileAllocatingLocked(); - - if (mCore->mIsAbandoned) { - // It's not really an error to disconnect after the surface has - // been abandoned; it should just be a no-op. - return NO_ERROR; - } - - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mCore->mConnectedApi == api) { - mCore->freeAllBuffersLocked(); - mCore->mConnectedApi = GonkBufferQueueCore::NO_CONNECTED_API; - mCore->mSidebandStream.clear(); - mCore->mDequeueCondition.broadcast(); - listener = mCore->mConsumerListener; - } else { - ALOGE("disconnect(P): connected to another API " - "(cur=%d req=%d)", mCore->mConnectedApi, api); - status = BAD_VALUE; - } - break; - default: - ALOGE("disconnect(P): unknown API %d", api); - status = BAD_VALUE; - break; - } - } // Autolock scope - - // Call back without lock held - if (listener != NULL) { - listener->onBuffersReleased(); - } - - return status; -} - -status_t GonkBufferQueueProducer::setSidebandStream(const sp& stream) { - return INVALID_OPERATION; -} - -void GonkBufferQueueProducer::allocateBuffers(bool async, uint32_t width, - uint32_t height, uint32_t format, uint32_t usage) { - ALOGE("allocateBuffers: no op"); -} - -void GonkBufferQueueProducer::binderDied(const wp& /* who */) { - // If we're here, it means that a producer we were connected to died. - // We're guaranteed that we are still connected to it because we remove - // this callback upon disconnect. It's therefore safe to read mConnectedApi - // without synchronization here. - int api = mCore->mConnectedApi; - disconnect(api); -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h deleted file mode 100644 index a1a22416a..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferQueueProducer.h +++ /dev/null @@ -1,216 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERQUEUEPRODUCER_LL_H -#define NATIVEWINDOW_GONKBUFFERQUEUEPRODUCER_LL_H - -#include "GonkBufferQueueDefs.h" -#include - -namespace android { - -class GonkBufferQueueProducer : public BnGraphicBufferProducer, - private IBinder::DeathRecipient { -public: - friend class GonkBufferQueue; // Needed to access binderDied - - GonkBufferQueueProducer(const sp& core); - virtual ~GonkBufferQueueProducer(); - - // requestBuffer returns the GraphicBuffer for slot N. - // - // In normal operation, this is called the first time slot N is returned - // by dequeueBuffer. It must be called again if dequeueBuffer returns - // flags indicating that previously-returned buffers are no longer valid. - virtual status_t requestBuffer(int slot, sp* buf); - - // setBufferCount updates the number of available buffer slots. If this - // method succeeds, buffer slots will be both unallocated and owned by - // the GonkBufferQueue object (i.e. they are not owned by the producer or - // consumer). - // - // This will fail if the producer has dequeued any buffers, or if - // bufferCount is invalid. bufferCount must generally be a value - // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS - // (inclusive). It may also be set to zero (the default) to indicate - // that the producer does not wish to set a value. The minimum value - // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - // ...). - // - // This may only be called by the producer. The consumer will be told - // to discard buffers through the onBuffersReleased callback. - virtual status_t setBufferCount(int bufferCount); - - // dequeueBuffer gets the next buffer slot index for the producer to use. - // If a buffer slot is available then that slot index is written to the - // location pointed to by the buf argument and a status of OK is returned. - // If no slot is available then a status of -EBUSY is returned and buf is - // unmodified. - // - // The outFence parameter will be updated to hold the fence associated with - // the buffer. The contents of the buffer must not be overwritten until the - // fence signals. If the fence is Fence::NO_FENCE, the buffer may be - // written immediately. - // - // The width and height parameters must be no greater than the minimum of - // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv). - // An error due to invalid dimensions might not be reported until - // updateTexImage() is called. If width and height are both zero, the - // default values specified by setDefaultBufferSize() are used instead. - // - // The pixel formats are enumerated in graphics.h, e.g. - // HAL_PIXEL_FORMAT_RGBA_8888. If the format is 0, the default format - // will be used. - // - // The usage argument specifies gralloc buffer usage flags. The values - // are enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER. These - // will be merged with the usage flags specified by setConsumerUsageBits. - // - // The return value may be a negative error value or a non-negative - // collection of flags. If the flags are set, the return values are - // valid, but additional actions must be performed. - // - // If IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION is set, the - // producer must discard cached GraphicBuffer references for the slot - // returned in buf. - // If IGraphicBufferProducer::RELEASE_ALL_BUFFERS is set, the producer - // must discard cached GraphicBuffer references for all slots. - // - // In both cases, the producer will need to call requestBuffer to get a - // GraphicBuffer handle for the returned slot. - virtual status_t dequeueBuffer(int *outSlot, sp* outFence, bool async, - uint32_t width, uint32_t height, uint32_t format, uint32_t usage); - - // See IGraphicBufferProducer::detachBuffer - virtual status_t detachBuffer(int slot); - - // See IGraphicBufferProducer::detachNextBuffer - virtual status_t detachNextBuffer(sp* outBuffer, - sp* outFence); - - // See IGraphicBufferProducer::attachBuffer - virtual status_t attachBuffer(int* outSlot, const sp& buffer); - - // queueBuffer returns a filled buffer to the GonkBufferQueue. - // - // Additional data is provided in the QueueBufferInput struct. Notably, - // a timestamp must be provided for the buffer. The timestamp is in - // nanoseconds, and must be monotonically increasing. Its other semantics - // (zero point, etc) are producer-specific and should be documented by the - // producer. - // - // The caller may provide a fence that signals when all rendering - // operations have completed. Alternatively, NO_FENCE may be used, - // indicating that the buffer is ready immediately. - // - // Some values are returned in the output struct: the current settings - // for default width and height, the current transform hint, and the - // number of queued buffers. - virtual status_t queueBuffer(int slot, - const QueueBufferInput& input, QueueBufferOutput* output); - - // cancelBuffer returns a dequeued buffer to the GonkBufferQueue, but doesn't - // queue it for use by the consumer. - // - // The buffer will not be overwritten until the fence signals. The fence - // will usually be the one obtained from dequeueBuffer. - virtual void cancelBuffer(int slot, const sp& fence); - - // Query native window attributes. The "what" values are enumerated in - // window.h (e.g. NATIVE_WINDOW_FORMAT). - virtual int query(int what, int* outValue); - - // connect attempts to connect a producer API to the GonkBufferQueue. This - // must be called before any other IGraphicBufferProducer methods are - // called except for getAllocator. A consumer must already be connected. - // - // This method will fail if connect was previously called on the - // GonkBufferQueue and no corresponding disconnect call was made (i.e. if - // it's still connected to a producer). - // - // APIs are enumerated in window.h (e.g. NATIVE_WINDOW_API_CPU). - virtual status_t connect(const sp& listener, - int api, bool producerControlledByApp, QueueBufferOutput* output); - - // disconnect attempts to disconnect a producer API from the GonkBufferQueue. - // Calling this method will cause any subsequent calls to other - // IGraphicBufferProducer methods to fail except for getAllocator and connect. - // Successfully calling connect after this will allow the other methods to - // succeed again. - // - // This method will fail if the the GonkBufferQueue is not currently - // connected to the specified producer API. - virtual status_t disconnect(int api); - - // Attaches a sideband buffer stream to the IGraphicBufferProducer. - // - // A sideband stream is a device-specific mechanism for passing buffers - // from the producer to the consumer without using dequeueBuffer/ - // queueBuffer. If a sideband stream is present, the consumer can choose - // whether to acquire buffers from the sideband stream or from the queued - // buffers. - // - // Passing NULL or a different stream handle will detach the previous - // handle if any. - virtual status_t setSidebandStream(const sp& stream); - - // See IGraphicBufferProducer::allocateBuffers - virtual void allocateBuffers(bool async, uint32_t width, uint32_t height, - uint32_t format, uint32_t usage); - - // setSynchronousMode sets whether dequeueBuffer is synchronous or - // asynchronous. In synchronous mode, dequeueBuffer blocks until - // a buffer is available, the currently bound buffer can be dequeued and - // queued buffers will be acquired in order. In asynchronous mode, - // a queued buffer may be replaced by a subsequently queued buffer. - // - // The default mode is synchronous. - // This should be called only during initialization. - virtual status_t setSynchronousMode(bool enabled); - -private: - // This is required by the IBinder::DeathRecipient interface - virtual void binderDied(const wp& who); - - // waitForFreeSlotThenRelock finds the oldest slot in the FREE state. It may - // block if there are no available slots and we are not in non-blocking - // mode (producer and consumer controlled by the application). If it blocks, - // it will release mCore->mMutex while blocked so that other operations on - // the GonkBufferQueue may succeed. - status_t waitForFreeSlotThenRelock(const char* caller, bool async, - int* found, status_t* returnFlags) const; - - sp mCore; - - // This references mCore->mSlots. Lock mCore->mMutex while accessing. - GonkBufferQueueDefs::SlotsType& mSlots; - - // This is a cached copy of the name stored in the GonkBufferQueueCore. - // It's updated during connect and dequeueBuffer (which should catch - // most updates). - String8 mConsumerName; - - // mSynchronousMode whether we're in synchronous mode or not - bool mSynchronousMode; - - uint32_t mStickyTransform; - -}; // class GonkBufferQueueProducer - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp deleted file mode 100644 index 9e4a424a9..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include "GonkBufferSlot.h" - -namespace android { - -const char* GonkBufferSlot::bufferStateName(BufferState state) { - switch (state) { - case GonkBufferSlot::DEQUEUED: return "DEQUEUED"; - case GonkBufferSlot::QUEUED: return "QUEUED"; - case GonkBufferSlot::FREE: return "FREE"; - case GonkBufferSlot::ACQUIRED: return "ACQUIRED"; - default: return "Unknown"; - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h b/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h deleted file mode 100644 index 759bb7b23..000000000 --- a/widget/gonk/nativewindow/GonkBufferQueueLL/GonkBufferSlot.h +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2014 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKBUFFERSLOT_LL_H -#define NATIVEWINDOW_GONKBUFFERSLOT_LL_H - -#include -#include - -#include - -#include "mozilla/layers/TextureClient.h" - -namespace android { - -struct GonkBufferSlot { - typedef mozilla::layers::TextureClient TextureClient; - - GonkBufferSlot() - : mBufferState(GonkBufferSlot::FREE), - mRequestBufferCalled(false), - mFrameNumber(0), - mAcquireCalled(false), - mNeedsCleanupOnRelease(false), - mAttachedByConsumer(false) { - } - - // mGraphicBuffer points to the buffer allocated for this slot or is NULL - // if no buffer has been allocated. - sp mGraphicBuffer; - - // BufferState represents the different states in which a buffer slot - // can be. All slots are initially FREE. - enum BufferState { - // FREE indicates that the buffer is available to be dequeued - // by the producer. The buffer may be in use by the consumer for - // a finite time, so the buffer must not be modified until the - // associated fence is signaled. - // - // The slot is "owned" by BufferQueue. It transitions to DEQUEUED - // when dequeueBuffer is called. - FREE = 0, - - // DEQUEUED indicates that the buffer has been dequeued by the - // producer, but has not yet been queued or canceled. The - // producer may modify the buffer's contents as soon as the - // associated ready fence is signaled. - // - // The slot is "owned" by the producer. It can transition to - // QUEUED (via queueBuffer) or back to FREE (via cancelBuffer). - DEQUEUED = 1, - - // QUEUED indicates that the buffer has been filled by the - // producer and queued for use by the consumer. The buffer - // contents may continue to be modified for a finite time, so - // the contents must not be accessed until the associated fence - // is signaled. - // - // The slot is "owned" by BufferQueue. It can transition to - // ACQUIRED (via acquireBuffer) or to FREE (if another buffer is - // queued in asynchronous mode). - QUEUED = 2, - - // ACQUIRED indicates that the buffer has been acquired by the - // consumer. As with QUEUED, the contents must not be accessed - // by the consumer until the fence is signaled. - // - // The slot is "owned" by the consumer. It transitions to FREE - // when releaseBuffer is called. - ACQUIRED = 3 - }; - - static const char* bufferStateName(BufferState state); - - // mBufferState is the current state of this buffer slot. - BufferState mBufferState; - - // mRequestBufferCalled is used for validating that the producer did - // call requestBuffer() when told to do so. Technically this is not - // needed but useful for debugging and catching producer bugs. - bool mRequestBufferCalled; - - // mFrameNumber is the number of the queued frame for this slot. This - // is used to dequeue buffers in LRU order (useful because buffers - // may be released before their release fence is signaled). - uint64_t mFrameNumber; - - // mFence is a fence which will signal when work initiated by the - // previous owner of the buffer is finished. When the buffer is FREE, - // the fence indicates when the consumer has finished reading - // from the buffer, or when the producer has finished writing if it - // called cancelBuffer after queueing some writes. When the buffer is - // QUEUED, it indicates when the producer has finished filling the - // buffer. When the buffer is DEQUEUED or ACQUIRED, the fence has been - // passed to the consumer or producer along with ownership of the - // buffer, and mFence is set to NO_FENCE. - sp mFence; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates whether this buffer needs to be cleaned up by the - // consumer. This is set when a buffer in ACQUIRED state is freed. - // It causes releaseBuffer to return STALE_BUFFER_SLOT. - bool mNeedsCleanupOnRelease; - - // Indicates whether the buffer was attached on the consumer side. - // If so, it needs to set the BUFFER_NEEDS_REALLOCATION flag when dequeued - // to prevent the producer from using a stale cached buffer. - bool mAttachedByConsumer; - - // mTextureClient is a thin abstraction over remotely allocated GraphicBuffer. - RefPtr mTextureClient; -}; - -} // namespace android - -#endif diff --git a/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp b/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp deleted file mode 100644 index 1ee37e4e2..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseJB.cpp +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkConsumerBase" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define EGL_EGLEXT_PROTOTYPES - -#include - -#include -#include -#include - -#include "GonkConsumerBaseJB.h" - -// Macros for including the GonkConsumerBase name in log messages -#define CB_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#define CB_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define CB_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define CB_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define CB_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -GonkConsumerBase::GonkConsumerBase(const sp& bufferQueue) : - mAbandoned(false), - mBufferQueue(bufferQueue) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp listener; - sp proxy; - listener = static_cast(this); - proxy = new GonkBufferQueue::ProxyConsumerListener(listener); - - status_t err = mBufferQueue->consumerConnect(proxy); - if (err != NO_ERROR) { - CB_LOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", - strerror(-err), err); - } else { - mBufferQueue->setConsumerName(mName); - } -} - -GonkConsumerBase::~GonkConsumerBase() { - CB_LOGV("~GonkConsumerBase"); - Mutex::Autolock lock(mMutex); - - // Verify that abandon() has been called before we get here. This should - // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a - // derived class to override that method and not call - // GonkConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); -} - -void GonkConsumerBase::onLastStrongRef(const void* id) { - abandon(); -} - -void GonkConsumerBase::freeBufferLocked(int slotIndex) { - CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = Fence::NO_FENCE; -} - -// Used for refactoring, should not be in final interface -sp GonkConsumerBase::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mBufferQueue; -} - -void GonkConsumerBase::onFrameAvailable() { - CB_LOGV("onFrameAvailable"); - - sp listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); -#if ANDROID_VERSION == 17 - listener = mFrameAvailableListener; -#else - listener = mFrameAvailableListener.promote(); -#endif - } - - if (listener != NULL) { - CB_LOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void GonkConsumerBase::onBuffersReleased() { - Mutex::Autolock lock(mMutex); - - CB_LOGV("onBuffersReleased"); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint32_t mask = 0; - mBufferQueue->getReleasedBuffers(&mask); - for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } -} - -void GonkConsumerBase::abandon() { - CB_LOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - abandonLocked(); - mAbandoned = true; - } -} - -void GonkConsumerBase::abandonLocked() { - CB_LOGV("abandonLocked"); - for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - // disconnect from the GonkBufferQueue - mBufferQueue->consumerDisconnect(); - mBufferQueue.clear(); -} - -void GonkConsumerBase::setFrameAvailableListener( -#if ANDROID_VERSION == 17 - const sp& listener) { -#else - const wp& listener) { -#endif - CB_LOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void GonkConsumerBase::dump(String8& result) const { - char buffer[1024]; - dump(result, "", buffer, 1024); -} - -void GonkConsumerBase::dump(String8& result, const char* prefix, - char* buffer, size_t size) const { - Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix, buffer, size); -} - -void GonkConsumerBase::dumpLocked(String8& result, const char* prefix, - char* buffer, size_t SIZE) const { - snprintf(buffer, SIZE, "%smAbandoned=%d\n", prefix, int(mAbandoned)); - result.append(buffer); - - if (!mAbandoned) { - mBufferQueue->dumpToString(result, prefix, buffer, SIZE); - } -} - -status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item) { - status_t err = mBufferQueue->acquireBuffer(item); - if (err != NO_ERROR) { - return err; - } - - if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; - } - - mSlots[item->mBuf].mFence = item->mFence; - - CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf); - - return OK; -} - -status_t GonkConsumerBase::addReleaseFence(int slot, const sp& fence) { - Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, fence); -} - -status_t GonkConsumerBase::addReleaseFenceLocked(int slot, const sp& fence) { - CB_LOGV("addReleaseFenceLocked: slot=%d", slot); - - if (!mSlots[slot].mFence.get()) { - mSlots[slot].mFence = fence; - } else { - sp mergedFence = Fence::merge( - String8::format("%.28s:%d", mName.string(), slot), - mSlots[slot].mFence, fence); - if (!mergedFence.get()) { - CB_LOGE("failed to merge release fences"); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - mSlots[slot].mFence = fence; - return BAD_VALUE; - } - mSlots[slot].mFence = mergedFence; - } - - return OK; -} - -status_t GonkConsumerBase::releaseBufferLocked(int slot) { - CB_LOGV("releaseBufferLocked: slot=%d", slot); - status_t err = mBufferQueue->releaseBuffer(slot, mSlots[slot].mFence); - if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(slot); - } - - mSlots[slot].mFence = Fence::NO_FENCE; - - return err; -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseJB.h b/widget/gonk/nativewindow/GonkConsumerBaseJB.h deleted file mode 100644 index 8f523af37..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseJB.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKCONSUMERBASE_JB_H -#define NATIVEWINDOW_GONKCONSUMERBASE_JB_H - -#include - -#include -#include -#include - -#include "GonkBufferQueueJB.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class String8; - -// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It -// handles common tasks like management of the connection to the GonkBufferQueue -// and the buffer pool. -class GonkConsumerBase : public virtual RefBase, - protected GonkBufferQueue::ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - virtual ~GonkConsumerBase(); - - // abandon frees all the buffers and puts the GonkConsumerBase into the - // 'abandoned' state. Once put in this state the GonkConsumerBase can never - // leave it. When in the 'abandoned' state, all methods of the - // IGraphicBufferProducer interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the GonkConsumerBase, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client - // or by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the GonkConsumerBase that will be used to identify it in - // log messages. - void setName(const String8& name); - - // getBufferQueue returns the GonkBufferQueue object to which this - // GonkConsumerBase is connected. - sp getBufferQueue() const; - - // dump writes the current state to a string. Child classes should add - // their state to the dump by overriding the dumpLocked method, which is - // called by these methods after locking the mutex. - void dump(String8& result) const; - void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const; - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. -#if ANDROID_VERSION == 17 - void setFrameAvailableListener(const sp& listener); -#else - void setFrameAvailableListener(const wp& listener); -#endif - -private: - GonkConsumerBase(const GonkConsumerBase&); - void operator=(const GonkConsumerBase&); - -protected: - - // GonkConsumerBase constructs a new GonkConsumerBase object to consume image - // buffers from the given GonkBufferQueue. - GonkConsumerBase(const sp &bufferQueue); - - // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that GonkConsumerBase - // can coordinate the clean-up by calling into virtual methods implemented - // by the derived classes. This would not be possible from the - // ConsuemrBase dtor because by the time that gets called the derived - // classes have already been destructed. - // - // This methods should not need to be overridden by derived classes, but - // if they are overridden the GonkConsumerBase implementation must be called - // from the derived class. - virtual void onLastStrongRef(const void* id); - - // Implementation of the GonkBufferQueue::ConsumerListener interface. These - // calls are used to notify the GonkConsumerBase of asynchronous events in the - // GonkBufferQueue. These methods should not need to be overridden by derived - // classes, but if they are overridden the GonkConsumerBase implementation - // must be called from the derived class. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot. Otherwise it has no effect. - // - // Derived classes should override this method to clean up any state they - // keep per slot. If it is overridden, the derived class's implementation - // must call GonkConsumerBase::freeBufferLocked. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex); - - // abandonLocked puts the GonkBufferQueue into the abandoned state, causing - // all future operations on it to fail. This method rather than the public - // abandon method should be overridden by child classes to add abandon- - // time behavior. - // - // Derived classes should override this method to clean up any object - // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call GonkConsumerBase::abandonLocked. - // - // This method must be called with mMutex locked. - virtual void abandonLocked(); - - // dumpLocked dumps the current state of the GonkConsumerBase object to the - // result string. Each line is prefixed with the string pointed to by the - // prefix argument. The buffer argument points to a buffer that may be - // used for intermediate formatting data, and the size of that buffer is - // indicated by the size argument. - // - // Derived classes should override this method to dump their internal - // state. If this method is overridden the derived class's implementation - // should call GonkConsumerBase::dumpLocked. - // - // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix, char* buffer, - size_t size) const; - - // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and - // updates the buffer slot for the buffer returned. - // - // Derived classes should override this method to perform any - // initialization that must take place the first time a buffer is assigned - // to a slot. If it is overridden the derived class's implementation must - // call GonkConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(GonkBufferQueue::BufferItem *item); - - // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the GonkBufferQueue. - // - // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the GonkBufferQueue. If - // it is overridden the derived class's implementation must call - // GonkConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int buf); - - // addReleaseFence* adds the sync points associated with a fence to the set - // of sync points that must be reached before the buffer in the given slot - // may be used after the slot has been released. This should be called by - // derived classes each time some asynchronous work is kicked off that - // references the buffer. - status_t addReleaseFence(int slot, const sp& fence); - status_t addReleaseFenceLocked(int slot, const sp& fence); - - // Slot contains the information and object references that - // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. - struct Slot { - // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if - // no Gralloc buffer is in the slot. - sp mGraphicBuffer; - - // mFence is a fence which will signal when the buffer associated with - // this buffer slot is no longer being used by the consumer and can be - // overwritten. The buffer can be dequeued before the fence signals; - // the producer is responsible for delaying writes until it signals. - sp mFence; - }; - - // mSlots stores the buffers that have been allocated by the GonkBufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of GonkBufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume images buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the abandon - // method. A GonkBufferQueue that has been abandoned will return the NO_INIT - // error from all IGonkConsumerBase methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the GonkConsumerBase in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. -#if ANDROID_VERSION == 17 - sp mFrameAvailableListener; -#else - wp mFrameAvailableListener; -#endif - - // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object - // if none is supplied - sp mBufferQueue; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkConsumerBase objects. It must be locked whenever the - // member variables are accessed or when any of the *Locked methods are - // called. - // - // This mutex is intended to be locked by derived classes. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKCONSUMERBASE_H diff --git a/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp b/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp deleted file mode 100644 index 3fc9fc16c..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseKK.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#define LOG_TAG "GonkConsumerBase" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define EGL_EGLEXT_PROTOTYPES - -#include - -#include -#include -#include - -#include "GonkConsumerBaseKK.h" - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -GonkConsumerBase::GonkConsumerBase(const sp& bufferQueue, bool controlledByApp) : - mAbandoned(false), - mConsumer(bufferQueue) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp listener = static_cast(this); - sp proxy = new GonkBufferQueue::ProxyConsumerListener(listener); - - status_t err = mConsumer->consumerConnect(proxy, controlledByApp); - if (err != NO_ERROR) { - ALOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", - strerror(-err), err); - } else { - mConsumer->setConsumerName(mName); - } -} - -GonkConsumerBase::~GonkConsumerBase() { - ALOGV("~GonkConsumerBase"); - Mutex::Autolock lock(mMutex); - - // Verify that abandon() has been called before we get here. This should - // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a - // derived class to override that method and not call - // GonkConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); -} - -void GonkConsumerBase::onLastStrongRef(const void* id) { - abandon(); -} - -void GonkConsumerBase::freeBufferLocked(int slotIndex) { - ALOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = Fence::NO_FENCE; - mSlots[slotIndex].mFrameNumber = 0; -} - -// Used for refactoring, should not be in final interface -sp GonkConsumerBase::getBufferQueue() const { - Mutex::Autolock lock(mMutex); - return mConsumer; -} - -void GonkConsumerBase::onFrameAvailable() { - ALOGV("onFrameAvailable"); - - sp listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener.promote(); - } - - if (listener != NULL) { - ALOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void GonkConsumerBase::onBuffersReleased() { - Mutex::Autolock lock(mMutex); - - ALOGV("onBuffersReleased"); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint32_t mask = 0; - mConsumer->getReleasedBuffers(&mask); - for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1 << i)) { - freeBufferLocked(i); - } - } -} - -void GonkConsumerBase::abandon() { - ALOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - abandonLocked(); - mAbandoned = true; - } -} - -void GonkConsumerBase::abandonLocked() { - ALOGV("abandonLocked"); - for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - // disconnect from the BufferQueue - mConsumer->consumerDisconnect(); - mConsumer.clear(); -} - -void GonkConsumerBase::setFrameAvailableListener( - const wp& listener) { - ALOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void GonkConsumerBase::dump(String8& result) const { - dump(result, ""); -} - -void GonkConsumerBase::dump(String8& result, const char* prefix) const { - Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix); -} - -void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); - - if (!mAbandoned) { - mConsumer->dumpToString(result, prefix); - } -} - -status_t GonkConsumerBase::acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); - if (err != NO_ERROR) { - return err; - } - - if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; - } - - mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; - mSlots[item->mBuf].mFence = item->mFence; - - ALOGV("acquireBufferLocked: -> slot=%d", item->mBuf); - - return OK; -} - -status_t GonkConsumerBase::addReleaseFence(int slot, - const sp graphicBuffer, const sp& fence) { - Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, graphicBuffer, fence); -} - -status_t GonkConsumerBase::addReleaseFenceLocked(int slot, - const sp graphicBuffer, const sp& fence) { - ALOGV("addReleaseFenceLocked: slot=%d", slot); - - // If consumer no longer tracks this graphicBuffer, we can safely - // drop this fence, as it will never be received by the producer. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - if (!mSlots[slot].mFence.get()) { - mSlots[slot].mFence = fence; - } else { - sp mergedFence = Fence::merge( - String8::format("%.28s:%d", mName.string(), slot), - mSlots[slot].mFence, fence); - if (!mergedFence.get()) { - ALOGE("failed to merge release fences"); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - mSlots[slot].mFence = fence; - return BAD_VALUE; - } - mSlots[slot].mFence = mergedFence; - } - - return OK; -} - -status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp graphicBuffer) { - // If consumer no longer tracks this graphicBuffer (we received a new - // buffer on the same slot), the buffer producer is definitely no longer - // tracking it. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - ALOGV("releaseBufferLocked: slot=%d/%llu", - slot, mSlots[slot].mFrameNumber); - status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); - if (err == GonkBufferQueue::STALE_BUFFER_SLOT) { - freeBufferLocked(slot); - } - - mSlots[slot].mFence = Fence::NO_FENCE; - - return err; -} - -bool GonkConsumerBase::stillTracking(int slot, - const sp graphicBuffer) { - if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { - return false; - } - return (mSlots[slot].mGraphicBuffer != NULL && - mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseKK.h b/widget/gonk/nativewindow/GonkConsumerBaseKK.h deleted file mode 100644 index e198ad843..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseKK.h +++ /dev/null @@ -1,240 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKCONSUMERBASE_KK_H -#define NATIVEWINDOW_GONKCONSUMERBASE_KK_H - -#include - -#include -#include -#include -#include - -#include "GonkBufferQueueKK.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class String8; - -// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It -// handles common tasks like management of the connection to the GonkBufferQueue -// and the buffer pool. -class GonkConsumerBase : public virtual RefBase, - protected ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - virtual ~GonkConsumerBase(); - - // abandon frees all the buffers and puts the GonkConsumerBase into the - // 'abandoned' state. Once put in this state the GonkConsumerBase can never - // leave it. When in the 'abandoned' state, all methods of the - // IGraphicBufferProducer interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the GonkConsumerBase, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client - // or by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the GonkConsumerBase that will be used to identify it in - // log messages. - void setName(const String8& name); - - // getBufferQueue returns the GonkBufferQueue object to which this - // GonkConsumerBase is connected. - sp getBufferQueue() const; - - // dump writes the current state to a string. Child classes should add - // their state to the dump by overriding the dumpLocked method, which is - // called by these methods after locking the mutex. - void dump(String8& result) const; - void dump(String8& result, const char* prefix) const; - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const wp& listener); - -private: - GonkConsumerBase(const GonkConsumerBase&); - void operator=(const GonkConsumerBase&); - -protected: - - // GonkConsumerBase constructs a new GonkConsumerBase object to consume image - // buffers from the given GonkBufferQueue. - GonkConsumerBase(const sp& bufferQueue, bool controlledByApp = false); - - // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that GonkConsumerBase - // can coordinate the clean-up by calling into virtual methods implemented - // by the derived classes. This would not be possible from the - // ConsuemrBase dtor because by the time that gets called the derived - // classes have already been destructed. - // - // This methods should not need to be overridden by derived classes, but - // if they are overridden the GonkConsumerBase implementation must be called - // from the derived class. - virtual void onLastStrongRef(const void* id); - - // Implementation of the GonkBufferQueue::ConsumerListener interface. These - // calls are used to notify the GonkConsumerBase of asynchronous events in the - // GonkBufferQueue. These methods should not need to be overridden by derived - // classes, but if they are overridden the GonkConsumerBase implementation - // must be called from the derived class. - virtual void onFrameAvailable(); - virtual void onBuffersReleased(); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot. Otherwise it has no effect. - // - // Derived classes should override this method to clean up any state they - // keep per slot. If it is overridden, the derived class's implementation - // must call GonkConsumerBase::freeBufferLocked. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex); - - // abandonLocked puts the GonkBufferQueue into the abandoned state, causing - // all future operations on it to fail. This method rather than the public - // abandon method should be overridden by child classes to add abandon- - // time behavior. - // - // Derived classes should override this method to clean up any object - // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call GonkConsumerBase::abandonLocked. - // - // This method must be called with mMutex locked. - virtual void abandonLocked(); - - // dumpLocked dumps the current state of the GonkConsumerBase object to the - // result string. Each line is prefixed with the string pointed to by the - // prefix argument. The buffer argument points to a buffer that may be - // used for intermediate formatting data, and the size of that buffer is - // indicated by the size argument. - // - // Derived classes should override this method to dump their internal - // state. If this method is overridden the derived class's implementation - // should call GonkConsumerBase::dumpLocked. - // - // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix) const; - - // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and - // updates the buffer slot for the buffer returned. - // - // Derived classes should override this method to perform any - // initialization that must take place the first time a buffer is assigned - // to a slot. If it is overridden the derived class's implementation must - // call GonkConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen); - - // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the GonkBufferQueue. - // - // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the GonkBufferQueue. If - // it is overridden the derived class's implementation must call - // GonkConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer); - - // returns true iff the slot still has the graphicBuffer in it. - bool stillTracking(int slot, const sp graphicBuffer); - - // addReleaseFence* adds the sync points associated with a fence to the set - // of sync points that must be reached before the buffer in the given slot - // may be used after the slot has been released. This should be called by - // derived classes each time some asynchronous work is kicked off that - // references the buffer. - status_t addReleaseFence(int slot, - const sp graphicBuffer, const sp& fence); - status_t addReleaseFenceLocked(int slot, - const sp graphicBuffer, const sp& fence); - - // Slot contains the information and object references that - // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. - struct Slot { - // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if - // no Gralloc buffer is in the slot. - sp mGraphicBuffer; - - // mFence is a fence which will signal when the buffer associated with - // this buffer slot is no longer being used by the consumer and can be - // overwritten. The buffer can be dequeued before the fence signals; - // the producer is responsible for delaying writes until it signals. - sp mFence; - - // the frame number of the last acquired frame for this slot - uint64_t mFrameNumber; - }; - - // mSlots stores the buffers that have been allocated by the GonkBufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of GonkBufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume images buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the abandon - // method. A GonkBufferQueue that has been abandoned will return the NO_INIT - // error from all IGonkConsumerBase methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the GonkConsumerBase in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - wp mFrameAvailableListener; - - // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object - // if none is supplied - sp mConsumer; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkConsumerBase objects. It must be locked whenever the - // member variables are accessed or when any of the *Locked methods are - // called. - // - // This mutex is intended to be locked by derived classes. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKCONSUMERBASE_H diff --git a/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp b/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp deleted file mode 100644 index 5b1166b57..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseLL.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#include - -#define LOG_TAG "GonkConsumerBase" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -//#define LOG_NDEBUG 0 - -#define EGL_EGLEXT_PROTOTYPES - -#include - -#include - -#include -#include - -#include "GonkConsumerBaseLL.h" - -namespace android { - -// Get an ID that's unique within this process. -static int32_t createProcessUniqueId() { - static volatile int32_t globalCounter = 0; - return android_atomic_inc(&globalCounter); -} - -GonkConsumerBase::GonkConsumerBase(const sp& bufferQueue, bool controlledByApp) : - mAbandoned(false), - mConsumer(bufferQueue) { - // Choose a name using the PID and a process-unique ID. - mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId()); - - // Note that we can't create an sp<...>(this) in a ctor that will not keep a - // reference once the ctor ends, as that would cause the refcount of 'this' - // dropping to 0 at the end of the ctor. Since all we need is a wp<...> - // that's what we create. - wp listener = static_cast(this); - sp proxy = new GonkBufferQueue::ProxyConsumerListener(listener); - - status_t err = mConsumer->consumerConnect(proxy, controlledByApp); - if (err != NO_ERROR) { - ALOGE("GonkConsumerBase: error connecting to GonkBufferQueue: %s (%d)", - strerror(-err), err); - } else { - mConsumer->setConsumerName(mName); - } -} - -GonkConsumerBase::~GonkConsumerBase() { - ALOGV("~GonkConsumerBase"); - Mutex::Autolock lock(mMutex); - - // Verify that abandon() has been called before we get here. This should - // be done by GonkConsumerBase::onLastStrongRef(), but it's possible for a - // derived class to override that method and not call - // GonkConsumerBase::onLastStrongRef(). - LOG_ALWAYS_FATAL_IF(!mAbandoned, "[%s] ~GonkConsumerBase was called, but the " - "consumer is not abandoned!", mName.string()); -} - -void GonkConsumerBase::onLastStrongRef(const void* id __attribute__((unused))) { - abandon(); -} - -void GonkConsumerBase::freeBufferLocked(int slotIndex) { - ALOGV("freeBufferLocked: slotIndex=%d", slotIndex); - mSlots[slotIndex].mGraphicBuffer = 0; - mSlots[slotIndex].mFence = Fence::NO_FENCE; - mSlots[slotIndex].mFrameNumber = 0; -} - -#if ANDROID_VERSION == 21 -void GonkConsumerBase::onFrameAvailable() { -#else -void GonkConsumerBase::onFrameAvailable(const ::android::BufferItem& item) { -#endif - ALOGV("onFrameAvailable"); - - sp listener; - { // scope for the lock - Mutex::Autolock lock(mMutex); - listener = mFrameAvailableListener.promote(); - } - - if (listener != NULL) { - ALOGV("actually calling onFrameAvailable"); - listener->onFrameAvailable(); - } -} - -void GonkConsumerBase::onBuffersReleased() { - Mutex::Autolock lock(mMutex); - - ALOGV("onBuffersReleased"); - - if (mAbandoned) { - // Nothing to do if we're already abandoned. - return; - } - - uint64_t mask = 0; - mConsumer->getReleasedBuffers(&mask); - for (int i = 0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - if (mask & (1ULL << i)) { - freeBufferLocked(i); - } - } -} - -void GonkConsumerBase::onSidebandStreamChanged() { -} - -void GonkConsumerBase::abandon() { - ALOGV("abandon"); - Mutex::Autolock lock(mMutex); - - if (!mAbandoned) { - abandonLocked(); - mAbandoned = true; - } -} - -void GonkConsumerBase::abandonLocked() { - ALOGV("abandonLocked"); - for (int i =0; i < GonkBufferQueue::NUM_BUFFER_SLOTS; i++) { - freeBufferLocked(i); - } - // disconnect from the BufferQueue - mConsumer->consumerDisconnect(); - mConsumer.clear(); -} - -void GonkConsumerBase::setFrameAvailableListener( - const wp& listener) { - ALOGV("setFrameAvailableListener"); - Mutex::Autolock lock(mMutex); - mFrameAvailableListener = listener; -} - -void GonkConsumerBase::dump(String8& result) const { - dump(result, ""); -} - -void GonkConsumerBase::dump(String8& result, const char* prefix) const { - Mutex::Autolock _l(mMutex); - dumpLocked(result, prefix); -} - -void GonkConsumerBase::dumpLocked(String8& result, const char* prefix) const { - result.appendFormat("%smAbandoned=%d\n", prefix, int(mAbandoned)); - - if (!mAbandoned) { - mConsumer->dumpToString(result, prefix); - } -} - -status_t GonkConsumerBase::acquireBufferLocked(GonkBufferQueue::BufferItem *item, - nsecs_t presentWhen) { - status_t err = mConsumer->acquireBuffer(item, presentWhen); - if (err != NO_ERROR) { - return err; - } - - if (item->mGraphicBuffer != NULL) { - mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer; - } - - mSlots[item->mBuf].mFrameNumber = item->mFrameNumber; - mSlots[item->mBuf].mFence = item->mFence; - - ALOGV("acquireBufferLocked: -> slot=%d/%" PRIu64, - item->mBuf, item->mFrameNumber); - - return OK; -} - -status_t GonkConsumerBase::addReleaseFence(int slot, - const sp graphicBuffer, const sp& fence) { - Mutex::Autolock lock(mMutex); - return addReleaseFenceLocked(slot, graphicBuffer, fence); -} - -status_t GonkConsumerBase::addReleaseFenceLocked(int slot, - const sp graphicBuffer, const sp& fence) { - ALOGV("addReleaseFenceLocked: slot=%d", slot); - - // If consumer no longer tracks this graphicBuffer, we can safely - // drop this fence, as it will never be received by the producer. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - if (!mSlots[slot].mFence.get()) { - mSlots[slot].mFence = fence; - } else { - sp mergedFence = Fence::merge( - String8::format("%.28s:%d", mName.string(), slot), - mSlots[slot].mFence, fence); - if (!mergedFence.get()) { - ALOGE("failed to merge release fences"); - // synchronization is broken, the best we can do is hope fences - // signal in order so the new fence will act like a union - mSlots[slot].mFence = fence; - return BAD_VALUE; - } - mSlots[slot].mFence = mergedFence; - } - - return OK; -} - -status_t GonkConsumerBase::releaseBufferLocked(int slot, const sp graphicBuffer) { - // If consumer no longer tracks this graphicBuffer (we received a new - // buffer on the same slot), the buffer producer is definitely no longer - // tracking it. - if (!stillTracking(slot, graphicBuffer)) { - return OK; - } - - ALOGV("releaseBufferLocked: slot=%d/%" PRIu64, - slot, mSlots[slot].mFrameNumber); - status_t err = mConsumer->releaseBuffer(slot, mSlots[slot].mFrameNumber, mSlots[slot].mFence); - if (err == IGonkGraphicBufferConsumer::STALE_BUFFER_SLOT) { - freeBufferLocked(slot); - } - - mSlots[slot].mFence = Fence::NO_FENCE; - - return err; -} - -bool GonkConsumerBase::stillTracking(int slot, - const sp graphicBuffer) { - if (slot < 0 || slot >= GonkBufferQueue::NUM_BUFFER_SLOTS) { - return false; - } - return (mSlots[slot].mGraphicBuffer != NULL && - mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle); -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkConsumerBaseLL.h b/widget/gonk/nativewindow/GonkConsumerBaseLL.h deleted file mode 100644 index 0b2c2d166..000000000 --- a/widget/gonk/nativewindow/GonkConsumerBaseLL.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKCONSUMERBASE_LL_H -#define NATIVEWINDOW_GONKCONSUMERBASE_LL_H - -#include - -#include -#include -#include -#include - -#include "GonkBufferQueueLL.h" - -namespace android { -// ---------------------------------------------------------------------------- - -class String8; - -// GonkConsumerBase is a base class for GonkBufferQueue consumer end-points. It -// handles common tasks like management of the connection to the GonkBufferQueue -// and the buffer pool. -class GonkConsumerBase : public virtual RefBase, - protected ConsumerListener { -public: - struct FrameAvailableListener : public virtual RefBase { - // onFrameAvailable() is called each time an additional frame becomes - // available for consumption. This means that frames that are queued - // while in asynchronous mode only trigger the callback if no previous - // frames are pending. Frames queued while in synchronous mode always - // trigger the callback. - // - // This is called without any lock held and can be called concurrently - // by multiple threads. - virtual void onFrameAvailable() = 0; - }; - - virtual ~GonkConsumerBase(); - - // abandon frees all the buffers and puts the GonkConsumerBase into the - // 'abandoned' state. Once put in this state the GonkConsumerBase can never - // leave it. When in the 'abandoned' state, all methods of the - // IGraphicBufferProducer interface will fail with the NO_INIT error. - // - // Note that while calling this method causes all the buffers to be freed - // from the perspective of the the GonkConsumerBase, if there are additional - // references on the buffers (e.g. if a buffer is referenced by a client - // or by OpenGL ES as a texture) then those buffer will remain allocated. - void abandon(); - - // set the name of the GonkConsumerBase that will be used to identify it in - // log messages. - void setName(const String8& name); - - // dump writes the current state to a string. Child classes should add - // their state to the dump by overriding the dumpLocked method, which is - // called by these methods after locking the mutex. - void dump(String8& result) const; - void dump(String8& result, const char* prefix) const; - - // setFrameAvailableListener sets the listener object that will be notified - // when a new frame becomes available. - void setFrameAvailableListener(const wp& listener); - -private: - GonkConsumerBase(const GonkConsumerBase&); - void operator=(const GonkConsumerBase&); - -protected: - // GonkConsumerBase constructs a new GonkConsumerBase object to consume image - // buffers from the given IGonkGraphicBufferConsumer. - // The controlledByApp flag indicates that this consumer is under the application's - // control. - GonkConsumerBase(const sp& consumer, bool controlledByApp = false); - - // onLastStrongRef gets called by RefBase just before the dtor of the most - // derived class. It is used to clean up the buffers so that GonkConsumerBase - // can coordinate the clean-up by calling into virtual methods implemented - // by the derived classes. This would not be possible from the - // ConsuemrBase dtor because by the time that gets called the derived - // classes have already been destructed. - // - // This methods should not need to be overridden by derived classes, but - // if they are overridden the GonkConsumerBase implementation must be called - // from the derived class. - virtual void onLastStrongRef(const void* id); - - // Implementation of the IConsumerListener interface. These - // calls are used to notify the GonkConsumerBase of asynchronous events in the - // GonkBufferQueue. The onFrameAvailable and onBuffersReleased methods should - // not need to be overridden by derived classes, but if they are overridden - // the GonkConsumerBase implementation must be called from the derived class. - // The GonkConsumerBase version of onSidebandStreamChanged does nothing and can - // be overriden by derived classes if they want the notification. -#if ANDROID_VERSION == 21 - virtual void onFrameAvailable(); -#else - virtual void onFrameAvailable(const ::android::BufferItem& item); - virtual void onFrameReplaced(const ::android::BufferItem& item) {}; -#endif - virtual void onBuffersReleased(); - virtual void onSidebandStreamChanged(); - - // freeBufferLocked frees up the given buffer slot. If the slot has been - // initialized this will release the reference to the GraphicBuffer in that - // slot. Otherwise it has no effect. - // - // Derived classes should override this method to clean up any state they - // keep per slot. If it is overridden, the derived class's implementation - // must call GonkConsumerBase::freeBufferLocked. - // - // This method must be called with mMutex locked. - virtual void freeBufferLocked(int slotIndex); - - // abandonLocked puts the GonkBufferQueue into the abandoned state, causing - // all future operations on it to fail. This method rather than the public - // abandon method should be overridden by child classes to add abandon- - // time behavior. - // - // Derived classes should override this method to clean up any object - // state they keep (as opposed to per-slot state). If it is overridden, - // the derived class's implementation must call GonkConsumerBase::abandonLocked. - // - // This method must be called with mMutex locked. - virtual void abandonLocked(); - - // dumpLocked dumps the current state of the GonkConsumerBase object to the - // result string. Each line is prefixed with the string pointed to by the - // prefix argument. The buffer argument points to a buffer that may be - // used for intermediate formatting data, and the size of that buffer is - // indicated by the size argument. - // - // Derived classes should override this method to dump their internal - // state. If this method is overridden the derived class's implementation - // should call GonkConsumerBase::dumpLocked. - // - // This method must be called with mMutex locked. - virtual void dumpLocked(String8& result, const char* prefix) const; - - // acquireBufferLocked fetches the next buffer from the GonkBufferQueue and - // updates the buffer slot for the buffer returned. - // - // Derived classes should override this method to perform any - // initialization that must take place the first time a buffer is assigned - // to a slot. If it is overridden the derived class's implementation must - // call GonkConsumerBase::acquireBufferLocked. - virtual status_t acquireBufferLocked(IGonkGraphicBufferConsumer::BufferItem *item, - nsecs_t presentWhen); - - // releaseBufferLocked relinquishes control over a buffer, returning that - // control to the GonkBufferQueue. - // - // Derived classes should override this method to perform any cleanup that - // must take place when a buffer is released back to the GonkBufferQueue. If - // it is overridden the derived class's implementation must call - // GonkConsumerBase::releaseBufferLocked. - virtual status_t releaseBufferLocked(int slot, const sp graphicBuffer); - - // returns true iff the slot still has the graphicBuffer in it. - bool stillTracking(int slot, const sp graphicBuffer); - - // addReleaseFence* adds the sync points associated with a fence to the set - // of sync points that must be reached before the buffer in the given slot - // may be used after the slot has been released. This should be called by - // derived classes each time some asynchronous work is kicked off that - // references the buffer. - status_t addReleaseFence(int slot, - const sp graphicBuffer, const sp& fence); - status_t addReleaseFenceLocked(int slot, - const sp graphicBuffer, const sp& fence); - - // Slot contains the information and object references that - // GonkConsumerBase maintains about a GonkBufferQueue buffer slot. - struct Slot { - // mGraphicBuffer is the Gralloc buffer store in the slot or NULL if - // no Gralloc buffer is in the slot. - sp mGraphicBuffer; - - // mFence is a fence which will signal when the buffer associated with - // this buffer slot is no longer being used by the consumer and can be - // overwritten. The buffer can be dequeued before the fence signals; - // the producer is responsible for delaying writes until it signals. - sp mFence; - - // the frame number of the last acquired frame for this slot - uint64_t mFrameNumber; - }; - - // mSlots stores the buffers that have been allocated by the GonkBufferQueue - // for each buffer slot. It is initialized to null pointers, and gets - // filled in with the result of GonkBufferQueue::acquire when the - // client dequeues a buffer from a - // slot that has not yet been used. The buffer allocated to a slot will also - // be replaced if the requested buffer usage or geometry differs from that - // of the buffer allocated to a slot. - Slot mSlots[GonkBufferQueue::NUM_BUFFER_SLOTS]; - - // mAbandoned indicates that the GonkBufferQueue will no longer be used to - // consume images buffers pushed to it using the IGraphicBufferProducer - // interface. It is initialized to false, and set to true in the abandon - // method. A GonkBufferQueue that has been abandoned will return the NO_INIT - // error from all IConsumerBase methods capable of returning an error. - bool mAbandoned; - - // mName is a string used to identify the GonkConsumerBase in log messages. - // It can be set by the setName method. - String8 mName; - - // mFrameAvailableListener is the listener object that will be called when a - // new frame becomes available. If it is not NULL it will be called from - // queueBuffer. - wp mFrameAvailableListener; - - // The GonkConsumerBase has-a GonkBufferQueue and is responsible for creating this object - // if none is supplied - sp mConsumer; - - // mMutex is the mutex used to prevent concurrent access to the member - // variables of GonkConsumerBase objects. It must be locked whenever the - // member variables are accessed or when any of the *Locked methods are - // called. - // - // This mutex is intended to be locked by derived classes. - mutable Mutex mMutex; -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // NATIVEWINDOW_GONKCONSUMERBASE_LL_H diff --git a/widget/gonk/nativewindow/GonkNativeWindow.h b/widget/gonk/nativewindow/GonkNativeWindow.h deleted file mode 100644 index 61b6780b8..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindow.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "GonkNativeWindowLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "GonkNativeWindowKK.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 -# include "GonkNativeWindowJB.h" -#endif diff --git a/widget/gonk/nativewindow/GonkNativeWindowJB.cpp b/widget/gonk/nativewindow/GonkNativeWindowJB.cpp deleted file mode 100644 index e38642009..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowJB.cpp +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "GonkNativeWindow" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - -#include "GonkNativeWindowJB.h" -#include "GrallocImages.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/RefPtr.h" - -#define BI_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) -#define BI_LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define BI_LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define BI_LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define BI_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) - -using namespace mozilla; -using namespace mozilla::layers; - -namespace android { - -GonkNativeWindow::GonkNativeWindow(int bufferCount) : - GonkConsumerBase(new GonkBufferQueue(true) ), - mNewFrameCallback(nullptr) -{ - mBufferQueue->setMaxAcquiredBufferCount(bufferCount); -} - -GonkNativeWindow::~GonkNativeWindow() { -} - -void GonkNativeWindow::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mBufferQueue->setConsumerName(name); -} -#if ANDROID_VERSION >= 18 -status_t GonkNativeWindow::acquireBuffer(BufferItem *item, bool waitForFence) { - status_t err; - - if (!item) return BAD_VALUE; - - Mutex::Autolock _l(mMutex); - - err = acquireBufferLocked(item); - if (err != OK) { - if (err != NO_BUFFER_AVAILABLE) { - BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } - return err; - } - - if (waitForFence) { - err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); - if (err != OK) { - BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; - - return OK; -} - -status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, - const sp& releaseFence) { - status_t err; - - Mutex::Autolock _l(mMutex); - - err = addReleaseFenceLocked(item.mBuf, releaseFence); - - err = releaseBufferLocked(item.mBuf); - if (err != OK) { - BI_LOGE("Failed to release buffer: %s (%d)", - strerror(-err), err); - } - return err; -} -#endif - -status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferSize(w, h); -} - -status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mBufferQueue->setDefaultBufferFormat(defaultFormat); -} - -already_AddRefed -GonkNativeWindow::getCurrentBuffer() { - Mutex::Autolock _l(mMutex); - GonkBufferQueue::BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item); - if (err != NO_ERROR) { - return NULL; - } - - RefPtr textureClient = - mBufferQueue->getTextureClientFromBuffer(item.mGraphicBuffer.get()); - if (!textureClient) { - return NULL; - } - textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); - return textureClient.forget(); -} - -/* static */ void -GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { - GonkNativeWindow* nativeWindow = - static_cast(closure); - - MOZ_ASSERT(client && !client->IsDead()); - client->ClearRecycleCallback(); - nativeWindow->returnBuffer(client); -} - -void GonkNativeWindow::returnBuffer(TextureClient* client) { - BI_LOGD("GonkNativeWindow::returnBuffer"); - Mutex::Autolock lock(mMutex); - - int index = mBufferQueue->getSlotFromTextureClientLocked(client); - if (index < 0) { - } - - FenceHandle handle = client->GetAndResetReleaseFenceHandle(); - RefPtr fdObj = handle.GetAndResetFdObj(); - sp fence = new Fence(fdObj->GetAndResetFd()); - - addReleaseFenceLocked(index, fence); - - releaseBufferLocked(index); -} - -already_AddRefed -GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { - Mutex::Autolock lock(mMutex); - return mBufferQueue->getTextureClientFromBuffer(buffer); -} - -void GonkNativeWindow::setNewFrameCallback( - GonkNativeWindowNewFrameCallback* callback) { - BI_LOGD("setNewFrameCallback"); - Mutex::Autolock lock(mMutex); - mNewFrameCallback = callback; -} - -void GonkNativeWindow::onFrameAvailable() { - GonkConsumerBase::onFrameAvailable(); - - if (mNewFrameCallback) { - mNewFrameCallback->OnNewFrame(); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowJB.h b/widget/gonk/nativewindow/GonkNativeWindowJB.h deleted file mode 100644 index e63a7527d..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowJB.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_JB_H -#define NATIVEWINDOW_GONKNATIVEWINDOW_JB_H - -#include -#include -#include -#include - -#include "GonkConsumerBaseJB.h" -#include "GrallocImages.h" -#include "mozilla/layers/LayersSurfaces.h" - -namespace mozilla { -namespace layers { - class PGrallocBufferChild; -} -} - -namespace android { - -// The user of GonkNativeWindow who wants to receive notification of -// new frames should implement this interface. -class GonkNativeWindowNewFrameCallback { -public: - virtual void OnNewFrame() = 0; -}; - -/** - * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may - * be acquired at once, to be used concurrently by the client. This consumer can - * operate either in synchronous or asynchronous mode. - */ -class GonkNativeWindow: public GonkConsumerBase -{ - typedef mozilla::layers::TextureClient TextureClient; - public: - typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; - - typedef GonkBufferQueue::BufferItem BufferItem; - - enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; - - // Create a new buffer item consumer. The consumerUsage parameter determines - // the consumer usage flags passed to the graphics allocator. The - // bufferCount parameter specifies how many buffers can be locked for user - // access at the same time. - GonkNativeWindow(int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS); - - virtual ~GonkNativeWindow(); - - // set the name of the GonkNativeWindow that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer, filling out the - // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue - // of buffers is empty, and INVALID_OPERATION if the maximum number of - // buffers is already acquired. - // - // Only a fixed number of buffers can be acquired at a time, determined by - // the construction-time bufferCount parameter. If INVALID_OPERATION is - // returned by acquireBuffer, then old buffers must be returned to the - // queue by calling releaseBuffer before more buffers can be acquired. - // - // If waitForFence is true, and the acquired BufferItem has a valid fence object, - // acquireBuffer will wait on the fence with no timeout before returning. -#if ANDROID_VERSION >= 18 - status_t acquireBuffer(BufferItem *item, bool waitForFence = true); -#endif - // Returns an acquired buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be acquired at a time, old buffers - // must be released by calling releaseBuffer to ensure new buffers can be - // acquired by acquireBuffer. Once a BufferItem is released, the caller must - // not access any members of the BufferItem, and should immediately remove - // all of its references to the BufferItem itself. -#if ANDROID_VERSION >= 18 - status_t releaseBuffer(const BufferItem &item, - const sp& releaseFence = Fence::NO_FENCE); -#endif - - sp getProducerInterface() const { return getBufferQueue(); } - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // Get next frame from the queue, caller owns the returned buffer. - already_AddRefed getCurrentBuffer(); - - // Return the buffer to the queue and mark it as FREE. After that - // the buffer is useable again for the decoder. - void returnBuffer(TextureClient* client); - - already_AddRefed getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); - - static void RecycleCallback(TextureClient* client, void* closure); - -protected: - virtual void onFrameAvailable(); - -private: - GonkNativeWindowNewFrameCallback* mNewFrameCallback; -}; - -} // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOW_JB_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowKK.cpp b/widget/gonk/nativewindow/GonkNativeWindowKK.cpp deleted file mode 100644 index cf34d6539..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowKK.cpp +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "GonkNativeWindow" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - -#include "GonkNativeWindowKK.h" -#include "GrallocImages.h" - -using namespace mozilla; -using namespace mozilla::layers; - -namespace android { - -GonkNativeWindow::GonkNativeWindow(int bufferCount) : - GonkConsumerBase(new GonkBufferQueue(true), false), - mNewFrameCallback(nullptr) -{ - mConsumer->setMaxAcquiredBufferCount(bufferCount); -} - -GonkNativeWindow::GonkNativeWindow(const sp& bq, - uint32_t consumerUsage, int bufferCount, bool controlledByApp) : - GonkConsumerBase(bq, controlledByApp) -{ - mConsumer->setConsumerUsageBits(consumerUsage); - mConsumer->setMaxAcquiredBufferCount(bufferCount); -} - -GonkNativeWindow::~GonkNativeWindow() { -} - -void GonkNativeWindow::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GonkNativeWindow::acquireBuffer(BufferItem *item, - nsecs_t presentWhen, bool waitForFence) { - status_t err; - - if (!item) return BAD_VALUE; - - Mutex::Autolock _l(mMutex); - - err = acquireBufferLocked(item, presentWhen); - if (err != OK) { - if (err != NO_BUFFER_AVAILABLE) { - ALOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } - return err; - } - - if (waitForFence) { - err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); - if (err != OK) { - ALOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; - - return OK; -} - -status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, - const sp& releaseFence) { - status_t err; - - Mutex::Autolock _l(mMutex); - - err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - - err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer); - if (err != OK) { - ALOGE("Failed to release buffer: %s (%d)", - strerror(-err), err); - } - return err; -} - -status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -already_AddRefed -GonkNativeWindow::getCurrentBuffer() { - Mutex::Autolock _l(mMutex); - BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item, 0); //??? - if (err != NO_ERROR) { - return NULL; - } - - RefPtr textureClient = - mConsumer->getTextureClientFromBuffer(item.mGraphicBuffer.get()); - if (!textureClient) { - return NULL; - } - textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); - return textureClient.forget(); -} - -/* static */ void -GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { - GonkNativeWindow* nativeWindow = - static_cast(closure); - - MOZ_ASSERT(client && !client->IsDead()); - client->ClearRecycleCallback(); - nativeWindow->returnBuffer(client); -} - -void GonkNativeWindow::returnBuffer(TextureClient* client) { - ALOGD("GonkNativeWindow::returnBuffer"); - Mutex::Autolock lock(mMutex); - - int index = mConsumer->getSlotFromTextureClientLocked(client); - if (index < 0) { - } - - FenceHandle handle = client->GetAndResetReleaseFenceHandle(); - RefPtr fdObj = handle.GetAndResetFdObj(); - sp fence = new Fence(fdObj->GetAndResetFd()); - - addReleaseFenceLocked(index, - mSlots[index].mGraphicBuffer, - fence); - - releaseBufferLocked(index, mSlots[index].mGraphicBuffer); -} - -already_AddRefed -GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { - Mutex::Autolock lock(mMutex); - return mConsumer->getTextureClientFromBuffer(buffer); -} - -void GonkNativeWindow::setNewFrameCallback( - GonkNativeWindowNewFrameCallback* callback) { - ALOGD("setNewFrameCallback"); - Mutex::Autolock lock(mMutex); - mNewFrameCallback = callback; -} - -void GonkNativeWindow::onFrameAvailable() { - GonkConsumerBase::onFrameAvailable(); - - if (mNewFrameCallback) { - mNewFrameCallback->OnNewFrame(); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowKK.h b/widget/gonk/nativewindow/GonkNativeWindowKK.h deleted file mode 100644 index e36788b41..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowKK.h +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2013 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_KK_H -#define NATIVEWINDOW_GONKNATIVEWINDOW_KK_H - -#include -#include -#include -#include - -#include "GonkConsumerBaseKK.h" -#include "GrallocImages.h" -#include "IGonkGraphicBufferConsumer.h" -#include "mozilla/layers/ImageBridgeChild.h" -#include "mozilla/layers/LayersSurfaces.h" - -namespace mozilla { -namespace layers { - class PGrallocBufferChild; -} -} - -namespace android { - -// The user of GonkNativeWindow who wants to receive notification of -// new frames should implement this interface. -class GonkNativeWindowNewFrameCallback { -public: - virtual void OnNewFrame() = 0; -}; - -/** - * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may - * be acquired at once, to be used concurrently by the client. This consumer can - * operate either in synchronous or asynchronous mode. - */ -class GonkNativeWindow: public GonkConsumerBase -{ - typedef mozilla::layers::TextureClient TextureClient; - public: - typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; - typedef IGonkGraphicBufferConsumer::BufferItem BufferItem; - - enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; - - // Create a new buffer item consumer. The consumerUsage parameter determines - // the consumer usage flags passed to the graphics allocator. The - // bufferCount parameter specifies how many buffers can be locked for user - // access at the same time. - // controlledByApp tells whether this consumer is controlled by the - // application. - GonkNativeWindow(int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS); - GonkNativeWindow(const sp& bq, uint32_t consumerUsage, - int bufferCount = GonkBufferQueue::MIN_UNDEQUEUED_BUFFERS, - bool controlledByApp = false); - - virtual ~GonkNativeWindow(); - - // set the name of the GonkNativeWindow that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer, filling out the - // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue - // of buffers is empty, and INVALID_OPERATION if the maximum number of - // buffers is already acquired. - // - // Only a fixed number of buffers can be acquired at a time, determined by - // the construction-time bufferCount parameter. If INVALID_OPERATION is - // returned by acquireBuffer, then old buffers must be returned to the - // queue by calling releaseBuffer before more buffers can be acquired. - // - // If waitForFence is true, and the acquired BufferItem has a valid fence object, - // acquireBuffer will wait on the fence with no timeout before returning. - status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, - bool waitForFence = true); - - // Returns an acquired buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be acquired at a time, old buffers - // must be released by calling releaseBuffer to ensure new buffers can be - // acquired by acquireBuffer. Once a BufferItem is released, the caller must - // not access any members of the BufferItem, and should immediately remove - // all of its references to the BufferItem itself. - status_t releaseBuffer(const BufferItem &item, - const sp& releaseFence = Fence::NO_FENCE); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // Get next frame from the queue, caller owns the returned buffer. - already_AddRefed getCurrentBuffer(); - - // Return the buffer to the queue and mark it as FREE. After that - // the buffer is useable again for the decoder. - void returnBuffer(TextureClient* client); - - already_AddRefed getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); - - static void RecycleCallback(TextureClient* client, void* closure); - -protected: - virtual void onFrameAvailable(); - -private: - GonkNativeWindowNewFrameCallback* mNewFrameCallback; -}; - -} // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOW_JB_H diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp b/widget/gonk/nativewindow/GonkNativeWindowLL.cpp deleted file mode 100644 index 48644a22f..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowLL.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "GonkNativeWindow" -#define ATRACE_TAG ATRACE_TAG_GRAPHICS -#include - -#include "GonkNativeWindowLL.h" - -using namespace mozilla; -using namespace mozilla::layers; - -namespace android { - -GonkNativeWindow::GonkNativeWindow( - const sp& consumer, int bufferCount) : - GonkConsumerBase(consumer, false), - mNewFrameCallback(nullptr) -{ - if (bufferCount != DEFAULT_MAX_BUFFERS) { - status_t err = mConsumer->setMaxAcquiredBufferCount(bufferCount); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set max acquired buffer count to %d", bufferCount); - } -} - -GonkNativeWindow::GonkNativeWindow( - const sp& consumer, uint32_t consumerUsage, - int bufferCount, bool controlledByApp) : - GonkConsumerBase(consumer, controlledByApp) -{ - status_t err = mConsumer->setConsumerUsageBits(consumerUsage); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set consumer usage bits to %#x", consumerUsage); - if (bufferCount != DEFAULT_MAX_BUFFERS) { - err = mConsumer->setMaxAcquiredBufferCount(bufferCount); - LOG_ALWAYS_FATAL_IF(err != OK, - "Failed to set max acquired buffer count to %d", bufferCount); - } -} - -GonkNativeWindow::~GonkNativeWindow() { -} - -void GonkNativeWindow::setName(const String8& name) { - Mutex::Autolock _l(mMutex); - mName = name; - mConsumer->setConsumerName(name); -} - -status_t GonkNativeWindow::acquireBuffer(BufferItem *item, - nsecs_t presentWhen, bool waitForFence) { - status_t err; - - if (!item) return BAD_VALUE; - - Mutex::Autolock _l(mMutex); - - err = acquireBufferLocked(item, presentWhen); - if (err != OK) { - if (err != NO_BUFFER_AVAILABLE) { - ALOGE("Error acquiring buffer: %s (%d)", strerror(err), err); - } - return err; - } - - if (waitForFence) { - err = item->mFence->waitForever("GonkNativeWindow::acquireBuffer"); - if (err != OK) { - ALOGE("Failed to wait for fence of acquired buffer: %s (%d)", - strerror(-err), err); - return err; - } - } - - item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer; - - return OK; -} - -status_t GonkNativeWindow::releaseBuffer(const BufferItem &item, - const sp& releaseFence) { - status_t err; - - Mutex::Autolock _l(mMutex); - - err = addReleaseFenceLocked(item.mBuf, item.mGraphicBuffer, releaseFence); - - err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer); - if (err != OK) { - ALOGE("Failed to release buffer: %s (%d)", - strerror(-err), err); - } - return err; -} - -status_t GonkNativeWindow::setDefaultBufferSize(uint32_t w, uint32_t h) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferSize(w, h); -} - -status_t GonkNativeWindow::setDefaultBufferFormat(uint32_t defaultFormat) { - Mutex::Autolock _l(mMutex); - return mConsumer->setDefaultBufferFormat(defaultFormat); -} - -already_AddRefed -GonkNativeWindow::getCurrentBuffer() { - Mutex::Autolock _l(mMutex); - BufferItem item; - - // In asynchronous mode the list is guaranteed to be one buffer - // deep, while in synchronous mode we use the oldest buffer. - status_t err = acquireBufferLocked(&item, 0); //??? - if (err != NO_ERROR) { - return NULL; - } - - RefPtr textureClient = - mConsumer->getTextureClientFromBuffer(item.mGraphicBuffer.get()); - if (!textureClient) { - return NULL; - } - textureClient->SetRecycleCallback(GonkNativeWindow::RecycleCallback, this); - return textureClient.forget(); -} - -/* static */ void -GonkNativeWindow::RecycleCallback(TextureClient* client, void* closure) { - GonkNativeWindow* nativeWindow = - static_cast(closure); - - MOZ_ASSERT(client && !client->IsDead()); - client->ClearRecycleCallback(); - nativeWindow->returnBuffer(client); -} - -void GonkNativeWindow::returnBuffer(TextureClient* client) { - ALOGD("GonkNativeWindow::returnBuffer"); - Mutex::Autolock lock(mMutex); - - int index = mConsumer->getSlotFromTextureClientLocked(client); - if (index < 0) { - return; - } - - FenceHandle handle = client->GetAndResetReleaseFenceHandle(); - RefPtr fdObj = handle.GetAndResetFdObj(); - sp fence = new Fence(fdObj->GetAndResetFd()); - - status_t err; - err = addReleaseFenceLocked(index, - mSlots[index].mGraphicBuffer, - fence); - - err = releaseBufferLocked(index, mSlots[index].mGraphicBuffer); - - if (err != OK) { - ALOGE("Failed to return buffer: %s (%d)", strerror(-err), err); - } -} - -already_AddRefed -GonkNativeWindow::getTextureClientFromBuffer(ANativeWindowBuffer* buffer) { - Mutex::Autolock lock(mMutex); - return mConsumer->getTextureClientFromBuffer(buffer); -} - -void GonkNativeWindow::setNewFrameCallback( - GonkNativeWindowNewFrameCallback* callback) { - ALOGD("setNewFrameCallback"); - Mutex::Autolock lock(mMutex); - mNewFrameCallback = callback; -} - -#if ANDROID_VERSION == 21 -void GonkNativeWindow::onFrameAvailable() { - GonkConsumerBase::onFrameAvailable(); -#else -void GonkNativeWindow::onFrameAvailable(const ::android::BufferItem &item) { - GonkConsumerBase::onFrameAvailable(item); -#endif - - if (mNewFrameCallback) { - mNewFrameCallback->OnNewFrame(); - } -} - -} // namespace android diff --git a/widget/gonk/nativewindow/GonkNativeWindowLL.h b/widget/gonk/nativewindow/GonkNativeWindowLL.h deleted file mode 100644 index 64cd6482d..000000000 --- a/widget/gonk/nativewindow/GonkNativeWindowLL.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2012 The Android Open Source Project - * Copyright (C) 2014 Mozilla Foundation - * - * 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. - */ - -#ifndef NATIVEWINDOW_GONKNATIVEWINDOW_LL_H -#define NATIVEWINDOW_GONKNATIVEWINDOW_LL_H - -#include - -#include -#include -#include - -#include "GonkConsumerBaseLL.h" -#include "IGonkGraphicBufferConsumerLL.h" - -namespace android { - -// The user of GonkNativeWindow who wants to receive notification of -// new frames should implement this interface. -class GonkNativeWindowNewFrameCallback { -public: - virtual void OnNewFrame() = 0; -}; - -/** - * GonkNativeWindow is a GonkBufferQueue consumer endpoint that allows clients - * access to the whole BufferItem entry from GonkBufferQueue. Multiple buffers may - * be acquired at once, to be used concurrently by the client. This consumer can - * operate either in synchronous or asynchronous mode. - */ -class GonkNativeWindow: public GonkConsumerBase -{ - typedef mozilla::layers::TextureClient TextureClient; - public: - typedef GonkConsumerBase::FrameAvailableListener FrameAvailableListener; - typedef GonkBufferQueue::BufferItem BufferItem; - - enum { DEFAULT_MAX_BUFFERS = -1 }; - enum { INVALID_BUFFER_SLOT = GonkBufferQueue::INVALID_BUFFER_SLOT }; - enum { NO_BUFFER_AVAILABLE = GonkBufferQueue::NO_BUFFER_AVAILABLE }; - - // Create a new buffer item consumer. The consumerUsage parameter determines - // the consumer usage flags passed to the graphics allocator. The - // bufferCount parameter specifies how many buffers can be locked for user - // access at the same time. - // controlledByApp tells whether this consumer is controlled by the - // application. - GonkNativeWindow(const sp& consumer, - int bufferCount = DEFAULT_MAX_BUFFERS); - GonkNativeWindow(const sp& consumer, - uint32_t consumerUsage, int bufferCount = DEFAULT_MAX_BUFFERS, - bool controlledByApp = false); - - virtual ~GonkNativeWindow(); - - // set the name of the GonkNativeWindow that will be used to identify it in - // log messages. - void setName(const String8& name); - - // Gets the next graphics buffer from the producer, filling out the - // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue - // of buffers is empty, and INVALID_OPERATION if the maximum number of - // buffers is already acquired. - // - // Only a fixed number of buffers can be acquired at a time, determined by - // the construction-time bufferCount parameter. If INVALID_OPERATION is - // returned by acquireBuffer, then old buffers must be returned to the - // queue by calling releaseBuffer before more buffers can be acquired. - // - // If waitForFence is true, and the acquired BufferItem has a valid fence object, - // acquireBuffer will wait on the fence with no timeout before returning. - status_t acquireBuffer(BufferItem *item, nsecs_t presentWhen, - bool waitForFence = true); - - // Returns an acquired buffer to the queue, allowing it to be reused. Since - // only a fixed number of buffers may be acquired at a time, old buffers - // must be released by calling releaseBuffer to ensure new buffers can be - // acquired by acquireBuffer. Once a BufferItem is released, the caller must - // not access any members of the BufferItem, and should immediately remove - // all of its references to the BufferItem itself. - status_t releaseBuffer(const BufferItem &item, - const sp& releaseFence = Fence::NO_FENCE); - - // setDefaultBufferSize is used to set the size of buffers returned by - // requestBuffers when a with and height of zero is requested. - status_t setDefaultBufferSize(uint32_t w, uint32_t h); - - // setDefaultBufferFormat allows the GonkBufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer - status_t setDefaultBufferFormat(uint32_t defaultFormat); - - // Get next frame from the queue, caller owns the returned buffer. - already_AddRefed getCurrentBuffer(); - - // Return the buffer to the queue and mark it as FREE. After that - // the buffer is useable again for the decoder. - void returnBuffer(TextureClient* client); - - already_AddRefed getTextureClientFromBuffer(ANativeWindowBuffer* buffer); - - void setNewFrameCallback(GonkNativeWindowNewFrameCallback* callback); - - static void RecycleCallback(TextureClient* client, void* closure); - -protected: -#if ANDROID_VERSION == 21 - virtual void onFrameAvailable(); -#else - virtual void onFrameAvailable(const ::android::BufferItem &item); -#endif - -private: - GonkNativeWindowNewFrameCallback* mNewFrameCallback; -}; - -} // namespace android - -#endif // NATIVEWINDOW_GONKNATIVEWINDOW_LL_H diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h deleted file mode 100644 index 14541c9b4..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumer.h +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright 2013 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 -# include "IGonkGraphicBufferConsumerLL.h" -#elif defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 19 -# include "IGonkGraphicBufferConsumerKK.h" -#endif diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp deleted file mode 100644 index c4c9f6578..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.cpp +++ /dev/null @@ -1,480 +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. - */ - -#define EGL_EGLEXT_PROTOTYPES - -#include -#include - -#include - -#include -#include - -#include -#include "IGonkGraphicBufferConsumerKK.h" - -#include -#include - -#include - -namespace android { -// --------------------------------------------------------------------------- - -IGonkGraphicBufferConsumer::BufferItem::BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mBuf) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -status_t IGonkGraphicBufferConsumer::BufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (count < BufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - FlattenableUtils::write(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mBuf); - FlattenableUtils::write(buffer, size, mIsDroppable); - FlattenableUtils::write(buffer, size, mAcquireCalled); - FlattenableUtils::write(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t IGonkGraphicBufferConsumer::BufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - FlattenableUtils::read(buffer, size, mIsAutoTimestamp); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mBuf); - FlattenableUtils::read(buffer, size, mIsDroppable); - FlattenableUtils::read(buffer, size, mAcquireCalled); - FlattenableUtils::read(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -enum { - ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - RELEASE_BUFFER, - CONSUMER_CONNECT, - CONSUMER_DISCONNECT, - GET_RELEASED_BUFFERS, - SET_DEFAULT_BUFFER_SIZE, - SET_DEFAULT_MAX_BUFFER_COUNT, - DISABLE_ASYNC_BUFFER, - SET_MAX_ACQUIRED_BUFFER_COUNT, - SET_CONSUMER_NAME, - SET_DEFAULT_BUFFER_FORMAT, - SET_CONSUMER_USAGE_BITS, - SET_TRANSFORM_HINT, - DUMP, -}; - -class BpGonkGraphicBufferConsumer : public BpInterface -{ -public: - BpGonkGraphicBufferConsumer(const sp& impl) - : BpInterface(impl) - { - } - - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt64(presentWhen); - status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.read(*buffer); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, - const sp& releaseFence) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(buf); - data.writeInt64(frameNumber); - data.write(*releaseFence); - status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeStrongBinder(consumer->asBinder()); - data.writeInt32(controlledByApp); - status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerDisconnect() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t getReleasedBuffers(uint32_t* slotMask) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); - if (result != NO_ERROR) { - return result; - } - *slotMask = reply.readInt32(); - return reply.readInt32(); - } - - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setDefaultMaxBufferCount(int bufferCount) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(bufferCount); - status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t disableAsyncBuffer() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(maxAcquiredBuffers); - status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual void setConsumerName(const String8& name) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(name); - remote()->transact(SET_CONSUMER_NAME, data, &reply); - } - - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(defaultFormat); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setConsumerUsageBits(uint32_t usage) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(usage); - status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setTransformHint(uint32_t hint) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(hint); - status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual void dumpToString(String8& result, const char* prefix) const { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(result); - data.writeString8(String8(prefix ? prefix : "")); - remote()->transact(DUMP, data, &reply); - reply.readString8(); - } -}; - -IMPLEMENT_META_INTERFACE(GonkGraphicBufferConsumer, "android.gui.IGonkGraphicBufferConsumer"); -// ---------------------------------------------------------------------- - -status_t BnGonkGraphicBufferConsumer::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case ACQUIRE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - BufferItem item; - int64_t presentWhen = data.readInt64(); - status_t result = acquireBuffer(&item, presentWhen); - status_t err = reply->write(item); - if (err) return err; - reply->writeInt32(result); - return NO_ERROR; - } break; - case RELEASE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - int buf = data.readInt32(); - uint64_t frameNumber = data.readInt64(); - sp releaseFence = new Fence(); - status_t err = data.read(*releaseFence); - if (err) return err; - status_t result = releaseBuffer(buf, frameNumber, releaseFence); - reply->writeInt32(result); - return NO_ERROR; - } break; - - case CONSUMER_CONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - sp consumer = IConsumerListener::asInterface( data.readStrongBinder() ); - bool controlledByApp = data.readInt32(); - status_t result = consumerConnect(consumer, controlledByApp); - reply->writeInt32(result); - return NO_ERROR; - } break; - - case CONSUMER_DISCONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = consumerDisconnect(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case GET_RELEASED_BUFFERS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t slotMask; - status_t result = getReleasedBuffers(&slotMask); - reply->writeInt32(slotMask); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_SIZE: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - status_t result = setDefaultBufferSize(w, h); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_MAX_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t bufferCount = data.readInt32(); - status_t result = setDefaultMaxBufferCount(bufferCount); - reply->writeInt32(result); - return NO_ERROR; - } break; - case DISABLE_ASYNC_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = disableAsyncBuffer(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t maxAcquiredBuffers = data.readInt32(); - status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_NAME: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - setConsumerName( data.readString8() ); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_FORMAT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t defaultFormat = data.readInt32(); - status_t result = setDefaultBufferFormat(defaultFormat); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_USAGE_BITS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t usage = data.readInt32(); - status_t result = setConsumerUsageBits(usage); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_TRANSFORM_HINT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t hint = data.readInt32(); - status_t result = setTransformHint(hint); - reply->writeInt32(result); - return NO_ERROR; - } break; - - case DUMP: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - String8 result = data.readString8(); - String8 prefix = data.readString8(); - static_cast(this)->dumpToString(result, prefix); - reply->writeString8(result); - return NO_ERROR; - } - } - return BBinder::onTransact(code, data, reply, flags); -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h deleted file mode 100644 index ce51e1ef2..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerKK.h +++ /dev/null @@ -1,228 +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. - */ - -#ifndef NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_KK_H -#define NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_KK_H - -#include -#include - -#include -#include -#include - -#include -#include - -#include "mozilla/Types.h" -#include "mozilla/layers/LayersSurfaces.h" - -namespace mozilla { - -namespace layers { -class TextureClient; -} -} - -namespace android { -// ---------------------------------------------------------------------------- - -class MOZ_EXPORT IConsumerListener; -class MOZ_EXPORT GraphicBuffer; -class MOZ_EXPORT Fence; - -class IGonkGraphicBufferConsumer : public IInterface { - typedef mozilla::layers::TextureClient TextureClient; -public: - - // public facing structure for BufferSlot - class BufferItem : public Flattenable { - friend class Flattenable; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - enum { INVALID_BUFFER_SLOT = -1 }; - BufferItem(); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer - int mBuf; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; - }; - - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the BufferQueue. If no buffer is pending then it returns -EINVAL. If a - // buffer is successfully acquired, the information about the buffer is - // returned in BufferItem. If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - // - // If presentWhen is nonzero, it indicates the time when the buffer will - // be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) = 0; - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp& releaseFence) = 0; - - // consumerConnect connects a consumer to the BufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // BufferQueue is placed into the "abandoned" state, causing most - // interactions with the BufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumer may not be NULL. - virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) = 0; - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed and the BufferQueue is placed in the "abandoned" - // state, causing most interactions with the BufferQueue by the producer to - // fail. - virtual status_t consumerDisconnect() = 0; - - // getReleasedBuffers sets the value pointed to by slotMask to a bit mask - // indicating which buffer slots have been released by the BufferQueue - // but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - virtual status_t getReleasedBuffers(uint32_t* slotMask) = 0; - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - virtual status_t disableAsyncBuffer() = 0; - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the BufferQueue. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name) = 0; - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - virtual status_t setConsumerUsageBits(uint32_t usage) = 0; - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - virtual status_t setTransformHint(uint32_t hint) = 0; - - // dump state into a string - virtual void dumpToString(String8& result, const char* prefix) const = 0; - -public: - DECLARE_META_INTERFACE(GonkGraphicBufferConsumer); -}; - -// ---------------------------------------------------------------------------- - -class BnGonkGraphicBufferConsumer : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_IGRAPHICBUFFERCONSUMER_H diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp deleted file mode 100644 index 729ed6736..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.cpp +++ /dev/null @@ -1,565 +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. - */ - -#include -#include - -#include -#include - -#include -#include - -#include -#include "IGonkGraphicBufferConsumerLL.h" - -#include -#include - -#include - -#include "mozilla/layers/TextureClient.h" - -namespace android { -// --------------------------------------------------------------------------- - -IGonkGraphicBufferConsumer::BufferItem::BufferItem() : - mTransform(0), - mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE), - mTimestamp(0), - mIsAutoTimestamp(false), - mFrameNumber(0), - mBuf(INVALID_BUFFER_SLOT), - mIsDroppable(false), - mAcquireCalled(false), - mTransformToDisplayInverse(false) { - mCrop.makeInvalid(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getPodSize() const { - size_t c = sizeof(mCrop) + - sizeof(mTransform) + - sizeof(mScalingMode) + - sizeof(mTimestamp) + - sizeof(mIsAutoTimestamp) + - sizeof(mFrameNumber) + - sizeof(mBuf) + - sizeof(mIsDroppable) + - sizeof(mAcquireCalled) + - sizeof(mTransformToDisplayInverse); - return c; -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFlattenedSize() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - if (mFence != 0) { - c += mFence->getFlattenedSize(); - c = FlattenableUtils::align<4>(c); - } - return sizeof(int32_t) + c + getPodSize(); -} - -size_t IGonkGraphicBufferConsumer::BufferItem::getFdCount() const { - size_t c = 0; - if (mGraphicBuffer != 0) { - c += mGraphicBuffer->getFdCount(); - } - if (mFence != 0) { - c += mFence->getFdCount(); - } - return c; -} - -static void writeBoolAsInt(void*& buffer, size_t& size, bool b) { - FlattenableUtils::write(buffer, size, static_cast(b)); -} - -static bool readBoolFromInt(void const*& buffer, size_t& size) { - int32_t i; - FlattenableUtils::read(buffer, size, i); - return static_cast(i); -} - -status_t IGonkGraphicBufferConsumer::BufferItem::flatten( - void*& buffer, size_t& size, int*& fds, size_t& count) const { - - // make sure we have enough space - if (size < BufferItem::getFlattenedSize()) { - return NO_MEMORY; - } - - // content flags are stored first - uint32_t& flags = *static_cast(buffer); - - // advance the pointer - FlattenableUtils::advance(buffer, size, sizeof(uint32_t)); - - flags = 0; - if (mGraphicBuffer != 0) { - status_t err = mGraphicBuffer->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 1; - } - if (mFence != 0) { - status_t err = mFence->flatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - flags |= 2; - } - - // check we have enough space (in case flattening the fence/graphicbuffer lied to us) - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::write(buffer, size, mCrop); - FlattenableUtils::write(buffer, size, mTransform); - FlattenableUtils::write(buffer, size, mScalingMode); - FlattenableUtils::write(buffer, size, mTimestamp); - writeBoolAsInt(buffer, size, mIsAutoTimestamp); - FlattenableUtils::write(buffer, size, mFrameNumber); - FlattenableUtils::write(buffer, size, mBuf); - writeBoolAsInt(buffer, size, mIsDroppable); - writeBoolAsInt(buffer, size, mAcquireCalled); - writeBoolAsInt(buffer, size, mTransformToDisplayInverse); - - return NO_ERROR; -} - -status_t IGonkGraphicBufferConsumer::BufferItem::unflatten( - void const*& buffer, size_t& size, int const*& fds, size_t& count) { - - if (size < sizeof(uint32_t)) - return NO_MEMORY; - - uint32_t flags = 0; - FlattenableUtils::read(buffer, size, flags); - - if (flags & 1) { - mGraphicBuffer = new GraphicBuffer(); - status_t err = mGraphicBuffer->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - if (flags & 2) { - mFence = new Fence(); - status_t err = mFence->unflatten(buffer, size, fds, count); - if (err) return err; - size -= FlattenableUtils::align<4>(buffer); - } - - // check we have enough space - if (size < getPodSize()) { - return NO_MEMORY; - } - - FlattenableUtils::read(buffer, size, mCrop); - FlattenableUtils::read(buffer, size, mTransform); - FlattenableUtils::read(buffer, size, mScalingMode); - FlattenableUtils::read(buffer, size, mTimestamp); - mIsAutoTimestamp = readBoolFromInt(buffer, size); - FlattenableUtils::read(buffer, size, mFrameNumber); - FlattenableUtils::read(buffer, size, mBuf); - mIsDroppable = readBoolFromInt(buffer, size); - mAcquireCalled = readBoolFromInt(buffer, size); - mTransformToDisplayInverse = readBoolFromInt(buffer, size); - - return NO_ERROR; -} - -// --------------------------------------------------------------------------- - -enum { - ACQUIRE_BUFFER = IBinder::FIRST_CALL_TRANSACTION, - DETACH_BUFFER, - ATTACH_BUFFER, - RELEASE_BUFFER, - CONSUMER_CONNECT, - CONSUMER_DISCONNECT, - GET_RELEASED_BUFFERS, - SET_DEFAULT_BUFFER_SIZE, - SET_DEFAULT_MAX_BUFFER_COUNT, - DISABLE_ASYNC_BUFFER, - SET_MAX_ACQUIRED_BUFFER_COUNT, - SET_CONSUMER_NAME, - SET_DEFAULT_BUFFER_FORMAT, - SET_CONSUMER_USAGE_BITS, - SET_TRANSFORM_HINT, - GET_SIDEBAND_STREAM, - DUMP, -}; - - -class BpGonkGraphicBufferConsumer : public BpInterface -{ -public: - BpGonkGraphicBufferConsumer(const sp& impl) - : BpInterface(impl) - { - } - - virtual status_t acquireBuffer(BufferItem *buffer, nsecs_t presentWhen) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt64(presentWhen); - status_t result = remote()->transact(ACQUIRE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.read(*buffer); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t detachBuffer(int slot) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(slot); - status_t result = remote()->transact(DETACH_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - result = reply.readInt32(); - return result; - } - - virtual status_t attachBuffer(int* slot, const sp& buffer) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.write(*buffer.get()); - status_t result = remote()->transact(ATTACH_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - *slot = reply.readInt32(); - result = reply.readInt32(); - return result; - } - - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp& releaseFence) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(buf); - data.writeInt64(frameNumber); - data.write(*releaseFence); - status_t result = remote()->transact(RELEASE_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeStrongBinder(consumer->asBinder()); - data.writeInt32(controlledByApp); - status_t result = remote()->transact(CONSUMER_CONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t consumerDisconnect() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(CONSUMER_DISCONNECT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t getReleasedBuffers(uint64_t* slotMask) { - Parcel data, reply; - if (slotMask == NULL) { - ALOGE("getReleasedBuffers: slotMask must not be NULL"); - return BAD_VALUE; - } - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(GET_RELEASED_BUFFERS, data, &reply); - if (result != NO_ERROR) { - return result; - } - *slotMask = reply.readInt64(); - return reply.readInt32(); - } - - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(w); - data.writeInt32(h); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_SIZE, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setDefaultMaxBufferCount(int bufferCount) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(bufferCount); - status_t result = remote()->transact(SET_DEFAULT_MAX_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t disableAsyncBuffer() { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - status_t result = remote()->transact(DISABLE_ASYNC_BUFFER, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(maxAcquiredBuffers); - status_t result = remote()->transact(SET_MAX_ACQUIRED_BUFFER_COUNT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual void setConsumerName(const String8& name) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(name); - remote()->transact(SET_CONSUMER_NAME, data, &reply); - } - - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(defaultFormat); - status_t result = remote()->transact(SET_DEFAULT_BUFFER_FORMAT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setConsumerUsageBits(uint32_t usage) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(usage); - status_t result = remote()->transact(SET_CONSUMER_USAGE_BITS, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual status_t setTransformHint(uint32_t hint) { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeInt32(hint); - status_t result = remote()->transact(SET_TRANSFORM_HINT, data, &reply); - if (result != NO_ERROR) { - return result; - } - return reply.readInt32(); - } - - virtual sp getSidebandStream() const { - Parcel data, reply; - status_t err; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - if ((err = remote()->transact(GET_SIDEBAND_STREAM, data, &reply)) != NO_ERROR) { - return NULL; - } - sp stream; - if (reply.readInt32()) { - stream = NativeHandle::create(reply.readNativeHandle(), true); - } - return stream; - } - - virtual void dumpToString(String8& result, const char* prefix) const { - Parcel data, reply; - data.writeInterfaceToken(IGonkGraphicBufferConsumer::getInterfaceDescriptor()); - data.writeString8(result); - data.writeString8(String8(prefix ? prefix : "")); - remote()->transact(DUMP, data, &reply); - reply.readString8(); - } - - // Added by mozilla - virtual already_AddRefed - getTextureClientFromBuffer(ANativeWindowBuffer* buffer) - { - return nullptr; - } - - virtual int - getSlotFromTextureClientLocked(mozilla::layers::TextureClient* client) const - { - return BAD_VALUE; - } -}; - -IMPLEMENT_META_INTERFACE(GonkGraphicBufferConsumer, "android.gui.IGonkGraphicBufferConsumer"); - -// ---------------------------------------------------------------------- - -status_t BnGonkGraphicBufferConsumer::onTransact( - uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) -{ - switch(code) { - case ACQUIRE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - BufferItem item; - int64_t presentWhen = data.readInt64(); - status_t result = acquireBuffer(&item, presentWhen); - status_t err = reply->write(item); - if (err) return err; - reply->writeInt32(result); - return NO_ERROR; - } break; - case DETACH_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - int slot = data.readInt32(); - int result = detachBuffer(slot); - reply->writeInt32(result); - return NO_ERROR; - } break; - case ATTACH_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - sp buffer = new GraphicBuffer(); - data.read(*buffer.get()); - int slot; - int result = attachBuffer(&slot, buffer); - reply->writeInt32(slot); - reply->writeInt32(result); - return NO_ERROR; - } break; - case RELEASE_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - int buf = data.readInt32(); - uint64_t frameNumber = data.readInt64(); - sp releaseFence = new Fence(); - status_t err = data.read(*releaseFence); - if (err) return err; - status_t result = releaseBuffer(buf, frameNumber, releaseFence); - reply->writeInt32(result); - return NO_ERROR; - } break; - case CONSUMER_CONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - sp consumer = IConsumerListener::asInterface( data.readStrongBinder() ); - bool controlledByApp = data.readInt32(); - status_t result = consumerConnect(consumer, controlledByApp); - reply->writeInt32(result); - return NO_ERROR; - } break; - case CONSUMER_DISCONNECT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = consumerDisconnect(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case GET_RELEASED_BUFFERS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint64_t slotMask; - status_t result = getReleasedBuffers(&slotMask); - reply->writeInt64(slotMask); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_SIZE: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t w = data.readInt32(); - uint32_t h = data.readInt32(); - status_t result = setDefaultBufferSize(w, h); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_DEFAULT_MAX_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t bufferCount = data.readInt32(); - status_t result = setDefaultMaxBufferCount(bufferCount); - reply->writeInt32(result); - return NO_ERROR; - } break; - case DISABLE_ASYNC_BUFFER: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - status_t result = disableAsyncBuffer(); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_MAX_ACQUIRED_BUFFER_COUNT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t maxAcquiredBuffers = data.readInt32(); - status_t result = setMaxAcquiredBufferCount(maxAcquiredBuffers); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_NAME: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - setConsumerName( data.readString8() ); - return NO_ERROR; - } break; - case SET_DEFAULT_BUFFER_FORMAT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t defaultFormat = data.readInt32(); - status_t result = setDefaultBufferFormat(defaultFormat); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_CONSUMER_USAGE_BITS: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t usage = data.readInt32(); - status_t result = setConsumerUsageBits(usage); - reply->writeInt32(result); - return NO_ERROR; - } break; - case SET_TRANSFORM_HINT: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - uint32_t hint = data.readInt32(); - status_t result = setTransformHint(hint); - reply->writeInt32(result); - return NO_ERROR; - } break; - case DUMP: { - CHECK_INTERFACE(IGonkGraphicBufferConsumer, data, reply); - String8 result = data.readString8(); - String8 prefix = data.readString8(); - static_cast(this)->dumpToString(result, prefix); - reply->writeString8(result); - return NO_ERROR; - } - } - return BBinder::onTransact(code, data, reply, flags); -} - -}; // namespace android diff --git a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h b/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h deleted file mode 100644 index 8a93a0849..000000000 --- a/widget/gonk/nativewindow/IGonkGraphicBufferConsumerLL.h +++ /dev/null @@ -1,337 +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. - */ - -#ifndef NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_LL_H -#define NATIVEWINDOW_IGONKGRAPHICBUFFERCONSUMER_LL_H - -#include -#include - -#include -#include -#include - -#include -#include - -#include "mozilla/RefPtr.h" - -class ANativeWindowBuffer; - -namespace mozilla { -namespace layers { -class TextureClient; -} -} - -namespace android { -// ---------------------------------------------------------------------------- - -class Fence; -class GraphicBuffer; -class IConsumerListener; -class NativeHandle; - -class IGonkGraphicBufferConsumer : public IInterface { -public: - - // public facing structure for BufferSlot - class BufferItem : public Flattenable { - friend class Flattenable; - size_t getPodSize() const; - size_t getFlattenedSize() const; - size_t getFdCount() const; - status_t flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const; - status_t unflatten(void const*& buffer, size_t& size, int const*& fds, size_t& count); - - public: - // The default value of mBuf, used to indicate this doesn't correspond to a slot. - enum { INVALID_BUFFER_SLOT = -1 }; - BufferItem(); - - // mGraphicBuffer points to the buffer allocated for this slot, or is NULL - // if the buffer in this slot has been acquired in the past (see - // BufferSlot.mAcquireCalled). - sp mGraphicBuffer; - - // mFence is a fence that will signal when the buffer is idle. - sp mFence; - - // mCrop is the current crop rectangle for this buffer slot. - Rect mCrop; - - // mTransform is the current transform flags for this buffer slot. - // refer to NATIVE_WINDOW_TRANSFORM_* in - uint32_t mTransform; - - // mScalingMode is the current scaling mode for this buffer slot. - // refer to NATIVE_WINDOW_SCALING_* in - uint32_t mScalingMode; - - // mTimestamp is the current timestamp for this buffer slot. This gets - // to set by queueBuffer each time this slot is queued. This value - // is guaranteed to be monotonically increasing for each newly - // acquired buffer. - int64_t mTimestamp; - - // mIsAutoTimestamp indicates whether mTimestamp was generated - // automatically when the buffer was queued. - bool mIsAutoTimestamp; - - // mFrameNumber is the number of the queued frame for this slot. - uint64_t mFrameNumber; - - // mBuf is the slot index of this buffer (default INVALID_BUFFER_SLOT). - int mBuf; - - // mIsDroppable whether this buffer was queued with the - // property that it can be replaced by a new buffer for the purpose of - // making sure dequeueBuffer() won't block. - // i.e.: was the BufferQueue in "mDequeueBufferCannotBlock" when this buffer - // was queued. - bool mIsDroppable; - - // Indicates whether this buffer has been seen by a consumer yet - bool mAcquireCalled; - - // Indicates this buffer must be transformed by the inverse transform of the screen - // it is displayed onto. This is applied after mTransform. - bool mTransformToDisplayInverse; - }; - - enum { - // Returned by releaseBuffer, after which the consumer must - // free any references to the just-released buffer that it might have. - STALE_BUFFER_SLOT = 1, - // Returned by dequeueBuffer if there are no pending buffers available. - NO_BUFFER_AVAILABLE, - // Returned by dequeueBuffer if it's too early for the buffer to be acquired. - PRESENT_LATER, - }; - - // acquireBuffer attempts to acquire ownership of the next pending buffer in - // the BufferQueue. If no buffer is pending then it returns - // NO_BUFFER_AVAILABLE. If a buffer is successfully acquired, the - // information about the buffer is returned in BufferItem. - // - // If the buffer returned had previously been - // acquired then the BufferItem::mGraphicBuffer field of buffer is set to - // NULL and it is assumed that the consumer still holds a reference to the - // buffer. - // - // If presentWhen is non-zero, it indicates the time when the buffer will - // be displayed on screen. If the buffer's timestamp is farther in the - // future, the buffer won't be acquired, and PRESENT_LATER will be - // returned. The presentation time is in nanoseconds, and the time base - // is CLOCK_MONOTONIC. - // - // Return of NO_ERROR means the operation completed as normal. - // - // Return of a positive value means the operation could not be completed - // at this time, but the user should try again later: - // * NO_BUFFER_AVAILABLE - no buffer is pending (nothing queued by producer) - // * PRESENT_LATER - the buffer's timestamp is farther in the future - // - // Return of a negative value means an error has occurred: - // * INVALID_OPERATION - too many buffers have been acquired - virtual status_t acquireBuffer(BufferItem* buffer, nsecs_t presentWhen) = 0; - - // detachBuffer attempts to remove all ownership of the buffer in the given - // slot from the buffer queue. If this call succeeds, the slot will be - // freed, and there will be no way to obtain the buffer from this interface. - // The freed slot will remain unallocated until either it is selected to - // hold a freshly allocated buffer in dequeueBuffer or a buffer is attached - // to the slot. The buffer must have already been acquired. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - the given slot number is invalid, either because it is - // out of the range [0, NUM_BUFFER_SLOTS) or because the slot - // it refers to is not currently acquired. - virtual status_t detachBuffer(int slot) = 0; - - // attachBuffer attempts to transfer ownership of a buffer to the buffer - // queue. If this call succeeds, it will be as if this buffer was acquired - // from the returned slot number. As such, this call will fail if attaching - // this buffer would cause too many buffers to be simultaneously acquired. - // - // If the buffer is successfully attached, its frameNumber is initialized - // to 0. This must be passed into the releaseBuffer call or else the buffer - // will be deallocated as stale. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - outSlot or buffer were NULL - // * INVALID_OPERATION - cannot attach the buffer because it would cause too - // many buffers to be acquired. - // * NO_MEMORY - no free slots available - virtual status_t attachBuffer(int *outSlot, - const sp& buffer) = 0; - - // releaseBuffer releases a buffer slot from the consumer back to the - // BufferQueue. This may be done while the buffer's contents are still - // being accessed. The fence will signal when the buffer is no longer - // in use. frameNumber is used to indentify the exact buffer returned. - // - // If releaseBuffer returns STALE_BUFFER_SLOT, then the consumer must free - // any references to the just-released buffer that it might have, as if it - // had received a onBuffersReleased() call with a mask set for the released - // buffer. - // - // Note that the dependencies on EGL will be removed once we switch to using - // the Android HW Sync HAL. - // - // Return of NO_ERROR means the operation completed as normal. - // - // Return of a positive value means the operation could not be completed - // at this time, but the user should try again later: - // * STALE_BUFFER_SLOT - see above (second paragraph) - // - // Return of a negative value means an error has occurred: - // * BAD_VALUE - one of the following could've happened: - // * the buffer slot was invalid - // * the fence was NULL - // * the buffer slot specified is not in the acquired state - virtual status_t releaseBuffer(int buf, uint64_t frameNumber, const sp& releaseFence) = 0; - - // consumerConnect connects a consumer to the BufferQueue. Only one - // consumer may be connected, and when that consumer disconnects the - // BufferQueue is placed into the "abandoned" state, causing most - // interactions with the BufferQueue by the producer to fail. - // controlledByApp indicates whether the consumer is controlled by - // the application. - // - // consumer may not be NULL. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned - // * BAD_VALUE - a NULL consumer was provided - virtual status_t consumerConnect(const sp& consumer, bool controlledByApp) = 0; - - // consumerDisconnect disconnects a consumer from the BufferQueue. All - // buffers will be freed and the BufferQueue is placed in the "abandoned" - // state, causing most interactions with the BufferQueue by the producer to - // fail. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - no consumer is currently connected - virtual status_t consumerDisconnect() = 0; - - // getReleasedBuffers sets the value pointed to by slotMask to a bit set. - // Each bit index with a 1 corresponds to a released buffer slot with that - // index value. In particular, a released buffer is one that has - // been released by the BufferQueue but have not yet been released by the consumer. - // - // This should be called from the onBuffersReleased() callback. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * NO_INIT - the buffer queue has been abandoned. - virtual status_t getReleasedBuffers(uint64_t* slotMask) = 0; - - // setDefaultBufferSize is used to set the size of buffers returned by - // dequeueBuffer when a width and height of zero is requested. Default - // is 1x1. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - either w or h was zero - virtual status_t setDefaultBufferSize(uint32_t w, uint32_t h) = 0; - - // setDefaultMaxBufferCount sets the default value for the maximum buffer - // count (the initial default is 2). If the producer has requested a - // buffer count using setBufferCount, the default buffer count will only - // take effect if the producer sets the count back to zero. - // - // The count must be between 2 and NUM_BUFFER_SLOTS, inclusive. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - bufferCount was out of range (see above). - virtual status_t setDefaultMaxBufferCount(int bufferCount) = 0; - - // disableAsyncBuffer disables the extra buffer used in async mode - // (when both producer and consumer have set their "isControlledByApp" - // flag) and has dequeueBuffer() return WOULD_BLOCK instead. - // - // This can only be called before consumerConnect(). - // - // Return of a value other than NO_ERROR means an error has occurred: - // * INVALID_OPERATION - attempting to call this after consumerConnect. - virtual status_t disableAsyncBuffer() = 0; - - // setMaxAcquiredBufferCount sets the maximum number of buffers that can - // be acquired by the consumer at one time (default 1). This call will - // fail if a producer is connected to the BufferQueue. - // - // maxAcquiredBuffers must be (inclusive) between 1 and MAX_MAX_ACQUIRED_BUFFERS. - // - // Return of a value other than NO_ERROR means an error has occurred: - // * BAD_VALUE - maxAcquiredBuffers was out of range (see above). - // * INVALID_OPERATION - attempting to call this after a producer connected. - virtual status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers) = 0; - - // setConsumerName sets the name used in logging - virtual void setConsumerName(const String8& name) = 0; - - // setDefaultBufferFormat allows the BufferQueue to create - // GraphicBuffers of a defaultFormat if no format is specified - // in dequeueBuffer. Formats are enumerated in graphics.h; the - // initial default is HAL_PIXEL_FORMAT_RGBA_8888. - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setDefaultBufferFormat(uint32_t defaultFormat) = 0; - - // setConsumerUsageBits will turn on additional usage bits for dequeueBuffer. - // These are merged with the bits passed to dequeueBuffer. The values are - // enumerated in gralloc.h, e.g. GRALLOC_USAGE_HW_RENDER; the default is 0. - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setConsumerUsageBits(uint32_t usage) = 0; - - // setTransformHint bakes in rotation to buffers so overlays can be used. - // The values are enumerated in window.h, e.g. - // NATIVE_WINDOW_TRANSFORM_ROT_90. The default is 0 (no transform). - // - // Return of a value other than NO_ERROR means an unknown error has occurred. - virtual status_t setTransformHint(uint32_t hint) = 0; - - // Retrieve the sideband buffer stream, if any. - virtual sp getSidebandStream() const = 0; - - // dump state into a string - virtual void dumpToString(String8& result, const char* prefix) const = 0; - - // Added by mozilla - virtual already_AddRefed - getTextureClientFromBuffer(ANativeWindowBuffer* buffer) = 0; - - virtual int getSlotFromTextureClientLocked(mozilla::layers::TextureClient* client) const = 0; - -public: - DECLARE_META_INTERFACE(GonkGraphicBufferConsumer); -}; - -// ---------------------------------------------------------------------------- - -class BnGonkGraphicBufferConsumer : public BnInterface -{ -public: - virtual status_t onTransact( uint32_t code, - const Parcel& data, - Parcel* reply, - uint32_t flags = 0); -}; - -// ---------------------------------------------------------------------------- -}; // namespace android - -#endif // ANDROID_GUI_IGONKGRAPHICBUFFERCONSUMER_H diff --git a/widget/gonk/nativewindow/moz.build b/widget/gonk/nativewindow/moz.build deleted file mode 100644 index fbcee601c..000000000 --- a/widget/gonk/nativewindow/moz.build +++ /dev/null @@ -1,104 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# Copyright 2013 Mozilla Foundation and Mozilla contributors -# -# 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. - -EXPORTS += [ - 'GonkBufferQueue.h', - 'GonkNativeWindow.h', -] - -if CONFIG['ANDROID_VERSION'] >= '19': - EXPORTS += [ - 'IGonkGraphicBufferConsumer.h', - ] - -if CONFIG['ANDROID_VERSION'] >= '21': - EXPORTS += [ - 'GonkBufferQueueLL/GonkBufferQueueDefs.h', - 'GonkBufferQueueLL/GonkBufferQueueLL.h', - 'GonkBufferQueueLL/GonkBufferQueueProducer.h', - 'GonkBufferQueueLL/GonkBufferSlot.h', - 'GonkConsumerBaseLL.h', - 'GonkNativeWindowLL.h', - 'IGonkGraphicBufferConsumerLL.h', - ] -elif CONFIG['ANDROID_VERSION'] >= '19': - EXPORTS += [ - 'GonkBufferQueueKK.h', - 'GonkConsumerBaseKK.h', - 'GonkNativeWindowKK.h', - 'IGonkGraphicBufferConsumerKK.h', - ] -elif CONFIG['ANDROID_VERSION'] in ('17', '18'): - EXPORTS += [ - 'GonkBufferQueueJB.h', - 'GonkConsumerBaseJB.h', - 'GonkNativeWindowJB.h', - ] - -if CONFIG['MOZ_WEBRTC']: - if CONFIG['ANDROID_VERSION'] >= '21': - SOURCES += [ - 'GonkBufferQueueLL/GonkBufferItem.cpp', - 'GonkBufferQueueLL/GonkBufferQueueConsumer.cpp', - 'GonkBufferQueueLL/GonkBufferQueueCore.cpp', - 'GonkBufferQueueLL/GonkBufferQueueLL.cpp', - 'GonkBufferQueueLL/GonkBufferQueueProducer.cpp', - 'GonkBufferQueueLL/GonkBufferSlot.cpp', - 'GonkConsumerBaseLL.cpp', - 'GonkNativeWindowLL.cpp', - 'IGonkGraphicBufferConsumerLL.cpp', - ] - elif CONFIG['ANDROID_VERSION'] >= '19': - SOURCES += [ - 'GonkBufferQueueKK.cpp', - 'GonkConsumerBaseKK.cpp', - 'GonkNativeWindowKK.cpp', - 'IGonkGraphicBufferConsumerKK.cpp', - ] - elif CONFIG['ANDROID_VERSION'] in ('17', '18'): - SOURCES += [ - 'GonkBufferQueueJB.cpp', - 'GonkConsumerBaseJB.cpp', - 'GonkNativeWindowJB.cpp', - ] - -if CONFIG['ANDROID_VERSION'] >= '18': - SOURCES += [ - 'FakeSurfaceComposer.cpp', - ] - -include('/ipc/chromium/chromium-config.mozbuild') - -if CONFIG['ANDROID_VERSION'] >= '18': - LOCAL_INCLUDES += [ - '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include', - ] - ] - -DEFINES['HAVE_ANDROID_OS'] = True - -# Suppress some GCC warnings being treated as errors: -# - about attributes on forward declarations for types that are already -# defined, which complains about an important MOZ_EXPORT for android::AString -if CONFIG['GNU_CC']: - CXXFLAGS += ['-Wno-error=attributes', '-Wno-overloaded-virtual'] - -FINAL_LIBRARY = 'xul' - -DISABLE_STL_WRAPPING = True - -NO_VISIBILITY_FLAGS = True diff --git a/widget/gonk/nsAppShell.cpp b/widget/gonk/nsAppShell.cpp deleted file mode 100644 index 24e791b4b..000000000 --- a/widget/gonk/nsAppShell.cpp +++ /dev/null @@ -1,1087 +0,0 @@ -/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim: set ts=4 sw=4 sts=4 tw=80 et: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "base/basictypes.h" -#include "GonkPermission.h" -#include "libdisplay/BootAnimation.h" -#include "nscore.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/FileUtils.h" -#include "mozilla/Hal.h" -#include "mozilla/MouseEvents.h" -#include "mozilla/Mutex.h" -#include "mozilla/Services.h" -#include "mozilla/TextEvents.h" -#if ANDROID_VERSION >= 18 -#include "nativewindow/FakeSurfaceComposer.h" -#endif -#include "nsAppShell.h" -#include "mozilla/DebugOnly.h" -#include "mozilla/dom/Touch.h" -#include "nsGkAtoms.h" -#include "nsIObserverService.h" -#include "nsIScreen.h" -#include "nsScreenManagerGonk.h" -#include "nsThreadUtils.h" -#include "nsWindow.h" -#include "OrientationObserver.h" -#include "GonkMemoryPressureMonitoring.h" - -#include "android/log.h" -#include "libui/EventHub.h" -#include "libui/InputReader.h" -#include "libui/InputDispatcher.h" - -#include "mozilla/Preferences.h" -#include "GeckoProfiler.h" - -// Defines kKeyMapping and GetKeyNameIndex() -#include "GonkKeyMapping.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "GeckoTouchDispatcher.h" - -#undef LOG -#define LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#ifdef VERBOSE_LOG_ENABLED -# define VERBOSE_LOG(args...) \ - __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#else -# define VERBOSE_LOG(args...) \ - (void)0 -#endif - -using namespace android; -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::services; -using namespace mozilla::widget; - -bool gDrawRequest = false; -static nsAppShell *gAppShell = nullptr; -static int epollfd = 0; -static int signalfds[2] = {0}; -static bool sDevInputAudioJack; -static int32_t sHeadphoneState; -static int32_t sMicrophoneState; - -// Amount of time in MS before an input is considered expired. -static const uint64_t kInputExpirationThresholdMs = 1000; -static const char kKey_WAKE_LOCK_ID[] = "GeckoKeyEvent"; - -NS_IMPL_ISUPPORTS_INHERITED(nsAppShell, nsBaseAppShell, nsIObserver) - -static uint64_t -nanosecsToMillisecs(nsecs_t nsecs) -{ - return nsecs / 1000000; -} - -namespace mozilla { - -bool ProcessNextEvent() -{ - return gAppShell->ProcessNextNativeEvent(true); -} - -void NotifyEvent() -{ - gAppShell->NotifyNativeEvent(); -} - -} // namespace mozilla - -static void -pipeHandler(int fd, FdHandler *data) -{ - ssize_t len; - do { - char tmp[32]; - len = read(fd, tmp, sizeof(tmp)); - } while (len > 0); -} - -struct Touch { - int32_t id; - PointerCoords coords; -}; - -struct UserInputData { - uint64_t timeMs; - enum { - MOTION_DATA, - KEY_DATA - } type; - int32_t action; - int32_t flags; - int32_t metaState; - int32_t deviceId; - union { - struct { - int32_t keyCode; - int32_t scanCode; - } key; - struct { - int32_t touchCount; - ::Touch touches[MAX_POINTERS]; - } motion; - }; -}; - -static mozilla::Modifiers -getDOMModifiers(int32_t metaState) -{ - mozilla::Modifiers result = 0; - if (metaState & (AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) { - result |= MODIFIER_ALT; - } - if (metaState & (AMETA_SHIFT_ON | - AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) { - result |= MODIFIER_SHIFT; - } - if (metaState & AMETA_FUNCTION_ON) { - result |= MODIFIER_FN; - } - if (metaState & (AMETA_CTRL_ON | - AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) { - result |= MODIFIER_CONTROL; - } - if (metaState & (AMETA_META_ON | - AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON)) { - result |= MODIFIER_META; - } - if (metaState & AMETA_CAPS_LOCK_ON) { - result |= MODIFIER_CAPSLOCK; - } - if (metaState & AMETA_NUM_LOCK_ON) { - result |= MODIFIER_NUMLOCK; - } - if (metaState & AMETA_SCROLL_LOCK_ON) { - result |= MODIFIER_SCROLLLOCK; - } - return result; -} - -class MOZ_STACK_CLASS KeyEventDispatcher -{ -public: - KeyEventDispatcher(const UserInputData& aData, - KeyCharacterMap* aKeyCharMap); - void Dispatch(); - -private: - const UserInputData& mData; - sp mKeyCharMap; - - char16_t mChar; - char16_t mUnmodifiedChar; - - uint32_t mDOMKeyCode; - uint32_t mDOMKeyLocation; - KeyNameIndex mDOMKeyNameIndex; - CodeNameIndex mDOMCodeNameIndex; - char16_t mDOMPrintableKeyValue; - - bool IsKeyPress() const - { - return mData.action == AKEY_EVENT_ACTION_DOWN; - } - bool IsRepeat() const - { - return IsKeyPress() && (mData.flags & AKEY_EVENT_FLAG_LONG_PRESS); - } - - char16_t PrintableKeyValue() const; - - int32_t UnmodifiedMetaState() const - { - return mData.metaState & - ~(AMETA_ALT_ON | AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON | - AMETA_CTRL_ON | AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON | - AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON); - } - - static bool IsControlChar(char16_t aChar) - { - return (aChar < ' ' || aChar == 0x7F); - } - - void DispatchKeyDownEvent(); - void DispatchKeyUpEvent(); - nsEventStatus DispatchKeyEventInternal(EventMessage aEventMessage); -}; - -KeyEventDispatcher::KeyEventDispatcher(const UserInputData& aData, - KeyCharacterMap* aKeyCharMap) - : mData(aData) - , mKeyCharMap(aKeyCharMap) - , mChar(0) - , mUnmodifiedChar(0) - , mDOMPrintableKeyValue(0) -{ - // XXX Printable key's keyCode value should be computed with actual - // input character. - mDOMKeyCode = (mData.key.keyCode < (ssize_t)ArrayLength(kKeyMapping)) ? - kKeyMapping[mData.key.keyCode] : 0; - mDOMKeyNameIndex = GetKeyNameIndex(mData.key.keyCode); - mDOMCodeNameIndex = GetCodeNameIndex(mData.key.scanCode); - mDOMKeyLocation = - WidgetKeyboardEvent::ComputeLocationFromCodeValue(mDOMCodeNameIndex); - - if (!mKeyCharMap.get()) { - return; - } - - mChar = mKeyCharMap->getCharacter(mData.key.keyCode, mData.metaState); - if (IsControlChar(mChar)) { - mChar = 0; - } - int32_t unmodifiedMetaState = UnmodifiedMetaState(); - if (mData.metaState == unmodifiedMetaState) { - mUnmodifiedChar = mChar; - } else { - mUnmodifiedChar = mKeyCharMap->getCharacter(mData.key.keyCode, - unmodifiedMetaState); - if (IsControlChar(mUnmodifiedChar)) { - mUnmodifiedChar = 0; - } - } - - mDOMPrintableKeyValue = PrintableKeyValue(); -} - -char16_t -KeyEventDispatcher::PrintableKeyValue() const -{ - if (mDOMKeyNameIndex != KEY_NAME_INDEX_USE_STRING) { - return 0; - } - return mChar ? mChar : mUnmodifiedChar; -} - -nsEventStatus -KeyEventDispatcher::DispatchKeyEventInternal(EventMessage aEventMessage) -{ - WidgetKeyboardEvent event(true, aEventMessage, nullptr); - if (aEventMessage == eKeyPress) { - // XXX If the charCode is not a printable character, the charCode - // should be computed without Ctrl/Alt/Meta modifiers. - event.mCharCode = static_cast(mChar); - } - if (!event.mCharCode) { - event.mKeyCode = mDOMKeyCode; - } - event.mIsChar = !!event.mCharCode; - event.mIsRepeat = IsRepeat(); - event.mKeyNameIndex = mDOMKeyNameIndex; - if (mDOMPrintableKeyValue) { - event.mKeyValue = mDOMPrintableKeyValue; - } - event.mCodeNameIndex = mDOMCodeNameIndex; - event.mModifiers = getDOMModifiers(mData.metaState); - event.mLocation = mDOMKeyLocation; - event.mTime = mData.timeMs; - return nsWindow::DispatchKeyInput(event); -} - -void -KeyEventDispatcher::Dispatch() -{ - // XXX Even if unknown key is pressed, DOM key event should be - // dispatched since Gecko for the other platforms are implemented - // as so. - if (!mDOMKeyCode && mDOMKeyNameIndex == KEY_NAME_INDEX_Unidentified) { - VERBOSE_LOG("Got unknown key event code. " - "type 0x%04x code 0x%04x value %d", - mData.action, mData.key.keyCode, IsKeyPress()); - return; - } - - if (IsKeyPress()) { - DispatchKeyDownEvent(); - } else { - DispatchKeyUpEvent(); - } -} - -void -KeyEventDispatcher::DispatchKeyDownEvent() -{ - nsEventStatus status = DispatchKeyEventInternal(eKeyDown); - if (status != nsEventStatus_eConsumeNoDefault) { - DispatchKeyEventInternal(eKeyPress); - } -} - -void -KeyEventDispatcher::DispatchKeyUpEvent() -{ - DispatchKeyEventInternal(eKeyUp); -} - -class SwitchEventRunnable : public mozilla::Runnable { -public: - SwitchEventRunnable(hal::SwitchEvent& aEvent) : mEvent(aEvent) - {} - - NS_IMETHOD Run() override - { - hal::NotifySwitchStateFromInputDevice(mEvent.device(), - mEvent.status()); - return NS_OK; - } -private: - hal::SwitchEvent mEvent; -}; - -static void -updateHeadphoneSwitch() -{ - hal::SwitchEvent event; - - switch (sHeadphoneState) { - case AKEY_STATE_UP: - event.status() = hal::SWITCH_STATE_OFF; - break; - case AKEY_STATE_DOWN: - event.status() = sMicrophoneState == AKEY_STATE_DOWN ? - hal::SWITCH_STATE_HEADSET : hal::SWITCH_STATE_HEADPHONE; - break; - default: - return; - } - - event.device() = hal::SWITCH_HEADPHONES; - NS_DispatchToMainThread(new SwitchEventRunnable(event)); -} - -class GeckoPointerController : public PointerControllerInterface { - float mX; - float mY; - int32_t mButtonState; - InputReaderConfiguration* mConfig; -public: - GeckoPointerController(InputReaderConfiguration* config) - : mX(0) - , mY(0) - , mButtonState(0) - , mConfig(config) - {} - - virtual bool getBounds(float* outMinX, float* outMinY, - float* outMaxX, float* outMaxY) const; - virtual void move(float deltaX, float deltaY); - virtual void setButtonState(int32_t buttonState); - virtual int32_t getButtonState() const; - virtual void setPosition(float x, float y); - virtual void getPosition(float* outX, float* outY) const; - virtual void fade(Transition transition) {} - virtual void unfade(Transition transition) {} - virtual void setPresentation(Presentation presentation) {} - virtual void setSpots(const PointerCoords* spotCoords, const uint32_t* spotIdToIndex, - BitSet32 spotIdBits) {} - virtual void clearSpots() {} -}; - -bool -GeckoPointerController::getBounds(float* outMinX, - float* outMinY, - float* outMaxX, - float* outMaxY) const -{ - DisplayViewport viewport; - - mConfig->getDisplayInfo(false, &viewport); - - *outMinX = *outMinY = 0; - *outMaxX = viewport.logicalRight; - *outMaxY = viewport.logicalBottom; - return true; -} - -void -GeckoPointerController::move(float deltaX, float deltaY) -{ - float minX, minY, maxX, maxY; - getBounds(&minX, &minY, &maxX, &maxY); - - mX = clamped(mX + deltaX, minX, maxX); - mY = clamped(mY + deltaY, minY, maxY); -} - -void -GeckoPointerController::setButtonState(int32_t buttonState) -{ - mButtonState = buttonState; -} - -int32_t -GeckoPointerController::getButtonState() const -{ - return mButtonState; -} - -void -GeckoPointerController::setPosition(float x, float y) -{ - mX = x; - mY = y; -} - -void -GeckoPointerController::getPosition(float* outX, float* outY) const -{ - *outX = mX; - *outY = mY; -} - -class GeckoInputReaderPolicy : public InputReaderPolicyInterface { - InputReaderConfiguration mConfig; -public: - GeckoInputReaderPolicy() {} - - virtual void getReaderConfiguration(InputReaderConfiguration* outConfig); - virtual sp obtainPointerController(int32_t -deviceId) - { - return new GeckoPointerController(&mConfig); - }; - virtual void notifyInputDevicesChanged(const android::Vector& inputDevices) {}; - virtual sp getKeyboardLayoutOverlay(const String8& inputDeviceDescriptor) - { - return nullptr; - }; - virtual String8 getDeviceAlias(const InputDeviceIdentifier& identifier) - { - return String8::empty(); - }; - - void setDisplayInfo(); - -protected: - virtual ~GeckoInputReaderPolicy() {} -}; - -class GeckoInputDispatcher : public InputDispatcherInterface { -public: - GeckoInputDispatcher(sp &aEventHub) - : mQueueLock("GeckoInputDispatcher::mQueueMutex") - , mEventHub(aEventHub) - , mKeyDownCount(0) - , mKeyEventsFiltered(false) - , mPowerWakelock(false) - { - mTouchDispatcher = GeckoTouchDispatcher::GetInstance(); - } - - virtual void dump(String8& dump); - - virtual void monitor() {} - - // Called on the main thread - virtual void dispatchOnce(); - - // notify* methods are called on the InputReaderThread - virtual void notifyConfigurationChanged(const NotifyConfigurationChangedArgs* args); - virtual void notifyKey(const NotifyKeyArgs* args); - virtual void notifyMotion(const NotifyMotionArgs* args); - virtual void notifySwitch(const NotifySwitchArgs* args); - virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args); - - virtual int32_t injectInputEvent(const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis, - uint32_t policyFlags); - - virtual void setInputWindows(const android::Vector >& inputWindowHandles); - virtual void setFocusedApplication(const sp& inputApplicationHandle); - - virtual void setInputDispatchMode(bool enabled, bool frozen); - virtual void setInputFilterEnabled(bool enabled) {} - virtual bool transferTouchFocus(const sp& fromChannel, - const sp& toChannel) { return true; } - - virtual status_t registerInputChannel(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor); - virtual status_t unregisterInputChannel(const sp& inputChannel); - - - -protected: - virtual ~GeckoInputDispatcher() { } - -private: - // mQueueLock should generally be locked while using mEventQueue. - // UserInputData is pushed on on the InputReaderThread and - // popped and dispatched on the main thread. - mozilla::Mutex mQueueLock; - std::queue mEventQueue; - sp mEventHub; - RefPtr mTouchDispatcher; - - int mKeyDownCount; - bool mKeyEventsFiltered; - bool mPowerWakelock; -}; - -// GeckoInputReaderPolicy -void -GeckoInputReaderPolicy::setDisplayInfo() -{ - static_assert(static_cast(nsIScreen::ROTATION_0_DEG) == - static_cast(DISPLAY_ORIENTATION_0), - "Orientation enums not matched!"); - static_assert(static_cast(nsIScreen::ROTATION_90_DEG) == - static_cast(DISPLAY_ORIENTATION_90), - "Orientation enums not matched!"); - static_assert(static_cast(nsIScreen::ROTATION_180_DEG) == - static_cast(DISPLAY_ORIENTATION_180), - "Orientation enums not matched!"); - static_assert(static_cast(nsIScreen::ROTATION_270_DEG) == - static_cast(DISPLAY_ORIENTATION_270), - "Orientation enums not matched!"); - - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - - uint32_t rotation = nsIScreen::ROTATION_0_DEG; - DebugOnly rv = screen->GetRotation(&rotation); - MOZ_ASSERT(NS_SUCCEEDED(rv)); - LayoutDeviceIntRect screenBounds = screen->GetNaturalBounds(); - - DisplayViewport viewport; - viewport.displayId = 0; - viewport.orientation = rotation; - viewport.physicalRight = viewport.deviceWidth = screenBounds.width; - viewport.physicalBottom = viewport.deviceHeight = screenBounds.height; - if (viewport.orientation == DISPLAY_ORIENTATION_90 || - viewport.orientation == DISPLAY_ORIENTATION_270) { - viewport.logicalRight = screenBounds.height; - viewport.logicalBottom = screenBounds.width; - } else { - viewport.logicalRight = screenBounds.width; - viewport.logicalBottom = screenBounds.height; - } - mConfig.setDisplayInfo(false, viewport); -} - -void GeckoInputReaderPolicy::getReaderConfiguration(InputReaderConfiguration* outConfig) -{ - *outConfig = mConfig; -} - - -// GeckoInputDispatcher -void -GeckoInputDispatcher::dump(String8& dump) -{ -} - -static bool -isExpired(const UserInputData& data) -{ - uint64_t timeNowMs = - nanosecsToMillisecs(systemTime(SYSTEM_TIME_MONOTONIC)); - return (timeNowMs - data.timeMs) > kInputExpirationThresholdMs; -} - -void -GeckoInputDispatcher::dispatchOnce() -{ - UserInputData data; - { - MutexAutoLock lock(mQueueLock); - if (mEventQueue.empty()) - return; - data = mEventQueue.front(); - mEventQueue.pop(); - if (!mEventQueue.empty()) - gAppShell->NotifyNativeEvent(); - } - - switch (data.type) { - case UserInputData::MOTION_DATA: { - MOZ_ASSERT_UNREACHABLE("Should not dispatch touch events here anymore"); - break; - } - case UserInputData::KEY_DATA: { - if (!mKeyDownCount) { - // No pending events, the filter state can be updated. - mKeyEventsFiltered = isExpired(data); - } - - mKeyDownCount += (data.action == AKEY_EVENT_ACTION_DOWN) ? 1 : -1; - if (mKeyEventsFiltered) { - return; - } - - sp kcm = mEventHub->getKeyCharacterMap(data.deviceId); - KeyEventDispatcher dispatcher(data, kcm.get()); - dispatcher.Dispatch(); - break; - } - } - MutexAutoLock lock(mQueueLock); - if (mPowerWakelock && mEventQueue.empty()) { - release_wake_lock(kKey_WAKE_LOCK_ID); - mPowerWakelock = false; - } -} - -void -GeckoInputDispatcher::notifyConfigurationChanged(const NotifyConfigurationChangedArgs*) -{ - gAppShell->CheckPowerKey(); -} - -void -GeckoInputDispatcher::notifyKey(const NotifyKeyArgs* args) -{ - UserInputData data; - data.timeMs = nanosecsToMillisecs(args->eventTime); - data.type = UserInputData::KEY_DATA; - data.action = args->action; - data.flags = args->flags; - data.metaState = args->metaState; - data.deviceId = args->deviceId; - data.key.keyCode = args->keyCode; - data.key.scanCode = args->scanCode; - { - MutexAutoLock lock(mQueueLock); - mEventQueue.push(data); - if (!mPowerWakelock) { - mPowerWakelock = - acquire_wake_lock(PARTIAL_WAKE_LOCK, kKey_WAKE_LOCK_ID); - } - } - gAppShell->NotifyNativeEvent(); -} - -static void -addMultiTouch(MultiTouchInput& aMultiTouch, - const NotifyMotionArgs* args, int aIndex) -{ - int32_t id = args->pointerProperties[aIndex].id; - PointerCoords coords = args->pointerCoords[aIndex]; - float force = coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE); - - float orientation = coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION); - float rotationAngle = orientation * 180 / M_PI; - if (rotationAngle == 90) { - rotationAngle = -90; - } - - float radiusX, radiusY; - if (rotationAngle < 0) { - radiusX = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR) / 2; - radiusY = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR) / 2; - rotationAngle += 90; - } else { - radiusX = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR) / 2; - radiusY = coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR) / 2; - } - - ScreenIntPoint point = ScreenIntPoint::Round(coords.getX(), - coords.getY()); - - SingleTouchData touchData(id, point, ScreenSize(radiusX, radiusY), - rotationAngle, force); - - aMultiTouch.mTouches.AppendElement(touchData); -} - -void -GeckoInputDispatcher::notifyMotion(const NotifyMotionArgs* args) -{ - uint32_t time = nanosecsToMillisecs(args->eventTime); - int32_t action = args->action & AMOTION_EVENT_ACTION_MASK; - int touchCount = args->pointerCount; - MOZ_ASSERT(touchCount <= MAX_POINTERS); - TimeStamp timestamp = mozilla::TimeStamp::FromSystemTime(args->eventTime); - Modifiers modifiers = getDOMModifiers(args->metaState); - - MultiTouchInput::MultiTouchType touchType = MultiTouchInput::MULTITOUCH_CANCEL; - switch (action) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - touchType = MultiTouchInput::MULTITOUCH_START; - break; - case AMOTION_EVENT_ACTION_MOVE: - touchType = MultiTouchInput::MULTITOUCH_MOVE; - break; - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_POINTER_UP: - touchType = MultiTouchInput::MULTITOUCH_END; - break; - case AMOTION_EVENT_ACTION_OUTSIDE: - case AMOTION_EVENT_ACTION_CANCEL: - touchType = MultiTouchInput::MULTITOUCH_CANCEL; - break; - case AMOTION_EVENT_ACTION_HOVER_EXIT: - case AMOTION_EVENT_ACTION_HOVER_ENTER: - case AMOTION_EVENT_ACTION_HOVER_MOVE: - NS_WARNING("Ignoring hover touch events"); - return; - default: - MOZ_ASSERT_UNREACHABLE("Could not assign a touch type"); - break; - } - - MultiTouchInput touchData(touchType, time, timestamp, modifiers); - - // For touch ends, we have to filter out which finger is actually - // the touch end since the touch array has all fingers, not just the touch - // that we want to end - if (touchType == MultiTouchInput::MULTITOUCH_END) { - int touchIndex = args->action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK; - touchIndex >>= AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - addMultiTouch(touchData, args, touchIndex); - } else { - for (int32_t i = 0; i < touchCount; ++i) { - addMultiTouch(touchData, args, i); - } - } - - mTouchDispatcher->NotifyTouch(touchData, timestamp); -} - -void GeckoInputDispatcher::notifySwitch(const NotifySwitchArgs* args) -{ - if (!sDevInputAudioJack) - return; - - bool needSwitchUpdate = false; - - if (args->switchMask & (1 << SW_HEADPHONE_INSERT)) { - sHeadphoneState = (args->switchValues & (1 << SW_HEADPHONE_INSERT)) ? - AKEY_STATE_DOWN : AKEY_STATE_UP; - needSwitchUpdate = true; - } - - if (args->switchMask & (1 << SW_MICROPHONE_INSERT)) { - sMicrophoneState = (args->switchValues & (1 << SW_MICROPHONE_INSERT)) ? - AKEY_STATE_DOWN : AKEY_STATE_UP; - needSwitchUpdate = true; - } - - if (needSwitchUpdate) - updateHeadphoneSwitch(); -} - -void GeckoInputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs* args) -{ -} - -int32_t GeckoInputDispatcher::injectInputEvent( - const InputEvent* event, - int32_t injectorPid, int32_t injectorUid, int32_t syncMode, - int32_t timeoutMillis, uint32_t policyFlags) -{ - return INPUT_EVENT_INJECTION_SUCCEEDED; -} - -void -GeckoInputDispatcher::setInputWindows(const android::Vector >& inputWindowHandles) -{ -} - -void -GeckoInputDispatcher::setFocusedApplication(const sp& inputApplicationHandle) -{ -} - -void -GeckoInputDispatcher::setInputDispatchMode(bool enabled, bool frozen) -{ -} - -status_t -GeckoInputDispatcher::registerInputChannel(const sp& inputChannel, - const sp& inputWindowHandle, bool monitor) -{ - return OK; -} - -status_t -GeckoInputDispatcher::unregisterInputChannel(const sp& inputChannel) -{ - return OK; -} - -nsAppShell::nsAppShell() - : mNativeCallbackRequest(false) - , mEnableDraw(false) - , mHandlers() - , mPowerKeyChecked(false) -{ - gAppShell = this; - if (XRE_IsParentProcess()) { - Preferences::SetCString("b2g.safe_mode", "unset"); - } -} - -nsAppShell::~nsAppShell() -{ - // mReaderThread and mEventHub will both be null if InitInputDevices - // is not called. - if (mReaderThread.get()) { - // We separate requestExit() and join() here so we can wake the EventHub's - // input loop, and stop it from polling for input events - mReaderThread->requestExit(); - mEventHub->wake(); - - status_t result = mReaderThread->requestExitAndWait(); - if (result) - LOG("Could not stop reader thread - %d", result); - } - gAppShell = nullptr; -} - -nsresult -nsAppShell::Init() -{ - nsresult rv = nsBaseAppShell::Init(); - NS_ENSURE_SUCCESS(rv, rv); - - epollfd = epoll_create(16); - NS_ENSURE_TRUE(epollfd >= 0, NS_ERROR_UNEXPECTED); - - int ret = pipe2(signalfds, O_NONBLOCK); - NS_ENSURE_FALSE(ret, NS_ERROR_UNEXPECTED); - - rv = AddFdHandler(signalfds[0], pipeHandler, ""); - NS_ENSURE_SUCCESS(rv, rv); - - InitGonkMemoryPressureMonitoring(); - - if (XRE_IsParentProcess()) { - printf("*****************************************************************\n"); - printf("***\n"); - printf("*** This is stdout. Most of the useful output will be in logcat.\n"); - printf("***\n"); - printf("*****************************************************************\n"); - GonkPermissionService::instantiate(); - - // Causes the kernel timezone to be set, which in turn causes the - // timestamps on SD cards to have the local time rather than UTC time. - hal::SetTimezone(hal::GetTimezone()); - } - - nsCOMPtr obsServ = GetObserverService(); - if (obsServ) { - obsServ->AddObserver(this, "browser-ui-startup-complete", false); - obsServ->AddObserver(this, "network-connection-state-changed", false); - } - - // Delay initializing input devices until the screen has been - // initialized (and we know the resolution). - return rv; -} - -void -nsAppShell::CheckPowerKey() -{ - if (mPowerKeyChecked) { - return; - } - - uint32_t deviceId = 0; - int32_t powerState = AKEY_STATE_UNKNOWN; - - // EventHub doesn't report the number of devices. - while (powerState != AKEY_STATE_DOWN && deviceId < 32) { - powerState = mEventHub->getKeyCodeState(deviceId++, AKEYCODE_POWER); - } - - // If Power is pressed while we startup, mark safe mode. - // Consumers of the b2g.safe_mode preference need to listen on this - // preference change to prevent startup races. - nsCOMPtr prefSetter = - NS_NewRunnableFunction([powerState] () -> void { - Preferences::SetCString("b2g.safe_mode", - (powerState == AKEY_STATE_DOWN) ? "yes" : "no"); - }); - NS_DispatchToMainThread(prefSetter.forget()); - - mPowerKeyChecked = true; -} - -NS_IMETHODIMP -nsAppShell::Observe(nsISupports* aSubject, - const char* aTopic, - const char16_t* aData) -{ - if (!strcmp(aTopic, "network-connection-state-changed")) { - NS_ConvertUTF16toUTF8 type(aData); - if (!type.IsEmpty()) { - hal::NotifyNetworkChange(hal::NetworkInformation(atoi(type.get()), 0, 0)); - } - return NS_OK; - } else if (!strcmp(aTopic, "browser-ui-startup-complete")) { - if (sDevInputAudioJack) { - sHeadphoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_HEADPHONE_INSERT); - sMicrophoneState = mReader->getSwitchState(-1, AINPUT_SOURCE_SWITCH, SW_MICROPHONE_INSERT); - updateHeadphoneSwitch(); - } - mEnableDraw = true; - - // System is almost booting up. Stop the bootAnim now. - StopBootAnimation(); - - NotifyEvent(); - return NS_OK; - } - - return nsBaseAppShell::Observe(aSubject, aTopic, aData); -} - -NS_IMETHODIMP -nsAppShell::Exit() -{ - OrientationObserver::ShutDown(); - nsCOMPtr obsServ = GetObserverService(); - if (obsServ) { - obsServ->RemoveObserver(this, "browser-ui-startup-complete"); - obsServ->RemoveObserver(this, "network-connection-state-changed"); - } - return nsBaseAppShell::Exit(); -} - -void -nsAppShell::InitInputDevices() -{ - sDevInputAudioJack = hal::IsHeadphoneEventFromInputDev(); - sHeadphoneState = AKEY_STATE_UNKNOWN; - sMicrophoneState = AKEY_STATE_UNKNOWN; - - mEventHub = new EventHub(); - mReaderPolicy = new GeckoInputReaderPolicy(); - mReaderPolicy->setDisplayInfo(); - mDispatcher = new GeckoInputDispatcher(mEventHub); - - mReader = new InputReader(mEventHub, mReaderPolicy, mDispatcher); - mReaderThread = new InputReaderThread(mReader); - - status_t result = mReaderThread->run("InputReader", PRIORITY_URGENT_DISPLAY); - if (result) { - LOG("Failed to initialize InputReader thread, bad things are going to happen..."); - } -} - -nsresult -nsAppShell::AddFdHandler(int fd, FdHandlerCallback handlerFunc, - const char* deviceName) -{ - epoll_event event = { - EPOLLIN, - { 0 } - }; - - FdHandler *handler = mHandlers.AppendElement(); - handler->fd = fd; - strncpy(handler->name, deviceName, sizeof(handler->name) - 1); - handler->func = handlerFunc; - event.data.u32 = mHandlers.Length() - 1; - return epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &event) ? - NS_ERROR_UNEXPECTED : NS_OK; -} - -void -nsAppShell::ScheduleNativeEventCallback() -{ - mNativeCallbackRequest = true; - NotifyEvent(); -} - -bool -nsAppShell::ProcessNextNativeEvent(bool mayWait) -{ - PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent", - js::ProfileEntry::Category::EVENTS); - - epoll_event events[16] = {{ 0 }}; - - int event_count; - { - PROFILER_LABEL("nsAppShell", "ProcessNextNativeEvent::Wait", - js::ProfileEntry::Category::EVENTS); - - if ((event_count = epoll_wait(epollfd, events, 16, mayWait ? -1 : 0)) <= 0) - return true; - } - - for (int i = 0; i < event_count; i++) - mHandlers[events[i].data.u32].run(); - - if (mDispatcher.get()) - mDispatcher->dispatchOnce(); - - // NativeEventCallback always schedules more if it needs it - // so we can coalesce these. - // See the implementation in nsBaseAppShell.cpp for more info - if (mNativeCallbackRequest) { - mNativeCallbackRequest = false; - NativeEventCallback(); - } - - if (gDrawRequest && mEnableDraw) { - gDrawRequest = false; - nsWindow::DoDraw(); - } - - return true; -} - -void -nsAppShell::NotifyNativeEvent() -{ - write(signalfds[1], "w", 1); -} - -/* static */ void -nsAppShell::NotifyScreenInitialized() -{ - gAppShell->InitInputDevices(); - - // Getting the instance of OrientationObserver to initialize it. - OrientationObserver::GetInstance(); -} - -/* static */ void -nsAppShell::NotifyScreenRotation() -{ - gAppShell->mReaderPolicy->setDisplayInfo(); - gAppShell->mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO); - - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - hal::NotifyScreenConfigurationChange(screen->GetConfiguration()); -} diff --git a/widget/gonk/nsAppShell.h b/widget/gonk/nsAppShell.h deleted file mode 100644 index 046a99ea1..000000000 --- a/widget/gonk/nsAppShell.h +++ /dev/null @@ -1,112 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsAppShell_h -#define nsAppShell_h - -#include - -#include "mozilla/Mutex.h" -#include "nsBaseAppShell.h" -#include "nsTArray.h" - -#include "utils/RefBase.h" - -namespace mozilla { -bool ProcessNextEvent(); -void NotifyEvent(); -} - -extern bool gDrawRequest; - -class FdHandler; -typedef void(*FdHandlerCallback)(int, FdHandler *); - -class FdHandler { -public: - FdHandler() - { - memset(name, 0, sizeof(name)); - } - - int fd; - char name[64]; - FdHandlerCallback func; - void run() - { - func(fd, this); - } -}; - -namespace android { -class EventHub; -class InputReader; -class InputReaderThread; -} - -class GeckoInputReaderPolicy; -class GeckoInputDispatcher; - -class nsAppShell : public nsBaseAppShell { -public: - nsAppShell(); - - NS_DECL_ISUPPORTS_INHERITED - NS_DECL_NSIOBSERVER - - nsresult Init(); - - NS_IMETHOD Exit() override; - - virtual bool ProcessNextNativeEvent(bool maywait); - - void NotifyNativeEvent(); - - static void NotifyScreenInitialized(); - static void NotifyScreenRotation(); - - void CheckPowerKey(); - -protected: - virtual ~nsAppShell(); - - virtual void ScheduleNativeEventCallback(); - -private: - nsresult AddFdHandler(int fd, FdHandlerCallback handlerFunc, - const char* deviceName); - void InitInputDevices(); - - // This is somewhat racy but is perfectly safe given how the callback works - bool mNativeCallbackRequest; - - // This gets flipped when we observe a browser-ui-startup-complete. - // browser-ui-startup-complete means that we're really ready to draw - // and can stop the boot animation - bool mEnableDraw; - nsTArray mHandlers; - - android::sp mEventHub; - android::sp mReaderPolicy; - android::sp mDispatcher; - android::sp mReader; - android::sp mReaderThread; - - // Guard against checking power key after the first configuration change. - bool mPowerKeyChecked; -}; - -#endif /* nsAppShell_h */ - diff --git a/widget/gonk/nsClipboard.cpp b/widget/gonk/nsClipboard.cpp deleted file mode 100644 index a1eabe8e5..000000000 --- a/widget/gonk/nsClipboard.cpp +++ /dev/null @@ -1,366 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsClipboard.h" - -#include "gfxDrawable.h" -#include "gfxUtils.h" -#include "ImageOps.h" -#include "imgIContainer.h" -#include "imgTools.h" -#include "mozilla/dom/ContentChild.h" -#include "mozilla/Preferences.h" -#include "nsArrayUtils.h" -#include "nsClipboardProxy.h" -#include "nsISupportsPrimitives.h" -#include "nsComponentManagerUtils.h" -#include "nsCOMPtr.h" -#include "nsServiceManagerUtils.h" -#include "nsStringStream.h" -#include "nsXULAppAPI.h" - -using namespace mozilla; -using mozilla::dom::ContentChild; - -#define LOG_TAG "Clipboard" -#define LOGI(args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, ## args) - - -NS_IMPL_ISUPPORTS(nsClipboard, nsIClipboard) - -nsClipboard::nsClipboard() - : mClipboard(mozilla::MakeUnique()) -{ -} - -NS_IMETHODIMP -nsClipboard::SetData(nsITransferable *aTransferable, - nsIClipboardOwner *anOwner, - int32_t aWhichClipboard) -{ - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - - if (!XRE_IsParentProcess()) { - // Re-direct to the clipboard proxy. - RefPtr clipboardProxy = new nsClipboardProxy(); - return clipboardProxy->SetData(aTransferable, anOwner, aWhichClipboard); - } - - // Clear out the clipboard in order to set the new data. - EmptyClipboard(aWhichClipboard); - - // Use a pref to toggle rich text/non-text support. - if (Preferences::GetBool("clipboard.plainTextOnly")) { - nsCOMPtr clip; - uint32_t len; - nsresult rv = aTransferable->GetTransferData(kUnicodeMime, - getter_AddRefs(clip), - &len); - if (NS_FAILED(rv)) { - return rv; - } - nsCOMPtr wideString = do_QueryInterface(clip); - if (!wideString) { - return NS_ERROR_NOT_IMPLEMENTED; - } - nsAutoString utf16string; - wideString->GetData(utf16string); - mClipboard->SetText(utf16string); - return NS_OK; - } - - // Get the types of supported flavors. - nsCOMPtr flavorList; - nsresult rv = aTransferable->FlavorsTransferableCanExport(getter_AddRefs(flavorList)); - if (!flavorList || NS_FAILED(rv)) { - return NS_ERROR_FAILURE; - } - - uint32_t flavorCount = 0; - flavorList->GetLength(&flavorCount); - bool imageAdded = false; - for (uint32_t i = 0; i < flavorCount; ++i) { - nsCOMPtr currentFlavor = do_QueryElementAt(flavorList, i); - - if (currentFlavor) { - // MIME type - nsXPIDLCString flavorStr; - currentFlavor->ToString(getter_Copies(flavorStr)); - - // Clip is the data which will be sent to the clipboard. - nsCOMPtr clip; - uint32_t len; - - if (flavorStr.EqualsLiteral(kUnicodeMime)) { - // text/plain - rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len); - nsCOMPtr wideString = do_QueryInterface(clip); - if (!wideString || NS_FAILED(rv)) { - continue; - } - - nsAutoString utf16string; - wideString->GetData(utf16string); - mClipboard->SetText(utf16string); - } else if (flavorStr.EqualsLiteral(kHTMLMime)) { - // text/html - rv = aTransferable->GetTransferData(flavorStr, getter_AddRefs(clip), &len); - nsCOMPtr wideString = do_QueryInterface(clip); - if (!wideString || NS_FAILED(rv)) { - continue; - } - - nsAutoString utf16string; - wideString->GetData(utf16string); - mClipboard->SetHTML(utf16string); - } else if (!imageAdded && // image is added only once to the clipboard. - (flavorStr.EqualsLiteral(kNativeImageMime) || - flavorStr.EqualsLiteral(kPNGImageMime) || - flavorStr.EqualsLiteral(kJPEGImageMime) || - flavorStr.EqualsLiteral(kJPGImageMime))) { - // image/[png|jpeg|jpg] or application/x-moz-nativeimage - - // Look through our transfer data for the image. - static const char* const imageMimeTypes[] = { - kNativeImageMime, kPNGImageMime, kJPEGImageMime, kJPGImageMime }; - - nsCOMPtr imgPtr; - for (uint32_t i = 0; !imgPtr && i < ArrayLength(imageMimeTypes); ++i) { - aTransferable->GetTransferData(imageMimeTypes[i], getter_AddRefs(clip), &len); - imgPtr = do_QueryInterface(clip); - } - if (!imgPtr) { - continue; - } - - nsCOMPtr imageData; - imgPtr->GetData(getter_AddRefs(imageData)); - nsCOMPtr image(do_QueryInterface(imageData)); - if (!image) { - continue; - } - - RefPtr surface = - image->GetFrame(imgIContainer::FRAME_CURRENT, - imgIContainer::FLAG_SYNC_DECODE); - if (!surface) { - continue; - } - - RefPtr dataSurface; - if (surface->GetFormat() == gfx::SurfaceFormat::B8G8R8A8) { - dataSurface = surface->GetDataSurface(); - } else { - // Convert format to SurfaceFormat::B8G8R8A8. - dataSurface = gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(surface, gfx::SurfaceFormat::B8G8R8A8); - } - - mClipboard->SetImage(dataSurface); - imageAdded = true; - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::GetData(nsITransferable *aTransferable, - int32_t aWhichClipboard) -{ - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - - if (!XRE_IsParentProcess()) { - // Re-direct to the clipboard proxy. - RefPtr clipboardProxy = new nsClipboardProxy(); - return clipboardProxy->GetData(aTransferable, aWhichClipboard); - } - - // Use a pref to toggle rich text/non-text support. - if (Preferences::GetBool("clipboard.plainTextOnly")) { - nsresult rv; - nsCOMPtr dataWrapper = - do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - rv = dataWrapper->SetData(mClipboard->GetText()); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - nsCOMPtr genericDataWrapper = do_QueryInterface(dataWrapper); - uint32_t len = mClipboard->GetText().Length() * sizeof(char16_t); - rv = aTransferable->SetTransferData(kUnicodeMime, genericDataWrapper, len); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return NS_OK; - } - - // Get flavor list that includes all acceptable flavors (including - // ones obtained through conversion). - // Note: We don't need to call nsITransferable::AddDataFlavor here - // because ContentParent already did. - nsCOMPtr flavorList; - nsresult rv = aTransferable->FlavorsTransferableCanImport(getter_AddRefs(flavorList)); - - if (!flavorList || NS_FAILED(rv)) { - return NS_ERROR_FAILURE; - } - - // Walk through flavors and see which flavor matches the one being pasted. - uint32_t flavorCount; - flavorList->GetLength(&flavorCount); - - for (uint32_t i = 0; i < flavorCount; ++i) { - nsCOMPtr currentFlavor = do_QueryElementAt(flavorList, i); - - if (currentFlavor) { - // flavorStr is the mime type. - nsXPIDLCString flavorStr; - currentFlavor->ToString(getter_Copies(flavorStr)); - - // text/plain, text/Unicode - if (flavorStr.EqualsLiteral(kUnicodeMime) && mClipboard->HasText()) { - nsresult rv; - nsCOMPtr dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - rv = dataWrapper->SetData(mClipboard->GetText()); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - - nsCOMPtr genericDataWrapper = do_QueryInterface(dataWrapper); - uint32_t len = mClipboard->GetText().Length() * sizeof(char16_t); - rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - break; - } - - // text/html - if (flavorStr.EqualsLiteral(kHTMLMime) && mClipboard->HasHTML()) { - nsresult rv; - nsCOMPtr dataWrapper = do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv); - rv = dataWrapper->SetData(mClipboard->GetHTML()); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - - nsCOMPtr genericDataWrapper = do_QueryInterface(dataWrapper); - uint32_t len = mClipboard->GetHTML().Length() * sizeof(char16_t); - rv = aTransferable->SetTransferData(flavorStr, genericDataWrapper, len); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - break; - } - - // image/[png|jpeg|jpg] - if ((flavorStr.EqualsLiteral(kPNGImageMime) || - flavorStr.EqualsLiteral(kJPEGImageMime) || - flavorStr.EqualsLiteral(kJPGImageMime)) && - mClipboard->HasImage() ) { - // Get image buffer from clipboard. - RefPtr image = mClipboard->GetImage(); - - // Encode according to MIME type. - RefPtr drawable = new gfxSurfaceDrawable(image, image->GetSize()); - nsCOMPtr imageContainer(image::ImageOps::CreateFromDrawable(drawable)); - nsCOMPtr imgTool = do_GetService(NS_IMGTOOLS_CID); - - nsCOMPtr byteStream; - nsresult rv = imgTool->EncodeImage(imageContainer, - flavorStr, - EmptyString(), - getter_AddRefs(byteStream)); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - - // Set transferable. - rv = aTransferable->SetTransferData(flavorStr, - byteStream, - sizeof(nsIInputStream*)); - if (NS_WARN_IF(NS_FAILED(rv))) { - continue; - } - break; - } - } - } - - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::EmptyClipboard(int32_t aWhichClipboard) -{ - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - if (XRE_IsParentProcess()) { - mClipboard->Clear(); - } else { - ContentChild::GetSingleton()->SendEmptyClipboard(aWhichClipboard); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::HasDataMatchingFlavors(const char **aFlavorList, - uint32_t aLength, int32_t aWhichClipboard, - bool *aHasType) -{ - *aHasType = false; - if (aWhichClipboard != kGlobalClipboard) { - return NS_ERROR_NOT_IMPLEMENTED; - } - if (XRE_IsParentProcess()) { - // Retrieve the union of all aHasType in aFlavorList - for (uint32_t i = 0; i < aLength; ++i) { - const char *flavor = aFlavorList[i]; - if (!flavor) { - continue; - } - if (!strcmp(flavor, kUnicodeMime) && mClipboard->HasText()) { - *aHasType = true; - } else if (!strcmp(flavor, kHTMLMime) && mClipboard->HasHTML()) { - *aHasType = true; - } else if (!strcmp(flavor, kJPEGImageMime) || - !strcmp(flavor, kJPGImageMime) || - !strcmp(flavor, kPNGImageMime)) { - // We will encode the image into any format you want, so we don't - // need to check each specific format - if (mClipboard->HasImage()) { - *aHasType = true; - } - } - } - } else { - RefPtr clipboardProxy = new nsClipboardProxy(); - return clipboardProxy->HasDataMatchingFlavors(aFlavorList, aLength, aWhichClipboard, aHasType); - } - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::SupportsSelectionClipboard(bool *aIsSupported) -{ - *aIsSupported = false; - return NS_OK; -} - -NS_IMETHODIMP -nsClipboard::SupportsFindClipboard(bool* _retval) -{ - NS_ENSURE_ARG_POINTER(_retval); - - *_retval = false; - return NS_OK; -} - diff --git a/widget/gonk/nsClipboard.h b/widget/gonk/nsClipboard.h deleted file mode 100644 index cd2e0dbd5..000000000 --- a/widget/gonk/nsClipboard.h +++ /dev/null @@ -1,27 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef nsClipbard_h__ -#define nsClipbard_h__ - -#include "GonkClipboardData.h" -#include "mozilla/UniquePtr.h" -#include "nsIClipboard.h" - -class nsClipboard final : public nsIClipboard -{ -public: - NS_DECL_ISUPPORTS - NS_DECL_NSICLIPBOARD - - nsClipboard(); - -protected: - ~nsClipboard() {} - -private: - mozilla::UniquePtr mClipboard; -}; - -#endif diff --git a/widget/gonk/nsIdleServiceGonk.cpp b/widget/gonk/nsIdleServiceGonk.cpp deleted file mode 100644 index dc7588e5e..000000000 --- a/widget/gonk/nsIdleServiceGonk.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:expandtab:shiftwidth=4:tabstop=4: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsIdleServiceGonk.h" -#include "nsIServiceManager.h" - -NS_IMPL_ISUPPORTS_INHERITED0(nsIdleServiceGonk, nsIdleService) - -bool -nsIdleServiceGonk::PollIdleTime(uint32_t *aIdleTime) -{ - return false; -} - -bool -nsIdleServiceGonk::UsePollMode() -{ - return false; -} diff --git a/widget/gonk/nsIdleServiceGonk.h b/widget/gonk/nsIdleServiceGonk.h deleted file mode 100644 index 32520dce6..000000000 --- a/widget/gonk/nsIdleServiceGonk.h +++ /dev/null @@ -1,47 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* vim:expandtab:shiftwidth=4:tabstop=4: */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsIdleServiceGonk_h__ -#define nsIdleServiceGonk_h__ - -#include "nsIdleService.h" - -class nsIdleServiceGonk : public nsIdleService -{ -public: - NS_DECL_ISUPPORTS_INHERITED - - bool PollIdleTime(uint32_t* aIdleTime); - - static already_AddRefed GetInstance() - { - RefPtr idleService = - nsIdleService::GetInstance().downcast(); - if (!idleService) { - idleService = new nsIdleServiceGonk(); - } - - return idleService.forget(); - } - -protected: - nsIdleServiceGonk() { } - virtual ~nsIdleServiceGonk() { } - bool UsePollMode(); -}; - -#endif // nsIdleServiceGonk_h__ diff --git a/widget/gonk/nsLookAndFeel.cpp b/widget/gonk/nsLookAndFeel.cpp deleted file mode 100644 index 120f257df..000000000 --- a/widget/gonk/nsLookAndFeel.cpp +++ /dev/null @@ -1,465 +0,0 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsLookAndFeel.h" -#include "nsStyleConsts.h" -#include "gfxFont.h" -#include "gfxFontConstants.h" -#include "mozilla/gfx/2D.h" -#include "cutils/properties.h" - -static const char16_t UNICODE_BULLET = 0x2022; - -nsLookAndFeel::nsLookAndFeel() - : nsXPLookAndFeel() -{ -} - -nsLookAndFeel::~nsLookAndFeel() -{ -} - -nsresult -nsLookAndFeel::NativeGetColor(ColorID aID, nscolor &aColor) -{ - nsresult rv = NS_OK; - -#define BASE_ACTIVE_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define BASE_NORMAL_COLOR NS_RGB(0xff,0xff,0xff) -#define BASE_SELECTED_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define BG_ACTIVE_COLOR NS_RGB(0xff,0xff,0xff) -#define BG_INSENSITIVE_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define BG_NORMAL_COLOR NS_RGB(0xff,0xff,0xff) -#define BG_PRELIGHT_COLOR NS_RGB(0xee,0xee,0xee) -#define BG_SELECTED_COLOR NS_RGB(0x99,0x99,0x99) -#define DARK_NORMAL_COLOR NS_RGB(0x88,0x88,0x88) -#define FG_INSENSITIVE_COLOR NS_RGB(0x44,0x44,0x44) -#define FG_NORMAL_COLOR NS_RGB(0x00,0x00,0x00) -#define FG_PRELIGHT_COLOR NS_RGB(0x77,0x77,0x77) -#define FG_SELECTED_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define LIGHT_NORMAL_COLOR NS_RGB(0xaa,0xaa,0xaa) -#define TEXT_ACTIVE_COLOR NS_RGB(0x99,0x99,0x99) -#define TEXT_NORMAL_COLOR NS_RGB(0x00,0x00,0x00) -#define TEXT_SELECTED_COLOR NS_RGB(0x00,0x00,0x00) - - switch (aID) { - // These colors don't seem to be used for anything anymore in Mozilla - // (except here at least TextSelectBackground and TextSelectForeground) - // The CSS2 colors below are used. - case eColorID_WindowBackground: - aColor = BASE_NORMAL_COLOR; - break; - case eColorID_WindowForeground: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_WidgetBackground: - aColor = BG_NORMAL_COLOR; - break; - case eColorID_WidgetForeground: - aColor = FG_NORMAL_COLOR; - break; - case eColorID_WidgetSelectBackground: - aColor = BG_SELECTED_COLOR; - break; - case eColorID_WidgetSelectForeground: - aColor = FG_SELECTED_COLOR; - break; - case eColorID_Widget3DHighlight: - aColor = NS_RGB(0xa0,0xa0,0xa0); - break; - case eColorID_Widget3DShadow: - aColor = NS_RGB(0x40,0x40,0x40); - break; - case eColorID_TextBackground: - // not used? - aColor = BASE_NORMAL_COLOR; - break; - case eColorID_TextForeground: - // not used? - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_TextSelectBackground: - aColor = NS_RGBA(0x33,0xb5,0xe5,0x66); - break; - case eColorID_IMESelectedRawTextBackground: - case eColorID_IMESelectedConvertedTextBackground: - // still used - aColor = BASE_SELECTED_COLOR; - break; - case eColorID_TextSelectForegroundCustom: - aColor = NS_RGB(0x4d,0x4d,0x4d); - break; - case eColorID_TextSelectForeground: - aColor = NS_CHANGE_COLOR_IF_SAME_AS_BG; - break; - case eColorID_IMESelectedRawTextForeground: - case eColorID_IMESelectedConvertedTextForeground: - // still used - aColor = TEXT_SELECTED_COLOR; - break; - case eColorID_IMERawInputBackground: - case eColorID_IMEConvertedTextBackground: - aColor = NS_TRANSPARENT; - break; - case eColorID_IMERawInputForeground: - case eColorID_IMEConvertedTextForeground: - aColor = NS_SAME_AS_FOREGROUND_COLOR; - break; - case eColorID_IMERawInputUnderline: - case eColorID_IMEConvertedTextUnderline: - aColor = NS_SAME_AS_FOREGROUND_COLOR; - break; - case eColorID_IMESelectedRawTextUnderline: - case eColorID_IMESelectedConvertedTextUnderline: - aColor = NS_TRANSPARENT; - break; - case eColorID_SpellCheckerUnderline: - aColor = NS_RGB(0xff, 0, 0); - break; - - // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors - case eColorID_activeborder: - // active window border - aColor = BG_NORMAL_COLOR; - break; - case eColorID_activecaption: - // active window caption background - aColor = BG_NORMAL_COLOR; - break; - case eColorID_appworkspace: - // MDI background color - aColor = BG_NORMAL_COLOR; - break; - case eColorID_background: - // desktop background - aColor = BG_NORMAL_COLOR; - break; - case eColorID_captiontext: - // text in active window caption, size box, and scrollbar arrow box (!) - aColor = FG_NORMAL_COLOR; - break; - case eColorID_graytext: - // disabled text in windows, menus, etc. - aColor = FG_INSENSITIVE_COLOR; - break; - case eColorID_highlight: - // background of selected item - aColor = BASE_SELECTED_COLOR; - break; - case eColorID_highlighttext: - // text of selected item - aColor = TEXT_SELECTED_COLOR; - break; - case eColorID_inactiveborder: - // inactive window border - aColor = BG_NORMAL_COLOR; - break; - case eColorID_inactivecaption: - // inactive window caption - aColor = BG_INSENSITIVE_COLOR; - break; - case eColorID_inactivecaptiontext: - // text in inactive window caption - aColor = FG_INSENSITIVE_COLOR; - break; - case eColorID_infobackground: - // tooltip background color - aColor = BG_NORMAL_COLOR; - break; - case eColorID_infotext: - // tooltip text color - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_menu: - // menu background - aColor = BG_NORMAL_COLOR; - break; - case eColorID_menutext: - // menu text - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID_scrollbar: - // scrollbar gray area - aColor = BG_ACTIVE_COLOR; - break; - - case eColorID_threedface: - case eColorID_buttonface: - // 3-D face color - aColor = BG_NORMAL_COLOR; - break; - - case eColorID_buttontext: - // text on push buttons - aColor = TEXT_NORMAL_COLOR; - break; - - case eColorID_buttonhighlight: - // 3-D highlighted edge color - case eColorID_threedhighlight: - // 3-D highlighted outer edge color - aColor = LIGHT_NORMAL_COLOR; - break; - - case eColorID_threedlightshadow: - // 3-D highlighted inner edge color - aColor = BG_NORMAL_COLOR; - break; - - case eColorID_buttonshadow: - // 3-D shadow edge color - case eColorID_threedshadow: - // 3-D shadow inner edge color - aColor = DARK_NORMAL_COLOR; - break; - - case eColorID_threeddarkshadow: - // 3-D shadow outer edge color - aColor = NS_RGB(0,0,0); - break; - - case eColorID_window: - case eColorID_windowframe: - aColor = BG_NORMAL_COLOR; - break; - - case eColorID_windowtext: - aColor = FG_NORMAL_COLOR; - break; - - case eColorID__moz_eventreerow: - case eColorID__moz_field: - aColor = BASE_NORMAL_COLOR; - break; - case eColorID__moz_fieldtext: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID__moz_dialog: - aColor = BG_NORMAL_COLOR; - break; - case eColorID__moz_dialogtext: - aColor = FG_NORMAL_COLOR; - break; - case eColorID__moz_dragtargetzone: - aColor = BG_SELECTED_COLOR; - break; - case eColorID__moz_buttondefault: - // default button border color - aColor = NS_RGB(0,0,0); - break; - case eColorID__moz_buttonhoverface: - aColor = BG_PRELIGHT_COLOR; - break; - case eColorID__moz_buttonhovertext: - aColor = FG_PRELIGHT_COLOR; - break; - case eColorID__moz_cellhighlight: - case eColorID__moz_html_cellhighlight: - aColor = BASE_ACTIVE_COLOR; - break; - case eColorID__moz_cellhighlighttext: - case eColorID__moz_html_cellhighlighttext: - aColor = TEXT_ACTIVE_COLOR; - break; - case eColorID__moz_menuhover: - aColor = BG_PRELIGHT_COLOR; - break; - case eColorID__moz_menuhovertext: - aColor = FG_PRELIGHT_COLOR; - break; - case eColorID__moz_oddtreerow: - aColor = NS_TRANSPARENT; - break; - case eColorID__moz_nativehyperlinktext: - aColor = NS_SAME_AS_FOREGROUND_COLOR; - break; - case eColorID__moz_comboboxtext: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID__moz_combobox: - aColor = BG_NORMAL_COLOR; - break; - case eColorID__moz_menubartext: - aColor = TEXT_NORMAL_COLOR; - break; - case eColorID__moz_menubarhovertext: - aColor = FG_PRELIGHT_COLOR; - break; - default: - /* default color is BLACK */ - aColor = 0; - rv = NS_ERROR_FAILURE; - break; - } - - return rv; -} - -nsresult -nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult) -{ - nsresult rv = nsXPLookAndFeel::GetIntImpl(aID, aResult); - if (NS_SUCCEEDED(rv)) - return rv; - - rv = NS_OK; - - switch (aID) { - case eIntID_CaretBlinkTime: - aResult = 500; - break; - - case eIntID_CaretWidth: - aResult = 1; - break; - - case eIntID_ShowCaretDuringSelection: - aResult = 0; - break; - - case eIntID_SelectTextfieldsOnKeyFocus: - // Select textfield content when focused by kbd - // used by EventStateManager::sTextfieldSelectModel - aResult = 1; - break; - - case eIntID_SubmenuDelay: - aResult = 200; - break; - - case eIntID_TooltipDelay: - aResult = 500; - break; - - case eIntID_MenusCanOverlapOSBar: - // we want XUL popups to be able to overlap the task bar. - aResult = 1; - break; - - case eIntID_ScrollArrowStyle: - aResult = eScrollArrowStyle_Single; - break; - - case eIntID_ScrollSliderStyle: - aResult = eScrollThumbStyle_Proportional; - break; - - case eIntID_TouchEnabled: - aResult = 1; - break; - - case eIntID_WindowsDefaultTheme: - case eIntID_WindowsThemeIdentifier: - case eIntID_OperatingSystemVersionIdentifier: - aResult = 0; - rv = NS_ERROR_NOT_IMPLEMENTED; - break; - - case eIntID_IMERawInputUnderlineStyle: - case eIntID_IMEConvertedTextUnderlineStyle: - aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID; - break; - - case eIntID_IMESelectedRawTextUnderlineStyle: - case eIntID_IMESelectedConvertedTextUnderline: - aResult = NS_STYLE_TEXT_DECORATION_STYLE_NONE; - break; - - case eIntID_SpellCheckerUnderlineStyle: - aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY; - break; - - case eIntID_ScrollbarButtonAutoRepeatBehavior: - aResult = 0; - break; - - case eIntID_PhysicalHomeButton: { - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.moz.has_home_button", propValue, "1"); - aResult = atoi(propValue); - break; - } - - case eIntID_ContextMenuOffsetVertical: - case eIntID_ContextMenuOffsetHorizontal: - aResult = 2; - break; - - default: - aResult = 0; - rv = NS_ERROR_FAILURE; - } - - return rv; -} - -nsresult -nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult) -{ - nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult); - if (NS_SUCCEEDED(res)) - return res; - res = NS_OK; - - switch (aID) { - case eFloatID_IMEUnderlineRelativeSize: - aResult = 1.0f; - break; - case eFloatID_SpellCheckerUnderlineRelativeSize: - aResult = 1.0f; - break; - default: - aResult = -1.0; - res = NS_ERROR_FAILURE; - } - return res; -} - -/*virtual*/ -bool -nsLookAndFeel::GetFontImpl(FontID aID, nsString& aFontName, - gfxFontStyle& aFontStyle, - float aDevPixPerCSSPixel) -{ - aFontName.AssignLiteral("\"Fira Sans\""); - aFontStyle.style = NS_FONT_STYLE_NORMAL; - aFontStyle.weight = NS_FONT_WEIGHT_NORMAL; - aFontStyle.stretch = NS_FONT_STRETCH_NORMAL; - aFontStyle.size = 9.0 * 96.0f / 72.0f; - aFontStyle.systemFont = true; - return true; -} - -/*virtual*/ -bool -nsLookAndFeel::GetEchoPasswordImpl() { - return true; -} - -/*virtual*/ -uint32_t -nsLookAndFeel::GetPasswordMaskDelayImpl() -{ - // Same value on Android framework - return 1500; -} - -/* virtual */ -char16_t -nsLookAndFeel::GetPasswordCharacterImpl() -{ - return UNICODE_BULLET; -} diff --git a/widget/gonk/nsLookAndFeel.h b/widget/gonk/nsLookAndFeel.h deleted file mode 100644 index aa7dce823..000000000 --- a/widget/gonk/nsLookAndFeel.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef __nsLookAndFeel -#define __nsLookAndFeel - -#include "nsXPLookAndFeel.h" - -class nsLookAndFeel : public nsXPLookAndFeel -{ -public: - nsLookAndFeel(); - virtual ~nsLookAndFeel(); - - virtual bool GetFontImpl(FontID aID, nsString& aName, gfxFontStyle& aStyle, - float aDevPixPerCSSPixel); - virtual nsresult GetIntImpl(IntID aID, int32_t &aResult); - virtual nsresult GetFloatImpl(FloatID aID, float &aResult); - virtual bool GetEchoPasswordImpl(); - virtual uint32_t GetPasswordMaskDelayImpl(); - virtual char16_t GetPasswordCharacterImpl(); - -protected: - virtual nsresult NativeGetColor(ColorID aID, nscolor &aColor); -}; - -#endif diff --git a/widget/gonk/nsScreenManagerGonk.cpp b/widget/gonk/nsScreenManagerGonk.cpp deleted file mode 100644 index e359fd195..000000000 --- a/widget/gonk/nsScreenManagerGonk.cpp +++ /dev/null @@ -1,1081 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "android/log.h" -#include "GLContext.h" -#include "gfxPrefs.h" -#include "gfxUtils.h" -#include "mozilla/MouseEvents.h" -#include "mozilla/TouchEvents.h" -#include "mozilla/Hal.h" -#include "libdisplay/BootAnimation.h" -#include "libdisplay/GonkDisplay.h" -#include "nsScreenManagerGonk.h" -#include "nsThreadUtils.h" -#include "HwcComposer2D.h" -#include "VsyncSource.h" -#include "nsWindow.h" -#include "mozilla/ClearOnShutdown.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/CompositorThread.h" -#include "mozilla/Services.h" -#include "mozilla/ProcessPriorityManager.h" -#include "nsIdleService.h" -#include "nsIObserverService.h" -#include "nsAppShell.h" -#include "nsProxyRelease.h" -#include "nsTArray.h" -#include "pixelflinger/format.h" -#include "nsIDisplayInfo.h" -#include "base/task.h" - -#if ANDROID_VERSION >= 17 -#include "libdisplay/DisplaySurface.h" -#endif - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "nsScreenGonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "nsScreenGonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "nsScreenGonk", ## args) - -using namespace mozilla; -using namespace mozilla::hal; -using namespace mozilla::gfx; -using namespace mozilla::gl; -using namespace mozilla::layers; -using namespace mozilla::dom; - -namespace { - -class ScreenOnOffEvent : public mozilla::Runnable { -public: - ScreenOnOffEvent(bool on) - : mIsOn(on) - {} - - NS_IMETHOD Run() override { - // Notify observers that the screen state has just changed. - nsCOMPtr observerService = mozilla::services::GetObserverService(); - if (observerService) { - observerService->NotifyObservers( - nullptr, "screen-state-changed", - mIsOn ? u"on" : u"off" - ); - } - - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - const nsTArray& windows = screen->GetTopWindows(); - - for (uint32_t i = 0; i < windows.Length(); i++) { - nsWindow *win = windows[i]; - - if (nsIWidgetListener* listener = win->GetWidgetListener()) { - listener->SizeModeChanged(mIsOn ? nsSizeMode_Fullscreen : nsSizeMode_Minimized); - } - } - - return NS_OK; - } - -private: - bool mIsOn; -}; - -static void -displayEnabledCallback(bool enabled) -{ - RefPtr screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->DisplayEnabled(enabled); -} - -} // namespace - -static uint32_t -SurfaceFormatToColorDepth(int32_t aSurfaceFormat) -{ - switch (aSurfaceFormat) { - case GGL_PIXEL_FORMAT_RGB_565: - return 16; - case GGL_PIXEL_FORMAT_RGBA_8888: - return 32; - } - return 24; // GGL_PIXEL_FORMAT_RGBX_8888 -} - -// nsScreenGonk.cpp - -nsScreenGonk::nsScreenGonk(uint32_t aId, - GonkDisplay::DisplayType aDisplayType, - const GonkDisplay::NativeData& aNativeData, - NotifyDisplayChangedEvent aEventVisibility) - : mId(aId) - , mEventVisibility(aEventVisibility) - , mNativeWindow(aNativeData.mNativeWindow) - , mDpi(aNativeData.mXdpi) - , mScreenRotation(nsIScreen::ROTATION_0_DEG) - , mPhysicalScreenRotation(nsIScreen::ROTATION_0_DEG) -#if ANDROID_VERSION >= 17 - , mDisplaySurface(aNativeData.mDisplaySurface) -#endif - , mIsMirroring(false) - , mDisplayType(aDisplayType) - , mEGLDisplay(EGL_NO_DISPLAY) - , mEGLSurface(EGL_NO_SURFACE) - , mGLContext(nullptr) - , mFramebuffer(nullptr) - , mMappedBuffer(nullptr) -{ - if (mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_WIDTH, &mVirtualBounds.width) || - mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_HEIGHT, &mVirtualBounds.height) || - mNativeWindow->query(mNativeWindow.get(), NATIVE_WINDOW_FORMAT, &mSurfaceFormat)) { - NS_RUNTIMEABORT("Failed to get native window size, aborting..."); - } - - mNaturalBounds = mVirtualBounds; - - if (IsPrimaryScreen()) { - char propValue[PROPERTY_VALUE_MAX]; - property_get("ro.sf.hwrotation", propValue, "0"); - mPhysicalScreenRotation = atoi(propValue) / 90; - } - - mColorDepth = SurfaceFormatToColorDepth(mSurfaceFormat); -} - -static void -ReleaseGLContextSync(mozilla::gl::GLContext* aGLContext) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - aGLContext->Release(); -} - -nsScreenGonk::~nsScreenGonk() -{ - // Release GLContext on compositor thread - if (mGLContext) { - CompositorThreadHolder::Loop()->PostTask( - NewRunnableFunction(&ReleaseGLContextSync, - mGLContext.forget().take())); - mGLContext = nullptr; - } -} - -bool -nsScreenGonk::IsPrimaryScreen() -{ - return mDisplayType == GonkDisplay::DISPLAY_PRIMARY; -} - -NS_IMETHODIMP -nsScreenGonk::GetId(uint32_t *outId) -{ - *outId = mId; - return NS_OK; -} - -uint32_t -nsScreenGonk::GetId() -{ - return mId; -} - -NotifyDisplayChangedEvent -nsScreenGonk::GetEventVisibility() -{ - return mEventVisibility; -} - -NS_IMETHODIMP -nsScreenGonk::GetRect(int32_t *outLeft, int32_t *outTop, - int32_t *outWidth, int32_t *outHeight) -{ - *outLeft = mVirtualBounds.x; - *outTop = mVirtualBounds.y; - - *outWidth = mVirtualBounds.width; - *outHeight = mVirtualBounds.height; - - return NS_OK; -} - -LayoutDeviceIntRect -nsScreenGonk::GetRect() -{ - return mVirtualBounds; -} - -NS_IMETHODIMP -nsScreenGonk::GetAvailRect(int32_t *outLeft, int32_t *outTop, - int32_t *outWidth, int32_t *outHeight) -{ - return GetRect(outLeft, outTop, outWidth, outHeight); -} - -NS_IMETHODIMP -nsScreenGonk::GetPixelDepth(int32_t *aPixelDepth) -{ - // XXX: this should actually return 32 when we're using 24-bit - // color, because we use RGBX. - *aPixelDepth = mColorDepth; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenGonk::GetColorDepth(int32_t *aColorDepth) -{ - *aColorDepth = mColorDepth; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenGonk::GetRotation(uint32_t* aRotation) -{ - *aRotation = mScreenRotation; - return NS_OK; -} - -float -nsScreenGonk::GetDpi() -{ - return mDpi; -} - -int32_t -nsScreenGonk::GetSurfaceFormat() -{ - return mSurfaceFormat; -} - -ANativeWindow* -nsScreenGonk::GetNativeWindow() -{ - return mNativeWindow.get(); -} - -NS_IMETHODIMP -nsScreenGonk::SetRotation(uint32_t aRotation) -{ - if (!(aRotation <= ROTATION_270_DEG)) { - return NS_ERROR_ILLEGAL_VALUE; - } - - if (mScreenRotation == aRotation) { - return NS_OK; - } - - mScreenRotation = aRotation; - uint32_t rotation = EffectiveScreenRotation(); - if (rotation == nsIScreen::ROTATION_90_DEG || - rotation == nsIScreen::ROTATION_270_DEG) { - mVirtualBounds = LayoutDeviceIntRect(0, 0, - mNaturalBounds.height, - mNaturalBounds.width); - } else { - mVirtualBounds = mNaturalBounds; - } - - nsAppShell::NotifyScreenRotation(); - - for (unsigned int i = 0; i < mTopWindows.Length(); i++) { - mTopWindows[i]->Resize(mVirtualBounds.width, - mVirtualBounds.height, - true); - } - - return NS_OK; -} - -LayoutDeviceIntRect -nsScreenGonk::GetNaturalBounds() -{ - return mNaturalBounds; -} - -uint32_t -nsScreenGonk::EffectiveScreenRotation() -{ - return (mScreenRotation + mPhysicalScreenRotation) % (360 / 90); -} - -// NB: This isn't gonk-specific, but gonk is the only widget backend -// that does this calculation itself, currently. -static ScreenOrientationInternal -ComputeOrientation(uint32_t aRotation, const LayoutDeviceIntSize& aScreenSize) -{ - bool naturallyPortrait = (aScreenSize.height > aScreenSize.width); - switch (aRotation) { - case nsIScreen::ROTATION_0_DEG: - return (naturallyPortrait ? eScreenOrientation_PortraitPrimary : - eScreenOrientation_LandscapePrimary); - case nsIScreen::ROTATION_90_DEG: - // Arbitrarily choosing 90deg to be primary "unnatural" - // rotation. - return (naturallyPortrait ? eScreenOrientation_LandscapePrimary : - eScreenOrientation_PortraitPrimary); - case nsIScreen::ROTATION_180_DEG: - return (naturallyPortrait ? eScreenOrientation_PortraitSecondary : - eScreenOrientation_LandscapeSecondary); - case nsIScreen::ROTATION_270_DEG: - return (naturallyPortrait ? eScreenOrientation_LandscapeSecondary : - eScreenOrientation_PortraitSecondary); - default: - MOZ_CRASH("Gonk screen must always have a known rotation"); - } -} - -static uint16_t -RotationToAngle(uint32_t aRotation) -{ - uint16_t angle = 90 * aRotation; - MOZ_ASSERT(angle == 0 || angle == 90 || angle == 180 || angle == 270); - return angle; -} - -ScreenConfiguration -nsScreenGonk::GetConfiguration() -{ - ScreenOrientationInternal orientation = - ComputeOrientation(mScreenRotation, mNaturalBounds.Size()); - - // NB: perpetuating colorDepth == pixelDepth illusion here, for - // consistency. - return ScreenConfiguration(mVirtualBounds.ToUnknownRect(), orientation, - RotationToAngle(mScreenRotation), - mColorDepth, mColorDepth); -} - -void -nsScreenGonk::RegisterWindow(nsWindow* aWindow) -{ - mTopWindows.AppendElement(aWindow); -} - -void -nsScreenGonk::UnregisterWindow(nsWindow* aWindow) -{ - mTopWindows.RemoveElement(aWindow); -} - -void -nsScreenGonk::BringToTop(nsWindow* aWindow) -{ - mTopWindows.RemoveElement(aWindow); - mTopWindows.InsertElementAt(0, aWindow); -} - -static gralloc_module_t const* -gralloc_module() -{ - hw_module_t const *module; - if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module)) { - return nullptr; - } - return reinterpret_cast(module); -} - -static SurfaceFormat -HalFormatToSurfaceFormat(int aHalFormat) -{ - switch (aHalFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - // Needs RB swap - return SurfaceFormat::B8G8R8A8; - case HAL_PIXEL_FORMAT_RGBX_8888: - // Needs RB swap - return SurfaceFormat::B8G8R8X8; - case HAL_PIXEL_FORMAT_BGRA_8888: - return SurfaceFormat::B8G8R8A8; - case HAL_PIXEL_FORMAT_RGB_565: - return SurfaceFormat::R5G6B5_UINT16; - default: - MOZ_CRASH("Unhandled HAL pixel format"); - return SurfaceFormat::UNKNOWN; // not reached - } -} - -static bool -NeedsRBSwap(int aHalFormat) -{ - switch (aHalFormat) { - case HAL_PIXEL_FORMAT_RGBA_8888: - return true; - case HAL_PIXEL_FORMAT_RGBX_8888: - return true; - case HAL_PIXEL_FORMAT_BGRA_8888: - return false; - case HAL_PIXEL_FORMAT_RGB_565: - return false; - default: - MOZ_CRASH("Unhandled HAL pixel format"); - return false; // not reached - } -} - -already_AddRefed -nsScreenGonk::StartRemoteDrawing() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(!mFramebuffer); - MOZ_ASSERT(!mMappedBuffer); - - mFramebuffer = DequeueBuffer(); - int width = mFramebuffer->width, height = mFramebuffer->height; - if (gralloc_module()->lock(gralloc_module(), mFramebuffer->handle, - GRALLOC_USAGE_SW_READ_NEVER | - GRALLOC_USAGE_SW_WRITE_OFTEN | - GRALLOC_USAGE_HW_FB, - 0, 0, width, height, - reinterpret_cast(&mMappedBuffer))) { - EndRemoteDrawing(); - return nullptr; - } - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - mFramebufferTarget = Factory::CreateDrawTargetForData( - BackendType::CAIRO, - mMappedBuffer, - IntSize(width, height), - mFramebuffer->stride * gfx::BytesPerPixel(format), - format); - if (!mFramebufferTarget) { - MOZ_CRASH("nsWindow::StartRemoteDrawing failed in CreateDrawTargetForData"); - } - if (!mBackBuffer || - mBackBuffer->GetSize() != mFramebufferTarget->GetSize() || - mBackBuffer->GetFormat() != mFramebufferTarget->GetFormat()) { - mBackBuffer = mFramebufferTarget->CreateSimilarDrawTarget( - mFramebufferTarget->GetSize(), mFramebufferTarget->GetFormat()); - } - RefPtr buffer(mBackBuffer); - return buffer.forget(); -} - -void -nsScreenGonk::EndRemoteDrawing() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - - if (mFramebufferTarget && mFramebuffer) { - IntSize size = mFramebufferTarget->GetSize(); - Rect rect(0, 0, size.width, size.height); - RefPtr source = mBackBuffer->Snapshot(); - mFramebufferTarget->DrawSurface(source, rect, rect); - - // Convert from BGR to RGB - // XXX this is a temporary solution. It consumes extra cpu cycles, - // it should not be used on product device. - if (NeedsRBSwap(GetSurfaceFormat())) { - LOGE("Very slow composition path, it should not be used on product!!!"); - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - gfxUtils::ConvertBGRAtoRGBA( - mMappedBuffer, - mFramebuffer->stride * mFramebuffer->height * gfx::BytesPerPixel(format)); - } - } - if (mMappedBuffer) { - MOZ_ASSERT(mFramebuffer); - gralloc_module()->unlock(gralloc_module(), mFramebuffer->handle); - mMappedBuffer = nullptr; - } - if (mFramebuffer) { - QueueBuffer(mFramebuffer); - } - mFramebuffer = nullptr; - mFramebufferTarget = nullptr; -} - -ANativeWindowBuffer* -nsScreenGonk::DequeueBuffer() -{ - ANativeWindowBuffer* buf = nullptr; -#if ANDROID_VERSION >= 17 - int fenceFd = -1; - mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf, &fenceFd); - android::sp fence(new android::Fence(fenceFd)); -#if ANDROID_VERSION == 17 - fence->waitForever(1000, "nsScreenGonk_DequeueBuffer"); - // 1000 is what Android uses. It is a warning timeout in ms. - // This timeout was removed in ANDROID_VERSION 18. -#else - fence->waitForever("nsScreenGonk_DequeueBuffer"); -#endif -#else - mNativeWindow->dequeueBuffer(mNativeWindow.get(), &buf); -#endif - return buf; -} - -bool -nsScreenGonk::QueueBuffer(ANativeWindowBuffer* buf) -{ -#if ANDROID_VERSION >= 17 - int ret = mNativeWindow->queueBuffer(mNativeWindow.get(), buf, -1); - return ret == 0; -#else - int ret = mNativeWindow->queueBuffer(mNativeWindow.get(), buf); - return ret == 0; -#endif -} - -nsresult -nsScreenGonk::MakeSnapshot(ANativeWindowBuffer* aBuffer) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(aBuffer); - - layers::CompositorBridgeParent* compositorParent = mCompositorBridgeParent; - if (!compositorParent) { - return NS_ERROR_FAILURE; - } - - int width = aBuffer->width, height = aBuffer->height; - uint8_t* mappedBuffer = nullptr; - if (gralloc_module()->lock(gralloc_module(), aBuffer->handle, - GRALLOC_USAGE_SW_READ_OFTEN | - GRALLOC_USAGE_SW_WRITE_OFTEN, - 0, 0, width, height, - reinterpret_cast(&mappedBuffer))) { - return NS_ERROR_FAILURE; - } - - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - RefPtr mTarget = - Factory::CreateDrawTargetForData( - BackendType::CAIRO, - mappedBuffer, - IntSize(width, height), - aBuffer->stride * gfx::BytesPerPixel(format), - format); - if (!mTarget) { - return NS_ERROR_FAILURE; - } - - gfx::IntRect rect = GetRect().ToUnknownRect(); - compositorParent->ForceComposeToTarget(mTarget, &rect); - - // Convert from BGR to RGB - // XXX this is a temporary solution. It consumes extra cpu cycles, - if (NeedsRBSwap(GetSurfaceFormat())) { - LOGE("Slow path of making Snapshot!!!"); - SurfaceFormat format = HalFormatToSurfaceFormat(GetSurfaceFormat()); - gfxUtils::ConvertBGRAtoRGBA( - mappedBuffer, - aBuffer->stride * aBuffer->height * gfx::BytesPerPixel(format)); - mappedBuffer = nullptr; - } - gralloc_module()->unlock(gralloc_module(), aBuffer->handle); - return NS_OK; -} - -void -nsScreenGonk::SetCompositorBridgeParent(layers::CompositorBridgeParent* aCompositorBridgeParent) -{ - MOZ_ASSERT(NS_IsMainThread()); - mCompositorBridgeParent = aCompositorBridgeParent; -} - -#if ANDROID_VERSION >= 17 -android::DisplaySurface* -nsScreenGonk::GetDisplaySurface() -{ - return mDisplaySurface.get(); -} - -int -nsScreenGonk::GetPrevDispAcquireFd() -{ - if (!mDisplaySurface.get()) { - return -1; - } - return mDisplaySurface->GetPrevDispAcquireFd(); -} -#endif - -GonkDisplay::DisplayType -nsScreenGonk::GetDisplayType() -{ - return mDisplayType; -} - -void -nsScreenGonk::SetEGLInfo(hwc_display_t aDisplay, - hwc_surface_t aSurface, - gl::GLContext* aGLContext) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - mEGLDisplay = aDisplay; - mEGLSurface = aSurface; - mGLContext = aGLContext; -} - -hwc_display_t -nsScreenGonk::GetEGLDisplay() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - return mEGLDisplay; -} - -hwc_surface_t -nsScreenGonk::GetEGLSurface() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - return mEGLSurface; -} - -already_AddRefed -nsScreenGonk::GetGLContext() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - RefPtrglContext = mGLContext; - return glContext.forget(); -} - -static void -UpdateMirroringWidgetSync(nsMainThreadPtrHandle&& aScreen, nsWindow* aWindow) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - already_AddRefed window(aWindow); - aScreen->UpdateMirroringWidget(window); -} - -bool -nsScreenGonk::EnableMirroring() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!IsPrimaryScreen()); - - RefPtr primaryScreen = nsScreenManagerGonk::GetPrimaryScreen(); - NS_ENSURE_TRUE(primaryScreen, false); - - bool ret = primaryScreen->SetMirroringScreen(this); - NS_ENSURE_TRUE(ret, false); - - // Create a widget for mirroring - nsWidgetInitData initData; - initData.mScreenId = mId; - RefPtr window = new nsWindow(); - nsresult rv = window->Create(nullptr, nullptr, mNaturalBounds, &initData); - NS_ENSURE_SUCCESS(rv, false); - MOZ_ASSERT(static_cast(window)->GetScreen() == this); - - // Update mMirroringWidget on compositor thread - nsMainThreadPtrHandle primary = - nsMainThreadPtrHandle(new nsMainThreadPtrHolder(primaryScreen, false)); - CompositorThreadHolder::Loop()->PostTask( - NewRunnableFunction(&UpdateMirroringWidgetSync, - primary, - window.forget().take())); - - mIsMirroring = true; - return true; -} - -bool -nsScreenGonk::DisableMirroring() -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(!IsPrimaryScreen()); - - mIsMirroring = false; - RefPtr primaryScreen = nsScreenManagerGonk::GetPrimaryScreen(); - NS_ENSURE_TRUE(primaryScreen, false); - - bool ret = primaryScreen->ClearMirroringScreen(this); - NS_ENSURE_TRUE(ret, false); - - // Update mMirroringWidget on compositor thread - nsMainThreadPtrHandle primary = - nsMainThreadPtrHandle(new nsMainThreadPtrHolder(primaryScreen, false)); - CompositorThreadHolder::Loop()->PostTask( - NewRunnableFunction(&UpdateMirroringWidgetSync, - primary, - nullptr)); - return true; -} - -bool -nsScreenGonk::SetMirroringScreen(nsScreenGonk* aScreen) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - if (mMirroringScreen) { - return false; - } - mMirroringScreen = aScreen; - return true; -} - -bool -nsScreenGonk::ClearMirroringScreen(nsScreenGonk* aScreen) -{ - MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - if (mMirroringScreen != aScreen) { - return false; - } - mMirroringScreen = nullptr; - return true; -} - -void -nsScreenGonk::UpdateMirroringWidget(already_AddRefed& aWindow) -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - if (mMirroringWidget) { - nsCOMPtr widget = mMirroringWidget.forget(); - NS_ReleaseOnMainThread(widget.forget()); - } - mMirroringWidget = aWindow; -} - -nsWindow* -nsScreenGonk::GetMirroringWidget() -{ - MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread()); - MOZ_ASSERT(IsPrimaryScreen()); - - return mMirroringWidget; -} - -NS_IMPL_ISUPPORTS(nsScreenManagerGonk, nsIScreenManager) - -nsScreenManagerGonk::nsScreenManagerGonk() - : mInitialized(false) -#if ANDROID_VERSION >= 19 - , mDisplayEnabled(false) -#endif -{ -} - -nsScreenManagerGonk::~nsScreenManagerGonk() -{ -} - -static StaticRefPtr sScreenManagerGonk; - -/* static */ already_AddRefed -nsScreenManagerGonk::GetInstance() -{ - MOZ_ASSERT(NS_IsMainThread()); - - // Avoid creating nsScreenManagerGonk from content process. - if (!XRE_IsParentProcess()) { - MOZ_CRASH("Non-chrome processes should not get here."); - } - - // Avoid creating multiple nsScreenManagerGonk instance inside main process. - if (!sScreenManagerGonk) { - sScreenManagerGonk = new nsScreenManagerGonk(); - ClearOnShutdown(&sScreenManagerGonk); - } - - RefPtr screenMgr = sScreenManagerGonk.get(); - return screenMgr.forget(); -} - -/* static */ already_AddRefed< nsScreenGonk> -nsScreenManagerGonk::GetPrimaryScreen() -{ - MOZ_ASSERT(NS_IsMainThread()); - - RefPtr manager = nsScreenManagerGonk::GetInstance(); - nsCOMPtr screen; - manager->GetPrimaryScreen(getter_AddRefs(screen)); - MOZ_ASSERT(screen); - return already_AddRefed( - static_cast(screen.forget().take())); -} - -void -nsScreenManagerGonk::Initialize() -{ - if (mInitialized) { - return; - } - - mScreenOnEvent = new ScreenOnOffEvent(true); - mScreenOffEvent = new ScreenOnOffEvent(false); - GetGonkDisplay()->OnEnabled(displayEnabledCallback); - - AddScreen(GonkDisplay::DISPLAY_PRIMARY); - - nsAppShell::NotifyScreenInitialized(); - mInitialized = true; -} - -void -nsScreenManagerGonk::DisplayEnabled(bool aEnabled) -{ - MOZ_ASSERT(NS_IsMainThread()); - -#if ANDROID_VERSION >= 19 - /* Bug 1244044 - * This function could be called before |mCompositorVsyncScheduler| is set. - * To avoid this issue, keep the value stored in |mDisplayEnabled|. - */ - mDisplayEnabled = aEnabled; - if (mCompositorVsyncScheduler) { - mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled); - } -#endif - - VsyncControl(aEnabled); - NS_DispatchToMainThread(aEnabled ? mScreenOnEvent : mScreenOffEvent); -} - -NS_IMETHODIMP -nsScreenManagerGonk::GetPrimaryScreen(nsIScreen **outScreen) -{ - NS_IF_ADDREF(*outScreen = mScreens[0].get()); - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForId(uint32_t aId, - nsIScreen **outScreen) -{ - for (size_t i = 0; i < mScreens.Length(); i++) { - if (mScreens[i]->GetId() == aId) { - NS_IF_ADDREF(*outScreen = mScreens[i].get()); - return NS_OK; - } - } - - *outScreen = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForRect(int32_t inLeft, - int32_t inTop, - int32_t inWidth, - int32_t inHeight, - nsIScreen **outScreen) -{ - // Since all screens have independent coordinate system, we could - // only return the primary screen no matter what rect is given. - return GetPrimaryScreen(outScreen); -} - -NS_IMETHODIMP -nsScreenManagerGonk::ScreenForNativeWidget(void *aWidget, nsIScreen **outScreen) -{ - for (size_t i = 0; i < mScreens.Length(); i++) { - if (aWidget == mScreens[i]->GetNativeWindow()) { - NS_IF_ADDREF(*outScreen = mScreens[i].get()); - return NS_OK; - } - } - - *outScreen = nullptr; - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::GetNumberOfScreens(uint32_t *aNumberOfScreens) -{ - *aNumberOfScreens = mScreens.Length(); - return NS_OK; -} - -NS_IMETHODIMP -nsScreenManagerGonk::GetSystemDefaultScale(float *aDefaultScale) -{ - *aDefaultScale = 1.0f; - return NS_OK; -} - -void -nsScreenManagerGonk::VsyncControl(bool aEnabled) -{ - if (!NS_IsMainThread()) { - NS_DispatchToMainThread( - NewRunnableMethod(this, - &nsScreenManagerGonk::VsyncControl, - aEnabled)); - return; - } - - MOZ_ASSERT(NS_IsMainThread()); - VsyncSource::Display &display = gfxPlatform::GetPlatform()->GetHardwareVsync()->GetGlobalDisplay(); - if (aEnabled) { - display.EnableVsync(); - } else { - display.DisableVsync(); - } -} - -uint32_t -nsScreenManagerGonk::GetIdFromType(GonkDisplay::DisplayType aDisplayType) -{ - // This is the only place where we make the assumption that - // display type is equivalent to screen id. - - // Bug 1138287 will address the conversion from type to id. - return aDisplayType; -} - -bool -nsScreenManagerGonk::IsScreenConnected(uint32_t aId) -{ - for (size_t i = 0; i < mScreens.Length(); ++i) { - if (mScreens[i]->GetId() == aId) { - return true; - } - } - - return false; -} - -namespace { - -// A concrete class as a subject for 'display-changed' observer event. -class DisplayInfo : public nsIDisplayInfo { -public: - NS_DECL_ISUPPORTS - - DisplayInfo(uint32_t aId, bool aConnected) - : mId(aId) - , mConnected(aConnected) - { - } - - NS_IMETHODIMP GetId(int32_t *aId) - { - *aId = mId; - return NS_OK; - } - - NS_IMETHODIMP GetConnected(bool *aConnected) - { - *aConnected = mConnected; - return NS_OK; - } - -private: - virtual ~DisplayInfo() {} - - uint32_t mId; - bool mConnected; -}; - -NS_IMPL_ISUPPORTS(DisplayInfo, nsIDisplayInfo, nsISupports) - -class NotifyTask : public mozilla::Runnable { -public: - NotifyTask(uint32_t aId, bool aConnected) - : mDisplayInfo(new DisplayInfo(aId, aConnected)) - { - } - - NS_IMETHOD Run() override - { - nsCOMPtr os = mozilla::services::GetObserverService(); - if (os) { - os->NotifyObservers(mDisplayInfo, "display-changed", nullptr); - } - - return NS_OK; - } -private: - RefPtr mDisplayInfo; -}; - -void -NotifyDisplayChange(uint32_t aId, bool aConnected) -{ - NS_DispatchToMainThread(new NotifyTask(aId, aConnected)); -} - -} // end of unnamed namespace. - -nsresult -nsScreenManagerGonk::AddScreen(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink, - NotifyDisplayChangedEvent aEventVisibility) -{ - MOZ_ASSERT(NS_IsMainThread()); - - NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES, - NS_ERROR_FAILURE); - - uint32_t id = GetIdFromType(aDisplayType); - NS_ENSURE_TRUE(!IsScreenConnected(id), NS_ERROR_FAILURE); - - GonkDisplay::NativeData nativeData = - GetGonkDisplay()->GetNativeData(aDisplayType, aSink); - nsScreenGonk* screen = new nsScreenGonk(id, - aDisplayType, - nativeData, - aEventVisibility); - mScreens.AppendElement(screen); - - if (aEventVisibility == NotifyDisplayChangedEvent::Observable) { - NotifyDisplayChange(id, true); - } - - // By default, non primary screen does mirroring. - if (aDisplayType != GonkDisplay::DISPLAY_PRIMARY && - gfxPrefs::ScreenMirroringEnabled()) { - screen->EnableMirroring(); - } - - return NS_OK; -} - -nsresult -nsScreenManagerGonk::RemoveScreen(GonkDisplay::DisplayType aDisplayType) -{ - MOZ_ASSERT(NS_IsMainThread()); - - NS_ENSURE_TRUE(aDisplayType < GonkDisplay::DisplayType::NUM_DISPLAY_TYPES, - NS_ERROR_FAILURE); - - NotifyDisplayChangedEvent eventVisibility = NotifyDisplayChangedEvent::Observable; - uint32_t screenId = GetIdFromType(aDisplayType); - NS_ENSURE_TRUE(IsScreenConnected(screenId), NS_ERROR_FAILURE); - - for (size_t i = 0; i < mScreens.Length(); i++) { - if (mScreens[i]->GetId() == screenId) { - if (mScreens[i]->IsMirroring()) { - mScreens[i]->DisableMirroring(); - } - eventVisibility = mScreens[i]->GetEventVisibility(); - mScreens.RemoveElementAt(i); - break; - } - } - - if (eventVisibility == NotifyDisplayChangedEvent::Observable) { - NotifyDisplayChange(screenId, false); - } - return NS_OK; -} - -#if ANDROID_VERSION >= 19 -void -nsScreenManagerGonk::SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler *aObserver) -{ - MOZ_ASSERT(NS_IsMainThread()); - - // We assume on b2g that there is only 1 CompositorBridgeParent - MOZ_ASSERT(mCompositorVsyncScheduler == nullptr); - MOZ_ASSERT(aObserver); - mCompositorVsyncScheduler = aObserver; - mCompositorVsyncScheduler->SetDisplay(mDisplayEnabled); -} -#endif diff --git a/widget/gonk/nsScreenManagerGonk.h b/widget/gonk/nsScreenManagerGonk.h deleted file mode 100644 index 33ef5edb8..000000000 --- a/widget/gonk/nsScreenManagerGonk.h +++ /dev/null @@ -1,228 +0,0 @@ -/* -*- Mode: C++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsScreenManagerGonk_h___ -#define nsScreenManagerGonk_h___ - -#include "cutils/properties.h" -#include "hardware/hwcomposer.h" - -#include "libdisplay/GonkDisplay.h" -#include "mozilla/Atomics.h" -#include "mozilla/Hal.h" -#include "mozilla/Mutex.h" -#include "nsBaseScreen.h" -#include "nsCOMPtr.h" -#include "nsIScreenManager.h" -#include "nsProxyRelease.h" - -#include - -class nsWindow; - -namespace android { - class DisplaySurface; - class IGraphicBufferProducer; -}; - -namespace mozilla { - class Runnable; -namespace gl { - class GLContext; -} -namespace layers { -class CompositorVsyncScheduler; -class CompositorBridgeParent; -} -} - -enum class NotifyDisplayChangedEvent : int8_t { - Observable, - Suppressed -}; - -class nsScreenGonk : public nsBaseScreen -{ - typedef mozilla::hal::ScreenConfiguration ScreenConfiguration; - typedef mozilla::GonkDisplay GonkDisplay; - typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; - typedef mozilla::layers::CompositorBridgeParent CompositorBridgeParent; - typedef mozilla::gfx::DrawTarget DrawTarget; - -public: - nsScreenGonk(uint32_t aId, - GonkDisplay::DisplayType aDisplayType, - const GonkDisplay::NativeData& aNativeData, - NotifyDisplayChangedEvent aEventVisibility); - - ~nsScreenGonk(); - - NS_IMETHOD GetId(uint32_t* aId); - NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); - NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight); - NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth); - NS_IMETHOD GetColorDepth(int32_t* aColorDepth); - NS_IMETHOD GetRotation(uint32_t* aRotation); - NS_IMETHOD SetRotation(uint32_t aRotation); - - uint32_t GetId(); - NotifyDisplayChangedEvent GetEventVisibility(); - LayoutDeviceIntRect GetRect(); - float GetDpi(); - int32_t GetSurfaceFormat(); - ANativeWindow* GetNativeWindow(); - LayoutDeviceIntRect GetNaturalBounds(); - uint32_t EffectiveScreenRotation(); - ScreenConfiguration GetConfiguration(); - bool IsPrimaryScreen(); - - already_AddRefed StartRemoteDrawing(); - void EndRemoteDrawing(); - - nsresult MakeSnapshot(ANativeWindowBuffer* aBuffer); - void SetCompositorBridgeParent(CompositorBridgeParent* aCompositorBridgeParent); - -#if ANDROID_VERSION >= 17 - android::DisplaySurface* GetDisplaySurface(); - int GetPrevDispAcquireFd(); -#endif - GonkDisplay::DisplayType GetDisplayType(); - - void RegisterWindow(nsWindow* aWindow); - void UnregisterWindow(nsWindow* aWindow); - void BringToTop(nsWindow* aWindow); - - const nsTArray& GetTopWindows() const - { - return mTopWindows; - } - - // Non-primary screen only - bool EnableMirroring(); - bool DisableMirroring(); - bool IsMirroring() - { - return mIsMirroring; - } - - // Primary screen only - bool SetMirroringScreen(nsScreenGonk* aScreen); - bool ClearMirroringScreen(nsScreenGonk* aScreen); - - // Called only on compositor thread - void SetEGLInfo(hwc_display_t aDisplay, hwc_surface_t aSurface, - mozilla::gl::GLContext* aGLContext); - hwc_display_t GetEGLDisplay(); - hwc_surface_t GetEGLSurface(); - already_AddRefed GetGLContext(); - void UpdateMirroringWidget(already_AddRefed& aWindow); // Primary screen only - nsWindow* GetMirroringWidget(); // Primary screen only - -protected: - ANativeWindowBuffer* DequeueBuffer(); - bool QueueBuffer(ANativeWindowBuffer* buf); - - uint32_t mId; - NotifyDisplayChangedEvent mEventVisibility; - int32_t mColorDepth; - android::sp mNativeWindow; - float mDpi; - int32_t mSurfaceFormat; - LayoutDeviceIntRect mNaturalBounds; // Screen bounds w/o rotation taken into account. - LayoutDeviceIntRect mVirtualBounds; // Screen bounds w/ rotation taken into account. - uint32_t mScreenRotation; - uint32_t mPhysicalScreenRotation; - nsTArray mTopWindows; -#if ANDROID_VERSION >= 17 - android::sp mDisplaySurface; -#endif - bool mIsMirroring; // Non-primary screen only - RefPtr mMirroringScreen; // Primary screen only - mozilla::Atomic mCompositorBridgeParent; - - // Accessed and updated only on compositor thread - GonkDisplay::DisplayType mDisplayType; - hwc_display_t mEGLDisplay; - hwc_surface_t mEGLSurface; - RefPtr mGLContext; - RefPtr mMirroringWidget; // Primary screen only - - // If we're using a BasicCompositor, these fields are temporarily - // set during frame composition. They wrap the hardware - // framebuffer. - RefPtr mFramebufferTarget; - ANativeWindowBuffer* mFramebuffer; - /** - * Points to a mapped gralloc buffer between calls to lock and unlock. - * Should be null outside of the lock-unlock pair. - */ - uint8_t* mMappedBuffer; - // If we're using a BasicCompositor, this is our window back - // buffer. The gralloc framebuffer driver expects us to draw the - // entire framebuffer on every frame, but gecko expects the - // windowing system to be tracking buffer updates for invalidated - // regions. We get stuck holding that bag. - // - // Only accessed on the compositor thread, except during - // destruction. - RefPtr mBackBuffer; -}; - -class nsScreenManagerGonk final : public nsIScreenManager -{ -public: - typedef mozilla::GonkDisplay GonkDisplay; - -public: - nsScreenManagerGonk(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISCREENMANAGER - - static already_AddRefed GetInstance(); - static already_AddRefed GetPrimaryScreen(); - - void Initialize(); - void DisplayEnabled(bool aEnabled); - - nsresult AddScreen(GonkDisplay::DisplayType aDisplayType, - android::IGraphicBufferProducer* aSink = nullptr, - NotifyDisplayChangedEvent aEventVisibility = NotifyDisplayChangedEvent::Observable); - - nsresult RemoveScreen(GonkDisplay::DisplayType aDisplayType); - -#if ANDROID_VERSION >= 19 - void SetCompositorVsyncScheduler(mozilla::layers::CompositorVsyncScheduler* aObserver); -#endif - -protected: - ~nsScreenManagerGonk(); - void VsyncControl(bool aEnabled); - uint32_t GetIdFromType(GonkDisplay::DisplayType aDisplayType); - bool IsScreenConnected(uint32_t aId); - - bool mInitialized; - nsTArray> mScreens; - RefPtr mScreenOnEvent; - RefPtr mScreenOffEvent; - -#if ANDROID_VERSION >= 19 - bool mDisplayEnabled; - RefPtr mCompositorVsyncScheduler; -#endif -}; - -#endif /* nsScreenManagerGonk_h___ */ diff --git a/widget/gonk/nsWidgetFactory.cpp b/widget/gonk/nsWidgetFactory.cpp deleted file mode 100644 index 1c7525544..000000000 --- a/widget/gonk/nsWidgetFactory.cpp +++ /dev/null @@ -1,128 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "base/basictypes.h" - -#include "mozilla/ModuleUtils.h" -#include "mozilla/WidgetUtils.h" - -#include "nsCOMPtr.h" -#include "nsWidgetsCID.h" -#include "nsAppShell.h" - -#include "nsWindow.h" -#include "nsLookAndFeel.h" -#include "nsAppShellSingleton.h" -#include "nsScreenManagerGonk.h" -#include "nsIdleServiceGonk.h" -#include "nsTransferable.h" -#include "nsClipboard.h" -#include "nsClipboardHelper.h" - -#include "nsHTMLFormatConverter.h" -#include "nsXULAppAPI.h" - -#include "PuppetWidget.h" - -using namespace mozilla::widget; - -// taken from android/nsWidgetFactory.cpp. GfxInfo is a legacy kludge, unfortunately -// for the time being we still have to implement it on all platforms. -#include "GfxInfo.h" -namespace mozilla { -namespace widget { -// This constructor should really be shared with all platforms. -NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init) -} -} - -NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsScreenManagerGonk, nsScreenManagerGonk::GetInstance) -NS_GENERIC_FACTORY_CONSTRUCTOR(PuppetScreenManager) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter) -NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIdleServiceGonk, nsIdleServiceGonk::GetInstance) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard) -NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper) - -NS_DEFINE_NAMED_CID(NS_APPSHELL_CID); -NS_DEFINE_NAMED_CID(NS_WINDOW_CID); -NS_DEFINE_NAMED_CID(NS_CHILD_CID); -NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID); -NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID); -NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID); -NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID); -NS_DEFINE_NAMED_CID(NS_GFXINFO_CID); -NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID); -NS_DEFINE_NAMED_CID(NS_CLIPBOARDHELPER_CID); - -static nsresult -ScreenManagerConstructor(nsISupports *aOuter, REFNSIID aIID, void **aResult) -{ - return (XRE_IsParentProcess()) ? - nsScreenManagerGonkConstructor(aOuter, aIID, aResult) : - PuppetScreenManagerConstructor(aOuter, aIID, aResult); -} - -static const mozilla::Module::CIDEntry kWidgetCIDs[] = { - { &kNS_WINDOW_CID, false, nullptr, nsWindowConstructor }, - { &kNS_CHILD_CID, false, nullptr, nsWindowConstructor }, - { &kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor }, - { &kNS_SCREENMANAGER_CID, false, nullptr, ScreenManagerConstructor }, - { &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor }, - { &kNS_IDLE_SERVICE_CID, false, nullptr, nsIdleServiceGonkConstructor }, - { &kNS_TRANSFERABLE_CID, false, nullptr, nsTransferableConstructor }, - { &kNS_GFXINFO_CID, false, nullptr, mozilla::widget::GfxInfoConstructor }, - { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardConstructor }, - { &kNS_CLIPBOARDHELPER_CID, false, nullptr, nsClipboardHelperConstructor }, - { nullptr } -}; - -static const mozilla::Module::ContractIDEntry kWidgetContracts[] = { - { "@mozilla.org/widgets/window/gonk;1", &kNS_WINDOW_CID }, - { "@mozilla.org/widgets/child_window/gonk;1", &kNS_CHILD_CID }, - { "@mozilla.org/widget/appshell/gonk;1", &kNS_APPSHELL_CID }, - { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID }, - { "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID }, - { "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID }, - { "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID }, - { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID }, - { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID }, - { "@mozilla.org/widget/clipboardhelper;1", &kNS_CLIPBOARDHELPER_CID }, - { nullptr } -}; - -static void -nsWidgetGonkModuleDtor() -{ - // Shutdown all XP level widget classes. - WidgetUtils::Shutdown(); - - nsLookAndFeel::Shutdown(); - nsAppShellShutdown(); -} - -static const mozilla::Module kWidgetModule = { - mozilla::Module::kVersion, - kWidgetCIDs, - kWidgetContracts, - nullptr, - nullptr, - nsAppShellInit, - nsWidgetGonkModuleDtor -}; - -NSMODULE_DEFN(nsWidgetGonkModule) = &kWidgetModule; diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp deleted file mode 100644 index e11b7f233..000000000 --- a/widget/gonk/nsWindow.cpp +++ /dev/null @@ -1,744 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#include "nsWindow.h" - -#include "mozilla/DebugOnly.h" - -#include - -#include "android/log.h" -#include "mozilla/dom/TabParent.h" -#include "mozilla/Preferences.h" -#include "mozilla/RefPtr.h" -#include "mozilla/Services.h" -#include "mozilla/FileUtils.h" -#include "mozilla/ClearOnShutdown.h" -#include "gfxContext.h" -#include "gfxPlatform.h" -#include "GLContextProvider.h" -#include "GLContext.h" -#include "GLContextEGL.h" -#include "nsAppShell.h" -#include "nsScreenManagerGonk.h" -#include "nsTArray.h" -#include "nsIWidgetListener.h" -#include "ClientLayerManager.h" -#include "BasicLayers.h" -#include "libdisplay/GonkDisplay.h" -#include "mozilla/TextEvents.h" -#include "mozilla/gfx/2D.h" -#include "mozilla/gfx/Logging.h" -#include "mozilla/layers/APZCTreeManager.h" -#include "mozilla/layers/APZThreadUtils.h" -#include "mozilla/layers/CompositorBridgeParent.h" -#include "mozilla/layers/CompositorThread.h" -#include "mozilla/layers/CompositorSession.h" -#include "mozilla/TouchEvents.h" -#include "HwcComposer2D.h" - -#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "Gonk" , ## args) -#define LOGW(args...) __android_log_print(ANDROID_LOG_WARN, "Gonk", ## args) -#define LOGE(args...) __android_log_print(ANDROID_LOG_ERROR, "Gonk", ## args) - -#define IS_TOPLEVEL() (mWindowType == eWindowType_toplevel || mWindowType == eWindowType_dialog) - -using namespace mozilla; -using namespace mozilla::dom; -using namespace mozilla::hal; -using namespace mozilla::gfx; -using namespace mozilla::gl; -using namespace mozilla::layers; -using namespace mozilla::widget; - -static nsWindow *gFocusedWindow = nullptr; - -NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget) - -nsWindow::nsWindow() -{ - RefPtr screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->Initialize(); - - // This is a hack to force initialization of the compositor - // resources, if we're going to use omtc. - // - // NB: GetPlatform() will create the gfxPlatform, which wants - // to know the color depth, which asks our native window. - // This has to happen after other init has finished. - gfxPlatform::GetPlatform(); - if (!ShouldUseOffMainThreadCompositing()) { - MOZ_CRASH("How can we render apps, then?"); - } -} - -nsWindow::~nsWindow() -{ - if (mScreen->IsPrimaryScreen()) { - mComposer2D->SetCompositorBridgeParent(nullptr); - } -} - -void -nsWindow::DoDraw(void) -{ - if (!hal::GetScreenEnabled()) { - gDrawRequest = true; - return; - } - - RefPtr screen = nsScreenManagerGonk::GetPrimaryScreen(); - const nsTArray& windows = screen->GetTopWindows(); - - if (windows.IsEmpty()) { - LOG(" no window to draw, bailing"); - return; - } - - RefPtr targetWindow = (nsWindow *)windows[0]; - while (targetWindow->GetLastChild()) { - targetWindow = (nsWindow *)targetWindow->GetLastChild(); - } - - nsIWidgetListener* listener = targetWindow->GetWidgetListener(); - if (listener) { - listener->WillPaintWindow(targetWindow); - } - - listener = targetWindow->GetWidgetListener(); - if (listener) { - LayerManager* lm = targetWindow->GetLayerManager(); - if (mozilla::layers::LayersBackend::LAYERS_CLIENT == lm->GetBackendType()) { - // No need to do anything, the compositor will handle drawing - } else { - NS_RUNTIMEABORT("Unexpected layer manager type"); - } - - listener->DidPaintWindow(); - } -} - -void -nsWindow::ConfigureAPZControllerThread() -{ - APZThreadUtils::SetControllerThread(CompositorThreadHolder::Loop()); -} - -/*static*/ nsEventStatus -nsWindow::DispatchKeyInput(WidgetKeyboardEvent& aEvent) -{ - if (!gFocusedWindow) { - return nsEventStatus_eIgnore; - } - - gFocusedWindow->UserActivity(); - - nsEventStatus status; - aEvent.mWidget = gFocusedWindow; - gFocusedWindow->DispatchEvent(&aEvent, status); - return status; -} - -/*static*/ void -nsWindow::DispatchTouchInput(MultiTouchInput& aInput) -{ - APZThreadUtils::AssertOnControllerThread(); - - if (!gFocusedWindow) { - return; - } - - gFocusedWindow->DispatchTouchInputViaAPZ(aInput); -} - -class DispatchTouchInputOnMainThread : public mozilla::Runnable -{ -public: - DispatchTouchInputOnMainThread(const MultiTouchInput& aInput, - const ScrollableLayerGuid& aGuid, - const uint64_t& aInputBlockId, - nsEventStatus aApzResponse) - : mInput(aInput) - , mGuid(aGuid) - , mInputBlockId(aInputBlockId) - , mApzResponse(aApzResponse) - {} - - NS_IMETHOD Run() override { - if (gFocusedWindow) { - gFocusedWindow->DispatchTouchEventForAPZ(mInput, mGuid, mInputBlockId, mApzResponse); - } - return NS_OK; - } - -private: - MultiTouchInput mInput; - ScrollableLayerGuid mGuid; - uint64_t mInputBlockId; - nsEventStatus mApzResponse; -}; - -void -nsWindow::DispatchTouchInputViaAPZ(MultiTouchInput& aInput) -{ - APZThreadUtils::AssertOnControllerThread(); - - if (!mAPZC) { - // In general mAPZC should not be null, but during initial setup - // it might be, so we handle that case by ignoring touch input there. - return; - } - - // First send it through the APZ code - mozilla::layers::ScrollableLayerGuid guid; - uint64_t inputBlockId; - nsEventStatus result = mAPZC->ReceiveInputEvent(aInput, &guid, &inputBlockId); - // If the APZ says to drop it, then we drop it - if (result == nsEventStatus_eConsumeNoDefault) { - return; - } - - // Can't use NS_NewRunnableMethod because it only takes up to one arg and - // we need more. Also we can't pass in |this| to the task because nsWindow - // refcounting is not threadsafe. Instead we just use the gFocusedWindow - // static ptr inside the task. - NS_DispatchToMainThread(new DispatchTouchInputOnMainThread( - aInput, guid, inputBlockId, result)); -} - -void -nsWindow::DispatchTouchEventForAPZ(const MultiTouchInput& aInput, - const ScrollableLayerGuid& aGuid, - const uint64_t aInputBlockId, - nsEventStatus aApzResponse) -{ - MOZ_ASSERT(NS_IsMainThread()); - UserActivity(); - - // Convert it to an event we can send to Gecko - WidgetTouchEvent event = aInput.ToWidgetTouchEvent(this); - - // Dispatch the event into the gecko root process for "normal" flow. - // The event might get sent to a child process, - // but if it doesn't we need to notify the APZ of various things. - // All of that happens in ProcessUntransformedAPZEvent - ProcessUntransformedAPZEvent(&event, aGuid, aInputBlockId, aApzResponse); -} - -class DispatchTouchInputOnControllerThread : public Runnable -{ -public: - DispatchTouchInputOnControllerThread(const MultiTouchInput& aInput) - : mInput(aInput) - {} - - NS_IMETHOD Run() override { - if (gFocusedWindow) { - gFocusedWindow->DispatchTouchInputViaAPZ(mInput); - } - return NS_OK; - } - -private: - MultiTouchInput mInput; -}; - -nsresult -nsWindow::SynthesizeNativeTouchPoint(uint32_t aPointerId, - TouchPointerState aPointerState, - LayoutDeviceIntPoint aPoint, - double aPointerPressure, - uint32_t aPointerOrientation, - nsIObserver* aObserver) -{ - AutoObserverNotifier notifier(aObserver, "touchpoint"); - - if (aPointerState == TOUCH_HOVER) { - return NS_ERROR_UNEXPECTED; - } - - if (!mSynthesizedTouchInput) { - mSynthesizedTouchInput = MakeUnique(); - } - - // We should probably use a real timestamp here, but this is B2G and - // so this probably never even exercised any more. - uint32_t time = 0; - TimeStamp timestamp = TimeStamp::FromSystemTime(time); - - MultiTouchInput inputToDispatch = UpdateSynthesizedTouchState( - mSynthesizedTouchInput.get(), time, timestamp, aPointerId, aPointerState, - aPoint, aPointerPressure, aPointerOrientation); - - // Can't use NewRunnableMethod here because that will pass a const-ref - // argument to DispatchTouchInputViaAPZ whereas that function takes a - // non-const ref. At this callsite we don't care about the mutations that - // the function performs so this is fine. Also we can't pass |this| to the - // task because nsWindow refcounting is not threadsafe. Instead we just use - // the gFocusedWindow static ptr instead the task. - APZThreadUtils::RunOnControllerThread( - MakeAndAddRef(inputToDispatch)); - - return NS_OK; -} - -nsresult -nsWindow::Create(nsIWidget* aParent, - void* aNativeParent, - const LayoutDeviceIntRect& aRect, - nsWidgetInitData* aInitData) -{ - BaseCreate(aParent, aInitData); - - nsCOMPtr screen; - - uint32_t screenId = aParent ? ((nsWindow*)aParent)->mScreen->GetId() : - aInitData->mScreenId; - - RefPtr screenManager = nsScreenManagerGonk::GetInstance(); - screenManager->ScreenForId(screenId, getter_AddRefs(screen)); - - mScreen = static_cast(screen.get()); - - mBounds = aRect; - - mParent = (nsWindow *)aParent; - mVisible = false; - - if (!aParent) { - mBounds = mScreen->GetRect(); - } - - mComposer2D = HwcComposer2D::GetInstance(); - - if (!IS_TOPLEVEL()) { - return NS_OK; - } - - mScreen->RegisterWindow(this); - - Resize(0, 0, mBounds.width, mBounds.height, false); - - return NS_OK; -} - -void -nsWindow::Destroy() -{ - mOnDestroyCalled = true; - mScreen->UnregisterWindow(this); - if (this == gFocusedWindow) { - gFocusedWindow = nullptr; - } - nsBaseWidget::OnDestroy(); -} - -NS_IMETHODIMP -nsWindow::Show(bool aState) -{ - if (mWindowType == eWindowType_invisible) { - return NS_OK; - } - - if (mVisible == aState) { - return NS_OK; - } - - mVisible = aState; - if (!IS_TOPLEVEL()) { - return mParent ? mParent->Show(aState) : NS_OK; - } - - if (aState) { - BringToTop(); - } else { - const nsTArray& windows = - mScreen->GetTopWindows(); - for (unsigned int i = 0; i < windows.Length(); i++) { - nsWindow *win = windows[i]; - if (!win->mVisible) { - continue; - } - win->BringToTop(); - break; - } - } - - return NS_OK; -} - -bool -nsWindow::IsVisible() const -{ - return mVisible; -} - -NS_IMETHODIMP -nsWindow::Move(double aX, - double aY) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::Resize(double aWidth, - double aHeight, - bool aRepaint) -{ - return Resize(0, 0, aWidth, aHeight, aRepaint); -} - -NS_IMETHODIMP -nsWindow::Resize(double aX, - double aY, - double aWidth, - double aHeight, - bool aRepaint) -{ - mBounds = LayoutDeviceIntRect(NSToIntRound(aX), NSToIntRound(aY), - NSToIntRound(aWidth), NSToIntRound(aHeight)); - if (mWidgetListener) { - mWidgetListener->WindowResized(this, mBounds.width, mBounds.height); - } - - if (aRepaint) { - Invalidate(mBounds); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::Enable(bool aState) -{ - return NS_OK; -} - -bool -nsWindow::IsEnabled() const -{ - return true; -} - -NS_IMETHODIMP -nsWindow::SetFocus(bool aRaise) -{ - if (aRaise) { - BringToTop(); - } - - if (!IS_TOPLEVEL() && mScreen->IsPrimaryScreen()) { - // We should only set focused window on non-toplevel primary window. - gFocusedWindow = this; - } - - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::ConfigureChildren(const nsTArray&) -{ - return NS_OK; -} - -NS_IMETHODIMP -nsWindow::Invalidate(const LayoutDeviceIntRect& aRect) -{ - nsWindow *top = mParent; - while (top && top->mParent) { - top = top->mParent; - } - const nsTArray& windows = mScreen->GetTopWindows(); - if (top != windows[0] && this != windows[0]) { - return NS_OK; - } - - gDrawRequest = true; - mozilla::NotifyEvent(); - return NS_OK; -} - -LayoutDeviceIntPoint -nsWindow::WidgetToScreenOffset() -{ - LayoutDeviceIntPoint p(0, 0); - nsWindow *w = this; - - while (w && w->mParent) { - p.x += w->mBounds.x; - p.y += w->mBounds.y; - - w = w->mParent; - } - - return p; -} - -void* -nsWindow::GetNativeData(uint32_t aDataType) -{ - switch (aDataType) { - case NS_NATIVE_WINDOW: - // Called before primary display's EGLSurface creation. - return mScreen->GetNativeWindow(); - case NS_NATIVE_OPENGL_CONTEXT: - return mScreen->GetGLContext().take(); - case NS_RAW_NATIVE_IME_CONTEXT: { - void* pseudoIMEContext = GetPseudoIMEContext(); - if (pseudoIMEContext) { - return pseudoIMEContext; - } - // There is only one IME context on Gonk. - return NS_ONLY_ONE_NATIVE_IME_CONTEXT; - } - } - - return nullptr; -} - -void -nsWindow::SetNativeData(uint32_t aDataType, uintptr_t aVal) -{ - switch (aDataType) { - case NS_NATIVE_OPENGL_CONTEXT: - GLContext* context = reinterpret_cast(aVal); - if (!context) { - mScreen->SetEGLInfo(EGL_NO_DISPLAY, - EGL_NO_SURFACE, - nullptr); - return; - } - mScreen->SetEGLInfo(GLContextEGL::Cast(context)->GetEGLDisplay(), - GLContextEGL::Cast(context)->GetEGLSurface(), - context); - return; - } -} - -NS_IMETHODIMP -nsWindow::DispatchEvent(WidgetGUIEvent* aEvent, nsEventStatus& aStatus) -{ - if (mWidgetListener) { - aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents); - } - return NS_OK; -} - -NS_IMETHODIMP_(void) -nsWindow::SetInputContext(const InputContext& aContext, - const InputContextAction& aAction) -{ - mInputContext = aContext; -} - -NS_IMETHODIMP_(InputContext) -nsWindow::GetInputContext() -{ - return mInputContext; -} - -nsresult -nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen*) -{ - if (mWindowType != eWindowType_toplevel) { - // Ignore fullscreen request for non-toplevel windows. - NS_WARNING("MakeFullScreen() on a dialog or child widget?"); - nsBaseWidget::InfallibleMakeFullScreen(aFullScreen); - return NS_OK; - } - - if (aFullScreen) { - // Fullscreen is "sticky" for toplevel widgets on gonk: we - // must paint the entire screen, and should only have one - // toplevel widget, so it doesn't make sense to ever "exit" - // fullscreen. If we do, we can leave parts of the screen - // unpainted. - nsIntRect virtualBounds; - mScreen->GetRect(&virtualBounds.x, &virtualBounds.y, - &virtualBounds.width, &virtualBounds.height); - Resize(virtualBounds.x, virtualBounds.y, - virtualBounds.width, virtualBounds.height, - /*repaint*/true); - } - - if (nsIWidgetListener* listener = GetWidgetListener()) { - listener->FullscreenChanged(aFullScreen); - } - return NS_OK; -} - -already_AddRefed -nsWindow::StartRemoteDrawing() -{ - RefPtr buffer = mScreen->StartRemoteDrawing(); - return buffer.forget(); -} - -void -nsWindow::EndRemoteDrawing() -{ - mScreen->EndRemoteDrawing(); -} - -float -nsWindow::GetDPI() -{ - return mScreen->GetDpi(); -} - -double -nsWindow::GetDefaultScaleInternal() -{ - float dpi = GetDPI(); - // The mean pixel density for mdpi devices is 160dpi, 240dpi for hdpi, - // and 320dpi for xhdpi, respectively. - // We'll take the mid-value between these three numbers as the boundary. - if (dpi < 200.0) { - return 1.0; // mdpi devices. - } - if (dpi < 280.0) { - return 1.5; // hdpi devices. - } - // xhdpi devices and beyond. - return floor(dpi / 150.0 + 0.5); -} - -LayerManager * -nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, - LayersBackend aBackendHint, - LayerManagerPersistence aPersistence) -{ - if (mLayerManager) { - // This layer manager might be used for painting outside of DoDraw(), so we need - // to set the correct rotation on it. - if (ClientLayerManager* manager = mLayerManager->AsClientLayerManager()) { - uint32_t rotation = mScreen->EffectiveScreenRotation(); - manager->SetDefaultTargetConfiguration(mozilla::layers::BufferMode::BUFFER_NONE, - ScreenRotation(rotation)); - } - return mLayerManager; - } - - const nsTArray& windows = mScreen->GetTopWindows(); - nsWindow *topWindow = windows[0]; - - if (!topWindow) { - LOGW(" -- no topwindow\n"); - return nullptr; - } - - CreateCompositor(); - if (RefPtr bridge = GetCompositorBridgeParent()) { - mScreen->SetCompositorBridgeParent(bridge); - if (mScreen->IsPrimaryScreen()) { - mComposer2D->SetCompositorBridgeParent(bridge); - } - } - MOZ_ASSERT(mLayerManager); - return mLayerManager; -} - -void -nsWindow::DestroyCompositor() -{ - if (RefPtr bridge = GetCompositorBridgeParent()) { - mScreen->SetCompositorBridgeParent(nullptr); - if (mScreen->IsPrimaryScreen()) { - // Unset CompositorBridgeParent - mComposer2D->SetCompositorBridgeParent(nullptr); - } - } - nsBaseWidget::DestroyCompositor(); -} - -void -nsWindow::BringToTop() -{ - const nsTArray& windows = mScreen->GetTopWindows(); - if (!windows.IsEmpty()) { - if (nsIWidgetListener* listener = windows[0]->GetWidgetListener()) { - listener->WindowDeactivated(); - } - } - - mScreen->BringToTop(this); - - if (mWidgetListener) { - mWidgetListener->WindowActivated(); - } - - Invalidate(mBounds); -} - -void -nsWindow::UserActivity() -{ - if (!mIdleService) { - mIdleService = do_GetService("@mozilla.org/widget/idleservice;1"); - } - - if (mIdleService) { - mIdleService->ResetIdleTimeOut(0); - } -} - -uint32_t -nsWindow::GetGLFrameBufferFormat() -{ - if (mLayerManager && - mLayerManager->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL) { - // We directly map the hardware fb on Gonk. The hardware fb - // has RGB format. - return LOCAL_GL_RGB; - } - return LOCAL_GL_NONE; -} - -LayoutDeviceIntRect -nsWindow::GetNaturalBounds() -{ - return mScreen->GetNaturalBounds(); -} - -nsScreenGonk* -nsWindow::GetScreen() -{ - return mScreen; -} - -bool -nsWindow::NeedsPaint() -{ - if (!mLayerManager) { - return false; - } - return nsIWidget::NeedsPaint(); -} - -Composer2D* -nsWindow::GetComposer2D() -{ - if (mScreen->GetDisplayType() == GonkDisplay::DISPLAY_VIRTUAL) { - return nullptr; - } - - return mComposer2D; -} - -CompositorBridgeParent* -nsWindow::GetCompositorBridgeParent() const -{ - return mCompositorSession ? mCompositorSession->GetInProcessBridge() : nullptr; -} diff --git a/widget/gonk/nsWindow.h b/widget/gonk/nsWindow.h deleted file mode 100644 index 6106982f9..000000000 --- a/widget/gonk/nsWindow.h +++ /dev/null @@ -1,154 +0,0 @@ -/* Copyright 2012 Mozilla Foundation and Mozilla contributors - * - * 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. - */ - -#ifndef nsWindow_h -#define nsWindow_h - -#include "InputData.h" -#include "mozilla/UniquePtr.h" -#include "nsBaseWidget.h" -#include "nsRegion.h" -#include "nsIIdleServiceInternal.h" -#include "Units.h" - -class ANativeWindowBuffer; - -namespace widget { -struct InputContext; -struct InputContextAction; -} - -namespace mozilla { -class HwcComposer2D; -} - -class nsScreenGonk; - -class nsWindow : public nsBaseWidget -{ -public: - nsWindow(); - - NS_DECL_ISUPPORTS_INHERITED - - static void DoDraw(void); - static nsEventStatus DispatchKeyInput(mozilla::WidgetKeyboardEvent& aEvent); - static void DispatchTouchInput(mozilla::MultiTouchInput& aInput); - - using nsBaseWidget::Create; // for Create signature not overridden here - virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent, - void* aNativeParent, - const LayoutDeviceIntRect& aRect, - nsWidgetInitData* aInitData) override; - virtual void Destroy(); - - NS_IMETHOD Show(bool aState); - virtual bool IsVisible() const; - NS_IMETHOD Move(double aX, - double aY); - NS_IMETHOD Resize(double aWidth, - double aHeight, - bool aRepaint); - NS_IMETHOD Resize(double aX, - double aY, - double aWidth, - double aHeight, - bool aRepaint); - NS_IMETHOD Enable(bool aState); - virtual bool IsEnabled() const; - NS_IMETHOD SetFocus(bool aRaise = false); - NS_IMETHOD ConfigureChildren(const nsTArray&); - NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect); - virtual void* GetNativeData(uint32_t aDataType); - virtual void SetNativeData(uint32_t aDataType, uintptr_t aVal); - NS_IMETHOD SetTitle(const nsAString& aTitle) - { - return NS_OK; - } - virtual LayoutDeviceIntPoint WidgetToScreenOffset(); - void DispatchTouchInputViaAPZ(mozilla::MultiTouchInput& aInput); - void DispatchTouchEventForAPZ(const mozilla::MultiTouchInput& aInput, - const ScrollableLayerGuid& aGuid, - const uint64_t aInputBlockId, - nsEventStatus aApzResponse); - NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent, - nsEventStatus& aStatus); - virtual nsresult SynthesizeNativeTouchPoint(uint32_t aPointerId, - TouchPointerState aPointerState, - LayoutDeviceIntPoint aPoint, - double aPointerPressure, - uint32_t aPointerOrientation, - nsIObserver* aObserver) override; - - virtual nsresult MakeFullScreen( - bool aFullScreen, nsIScreen* aTargetScreen = nullptr) override; - - virtual already_AddRefed - StartRemoteDrawing() override; - virtual void EndRemoteDrawing() override; - - virtual float GetDPI(); - virtual double GetDefaultScaleInternal(); - virtual mozilla::layers::LayerManager* - GetLayerManager(PLayerTransactionChild* aShadowManager = nullptr, - LayersBackend aBackendHint = mozilla::layers::LayersBackend::LAYERS_NONE, - LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT); - virtual void DestroyCompositor(); - - NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, - const InputContextAction& aAction); - NS_IMETHOD_(InputContext) GetInputContext(); - - virtual uint32_t GetGLFrameBufferFormat() override; - - virtual LayoutDeviceIntRect GetNaturalBounds() override; - virtual bool NeedsPaint(); - - virtual Composer2D* GetComposer2D() override; - - void ConfigureAPZControllerThread() override; - - nsScreenGonk* GetScreen(); - -protected: - nsWindow* mParent; - bool mVisible; - InputContext mInputContext; - nsCOMPtr mIdleService; - - virtual ~nsWindow(); - - void BringToTop(); - - // Call this function when the users activity is the direct cause of an - // event (like a keypress or mouse click). - void UserActivity(); - - bool UseExternalCompositingSurface() const override { - return true; - } - CompositorBridgeParent* GetCompositorBridgeParent() const; - -private: - // This is used by SynthesizeNativeTouchPoint to maintain state between - // multiple synthesized points - mozilla::UniquePtr mSynthesizedTouchInput; - - RefPtr mScreen; - - RefPtr mComposer2D; -}; - -#endif /* nsWindow_h */ diff --git a/widget/moz.build b/widget/moz.build index f69f2d87c..5138a89ef 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -6,9 +6,9 @@ toolkit = CONFIG['MOZ_WIDGET_TOOLKIT'] -if toolkit in ('cocoa', 'android', 'gonk', 'uikit'): +if toolkit in ('cocoa', 'android', 'uikit'): DIRS += [toolkit] -if toolkit in ('android', 'gonk', 'gtk2', 'gtk3'): +if toolkit in ('android', 'gtk2', 'gtk3'): EXPORTS += ['nsIPrintDialogService.h'] if toolkit == 'windows': @@ -222,7 +222,7 @@ if toolkit in ('cocoa', 'windows'): ] if toolkit in {'gtk2', 'gtk3', 'cocoa', 'windows', - 'android', 'gonk', 'uikit'}: + 'android', 'uikit'}: UNIFIED_SOURCES += [ 'nsBaseFilePicker.cpp', ] -- cgit v1.2.3